From fd4aa51b015f2367ebc895cfb906299cd917ea77 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 12:50:41 +0800 Subject: [PATCH 001/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E5=9F=BA?= =?UTF-8?q?=E7=B1=BB=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/MultipleUploadBase.cs | 104 ++++++++++++------ .../Components/Upload/SingleUploadBase.cs | 104 ++++++------------ 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs index eef0a2756d7..6156d8508f3 100644 --- a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs @@ -6,38 +6,60 @@ namespace BootstrapBlazor.Components; /// -/// MultipleUploadBase 基类 +/// SingleUploadBase 基类 /// -public abstract class MultipleUploadBase : UploadBase +/// +public abstract class MultipleUploadBase : SingleUploadBase { /// - /// + /// 获得/设置 是否仅上传一次 默认 false /// - /// - /// - protected string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item.Uploaded && item.Code == 0) - .AddClass("is-invalid", item.Code != 0) - .AddClass("disabled", IsDisabled) - .Build(); + [Parameter] + public bool IsSingle { get; set; } /// - /// + /// 获得/设置 最大上传个数 默认为最大值 /// - protected virtual string? ItemClassString => CssBuilder.Default("upload-item") - .Build(); + [Parameter] + public int Max { get; set; } = int.MaxValue; /// - /// 获得/设置 已上传文件集合 + /// 是否显示上传组件 /// - [Parameter] - public List? DefaultFileList { get; set; } + protected bool CheckCanUpload() + { + var count = GetUploadFiles().Count; + return IsSingle ? count < 1 : count < Max; + } /// - /// 获得/设置 是否显示上传进度 默认为 false + /// 获得当前图片集合 /// - [Parameter] - public bool ShowProgress { get; set; } + /// + protected virtual List GetUploadFiles() + { + var ret = new List(); + if (IsSingle) + { + if (DefaultFileList != null && DefaultFileList.Count != 0) + { + ret.Add(DefaultFileList.First()); + } + if (ret.Count == 0 && UploadFiles.Count != 0) + { + ret.Add(UploadFiles.First()); + } + } + else + { + if (DefaultFileList != null) + { + ret.AddRange(DefaultFileList); + } + ret.AddRange(UploadFiles); + } + return ret; + } /// /// OnFileDelete 回调委托 @@ -49,29 +71,47 @@ protected override async Task OnFileDelete(UploadFile item) var ret = await base.OnFileDelete(item); if (ret) { - UploadFiles.Remove(item); + if (IsSingle) + { + UploadFiles.Clear(); + } + else + { + UploadFiles.Remove(item); + } if (!string.IsNullOrEmpty(item.ValidateId)) { await RemoveValidResult(item.ValidateId); } - DefaultFileList?.Remove(item); + RemoveItem(); + } + + void RemoveItem() + { + if (DefaultFileList != null) + { + if (IsSingle) + { + DefaultFileList.Clear(); + } + else + { + DefaultFileList.Remove(item); + } + } } return ret; } /// - /// 是否显示进度条方法 + /// 更新上传进度方法 /// - /// - /// - protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; - - /// - /// 清空上传列表方法 - /// - public override void Reset() + /// + protected void Update(UploadFile file) { - DefaultFileList?.Clear(); - base.Reset(); + if (GetShowProgress(file)) + { + StateHasChanged(); + } } } diff --git a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs index 4cfac7b9513..c4933fd3fc0 100644 --- a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs @@ -6,60 +6,38 @@ namespace BootstrapBlazor.Components; /// -/// SingleUploadBase 基类 +/// MultipleUploadBase 基类 /// -/// -public abstract class SingleUploadBase : MultipleUploadBase +public abstract class SingleUploadBase : UploadBase { /// - /// 获得/设置 是否仅上传一次 默认 false + /// /// - [Parameter] - public bool IsSingle { get; set; } + /// + /// + protected string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-invalid", item.Code != 0) + .AddClass("disabled", IsDisabled) + .Build(); /// - /// 获得/设置 最大上传个数 默认为最大值 + /// /// - [Parameter] - public int Max { get; set; } = int.MaxValue; + protected virtual string? ItemClassString => CssBuilder.Default("upload-item") + .Build(); /// - /// 是否显示上传组件 + /// 获得/设置 已上传文件集合 /// - protected bool CheckCanUpload() - { - var count = GetUploadFiles().Count; - return IsSingle ? count < 1 : count < Max; - } + [Parameter] + public List? DefaultFileList { get; set; } /// - /// 获得当前图片集合 + /// 获得/设置 是否显示上传进度 默认为 false /// - /// - protected virtual List GetUploadFiles() - { - var ret = new List(); - if (IsSingle) - { - if (DefaultFileList != null && DefaultFileList.Count != 0) - { - ret.Add(DefaultFileList.First()); - } - if (ret.Count == 0 && UploadFiles.Count != 0) - { - ret.Add(UploadFiles.First()); - } - } - else - { - if (DefaultFileList != null) - { - ret.AddRange(DefaultFileList); - } - ret.AddRange(UploadFiles); - } - return ret; - } + [Parameter] + public bool ShowProgress { get; set; } /// /// OnFileDelete 回调委托 @@ -71,47 +49,29 @@ protected override async Task OnFileDelete(UploadFile item) var ret = await base.OnFileDelete(item); if (ret) { - if (IsSingle) - { - UploadFiles.Clear(); - } - else - { - UploadFiles.Remove(item); - } + UploadFiles.Remove(item); if (!string.IsNullOrEmpty(item.ValidateId)) { await RemoveValidResult(item.ValidateId); } - RemoveItem(); - } - - void RemoveItem() - { - if (DefaultFileList != null) - { - if (IsSingle) - { - DefaultFileList.Clear(); - } - else - { - DefaultFileList.Remove(item); - } - } + DefaultFileList?.Remove(item); } return ret; } /// - /// 更新上传进度方法 + /// 是否显示进度条方法 /// - /// - protected void Update(UploadFile file) + /// + /// + protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; + + /// + /// 清空上传列表方法 + /// + public override void Reset() { - if (GetShowProgress(file)) - { - StateHasChanged(); - } + DefaultFileList?.Clear(); + base.Reset(); } } From 3e67c0b85c0293963dcf389ddb0688d202ed29af Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 12:53:07 +0800 Subject: [PATCH 002/177] =?UTF-8?q?Revert=20"refactor:=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=9F=BA=E7=B1=BB=E9=80=BB=E8=BE=91"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fd4aa51b015f2367ebc895cfb906299cd917ea77. --- .../Components/Upload/MultipleUploadBase.cs | 104 ++++++------------ .../Components/Upload/SingleUploadBase.cs | 104 ++++++++++++------ 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs index 6156d8508f3..eef0a2756d7 100644 --- a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs @@ -6,60 +6,38 @@ namespace BootstrapBlazor.Components; /// -/// SingleUploadBase 基类 +/// MultipleUploadBase 基类 /// -/// -public abstract class MultipleUploadBase : SingleUploadBase +public abstract class MultipleUploadBase : UploadBase { /// - /// 获得/设置 是否仅上传一次 默认 false + /// /// - [Parameter] - public bool IsSingle { get; set; } + /// + /// + protected string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-invalid", item.Code != 0) + .AddClass("disabled", IsDisabled) + .Build(); /// - /// 获得/设置 最大上传个数 默认为最大值 + /// /// - [Parameter] - public int Max { get; set; } = int.MaxValue; + protected virtual string? ItemClassString => CssBuilder.Default("upload-item") + .Build(); /// - /// 是否显示上传组件 + /// 获得/设置 已上传文件集合 /// - protected bool CheckCanUpload() - { - var count = GetUploadFiles().Count; - return IsSingle ? count < 1 : count < Max; - } + [Parameter] + public List? DefaultFileList { get; set; } /// - /// 获得当前图片集合 + /// 获得/设置 是否显示上传进度 默认为 false /// - /// - protected virtual List GetUploadFiles() - { - var ret = new List(); - if (IsSingle) - { - if (DefaultFileList != null && DefaultFileList.Count != 0) - { - ret.Add(DefaultFileList.First()); - } - if (ret.Count == 0 && UploadFiles.Count != 0) - { - ret.Add(UploadFiles.First()); - } - } - else - { - if (DefaultFileList != null) - { - ret.AddRange(DefaultFileList); - } - ret.AddRange(UploadFiles); - } - return ret; - } + [Parameter] + public bool ShowProgress { get; set; } /// /// OnFileDelete 回调委托 @@ -71,47 +49,29 @@ protected override async Task OnFileDelete(UploadFile item) var ret = await base.OnFileDelete(item); if (ret) { - if (IsSingle) - { - UploadFiles.Clear(); - } - else - { - UploadFiles.Remove(item); - } + UploadFiles.Remove(item); if (!string.IsNullOrEmpty(item.ValidateId)) { await RemoveValidResult(item.ValidateId); } - RemoveItem(); - } - - void RemoveItem() - { - if (DefaultFileList != null) - { - if (IsSingle) - { - DefaultFileList.Clear(); - } - else - { - DefaultFileList.Remove(item); - } - } + DefaultFileList?.Remove(item); } return ret; } /// - /// 更新上传进度方法 + /// 是否显示进度条方法 /// - /// - protected void Update(UploadFile file) + /// + /// + protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; + + /// + /// 清空上传列表方法 + /// + public override void Reset() { - if (GetShowProgress(file)) - { - StateHasChanged(); - } + DefaultFileList?.Clear(); + base.Reset(); } } diff --git a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs index c4933fd3fc0..4cfac7b9513 100644 --- a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs @@ -6,38 +6,60 @@ namespace BootstrapBlazor.Components; /// -/// MultipleUploadBase 基类 +/// SingleUploadBase 基类 /// -public abstract class SingleUploadBase : UploadBase +/// +public abstract class SingleUploadBase : MultipleUploadBase { /// - /// + /// 获得/设置 是否仅上传一次 默认 false /// - /// - /// - protected string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item.Uploaded && item.Code == 0) - .AddClass("is-invalid", item.Code != 0) - .AddClass("disabled", IsDisabled) - .Build(); + [Parameter] + public bool IsSingle { get; set; } /// - /// + /// 获得/设置 最大上传个数 默认为最大值 /// - protected virtual string? ItemClassString => CssBuilder.Default("upload-item") - .Build(); + [Parameter] + public int Max { get; set; } = int.MaxValue; /// - /// 获得/设置 已上传文件集合 + /// 是否显示上传组件 /// - [Parameter] - public List? DefaultFileList { get; set; } + protected bool CheckCanUpload() + { + var count = GetUploadFiles().Count; + return IsSingle ? count < 1 : count < Max; + } /// - /// 获得/设置 是否显示上传进度 默认为 false + /// 获得当前图片集合 /// - [Parameter] - public bool ShowProgress { get; set; } + /// + protected virtual List GetUploadFiles() + { + var ret = new List(); + if (IsSingle) + { + if (DefaultFileList != null && DefaultFileList.Count != 0) + { + ret.Add(DefaultFileList.First()); + } + if (ret.Count == 0 && UploadFiles.Count != 0) + { + ret.Add(UploadFiles.First()); + } + } + else + { + if (DefaultFileList != null) + { + ret.AddRange(DefaultFileList); + } + ret.AddRange(UploadFiles); + } + return ret; + } /// /// OnFileDelete 回调委托 @@ -49,29 +71,47 @@ protected override async Task OnFileDelete(UploadFile item) var ret = await base.OnFileDelete(item); if (ret) { - UploadFiles.Remove(item); + if (IsSingle) + { + UploadFiles.Clear(); + } + else + { + UploadFiles.Remove(item); + } if (!string.IsNullOrEmpty(item.ValidateId)) { await RemoveValidResult(item.ValidateId); } - DefaultFileList?.Remove(item); + RemoveItem(); + } + + void RemoveItem() + { + if (DefaultFileList != null) + { + if (IsSingle) + { + DefaultFileList.Clear(); + } + else + { + DefaultFileList.Remove(item); + } + } } return ret; } /// - /// 是否显示进度条方法 + /// 更新上传进度方法 /// - /// - /// - protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; - - /// - /// 清空上传列表方法 - /// - public override void Reset() + /// + protected void Update(UploadFile file) { - DefaultFileList?.Clear(); - base.Reset(); + if (GetShowProgress(file)) + { + StateHasChanged(); + } } } From d03eaf8fdae6e3907bae7494209edfd919c4dbed Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 16:15:17 +0800 Subject: [PATCH 003/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=BB=A7?= =?UTF-8?q?=E6=89=BF=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 3 +- .../Components/Upload/AvatarUpload.razor.cs | 74 ++--- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 216 +++++++++++++ .../Components/Upload/ButtonUploadBase.cs | 305 ------------------ .../Components/Upload/CardUpload.razor | 2 +- .../Components/Upload/CardUpload.razor.cs | 63 ++++ .../Components/Upload/DropUpload.razor | 4 +- .../Components/Upload/DropUpload.razor.cs | 27 +- .../Components/Upload/InputUpload.razor.cs | 74 ++--- ...Base.razor.scss => InputUpload.razor.scss} | 0 .../Components/Upload/MultipleUploadBase.cs | 77 ----- .../Components/Upload/SingleUploadBase.cs | 117 ------- .../Components/Upload/UploadBase.cs | 159 +++++++-- .../wwwroot/scss/components.scss | 2 +- 15 files changed, 479 insertions(+), 646 deletions(-) delete mode 100644 src/BootstrapBlazor/Components/Upload/ButtonUploadBase.cs rename src/BootstrapBlazor/Components/Upload/{UploadBase.razor.scss => InputUpload.razor.scss} (100%) delete mode 100644 src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs delete mode 100644 src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 7ca69bc97a5..8c24c0fda81 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @typeparam TValue -@inherits SingleUploadBase +@inherits UploadBase @if (IsShowLabel) { @@ -47,7 +47,6 @@ - @code { RenderFragment RenderAdd => @
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index ee2ca42c940..8779d3c0a0f 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -12,45 +12,6 @@ namespace BootstrapBlazor.Components; ///
public partial class AvatarUpload { - /// - /// - /// - /// - /// - protected new string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", !IsDisabled && item.IsValid.HasValue && item.IsValid.Value) - .AddClass("is-invalid", !IsDisabled && item.IsValid.HasValue && !item.IsValid.Value) - .AddClass("is-valid", !IsDisabled && !item.IsValid.HasValue && item.Uploaded && item.Code == 0) - .AddClass("is-invalid", !IsDisabled && !item.IsValid.HasValue && item.Code != 0) - .AddClass("disabled", IsDisabled) - .Build(); - - /// - /// - /// - protected override string? ItemClassString => CssBuilder.Default(base.ItemClassString) - .AddClass("is-circle", IsCircle) - .AddClass("is-single", IsSingle) - .AddClass("disabled", IsDisabled) - .Build(); - - /// - /// 获得/设置 预览框 Style 属性 - /// - private string? PrevStyleString => CssBuilder.Default() - .AddClass($"width: {Width}px;", Width > 0) - .AddClass($"height: {Height}px;", Height > 0 && !IsCircle) - .AddClass($"height: {Width}px;", IsCircle) - .Build(); - - private string? ValidStatusIconString => CssBuilder.Default("valid-icon valid") - .AddClass(ValidStatusIcon) - .Build(); - - private string? InvalidStatusIconString => CssBuilder.Default("valid-icon invalid") - .AddClass(InvalidStatusIcon) - .Build(); - /// /// 获得/设置 文件预览框宽度 /// @@ -109,6 +70,41 @@ public partial class AvatarUpload [NotNull] private IIconTheme? IconTheme { get; set; } + private string? ClassString => CssBuilder.Default("upload") + .AddClassFromAttributes(AdditionalAttributes) + .Build(); + + private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", !IsDisabled && item.IsValid.HasValue && item.IsValid.Value) + .AddClass("is-invalid", !IsDisabled && item.IsValid.HasValue && !item.IsValid.Value) + .AddClass("is-valid", !IsDisabled && !item.IsValid.HasValue && item.Uploaded && item.Code == 0) + .AddClass("is-invalid", !IsDisabled && !item.IsValid.HasValue && item.Code != 0) + .AddClass("disabled", IsDisabled) + .Build(); + + private string? ItemClassString => CssBuilder.Default("upload-item") + .AddClass("is-circle", IsCircle) + .AddClass("is-single", IsSingle) + .AddClass("disabled", IsDisabled) + .Build(); + + /// + /// 获得/设置 预览框 Style 属性 + /// + private string? PrevStyleString => CssBuilder.Default() + .AddClass($"width: {Width}px;", Width > 0) + .AddClass($"height: {Height}px;", Height > 0 && !IsCircle) + .AddClass($"height: {Width}px;", IsCircle) + .Build(); + + private string? ValidStatusIconString => CssBuilder.Default("valid-icon valid") + .AddClass(ValidStatusIcon) + .Build(); + + private string? InvalidStatusIconString => CssBuilder.Default("valid-icon invalid") + .AddClass(InvalidStatusIcon) + .Build(); + /// /// /// diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 601c34b1f2d..89f7fe711cd 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @typeparam TValue -@inherits ButtonUploadBase +@inherits UploadBase @if (IsShowLabel) { diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 6e5ea7e1610..61ff7de0d90 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -124,6 +124,127 @@ public partial class ButtonUpload [NotNull] private IIconTheme? IconTheme { get; set; } + /// + /// 获得/设置 是否上传整个目录 默认为 false + /// + [Parameter] + public bool IsDirectory { get; set; } + + /// + /// 获得/设置 是否允许多文件上传 默认 false 不允许 + /// + [Parameter] + public bool IsMultiple { get; set; } + + /// + /// 获得/设置 设置文件格式图标回调委托 + /// + [Parameter] + public Func? OnGetFileFormat { get; set; } + + /// + /// 获得/设置 是否显示下载按钮 默认 false + /// + [Parameter] + public bool ShowDownloadButton { get; set; } + + /// + /// 获得/设置 点击下载按钮回调方法 默认 null + /// + [Parameter] + public Func? OnDownload { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconExcel { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconDocx { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPPT { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconAudio { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconVideo { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconCode { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPdf { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconZip { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconArchive { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconImage { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconFile { get; set; } + + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + + /// + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + + private string? ClassString => CssBuilder.Default("upload") + .AddClassFromAttributes(AdditionalAttributes) + .Build(); + + private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-invalid", item.Code != 0) + .Build(); + + private string? ItemClassString => CssBuilder.Default("upload-item") + .AddClass("disabled", IsDisabled) + .Build(); + /// /// OnParametersSet 方法 /// @@ -138,5 +259,100 @@ protected override void OnParametersSet() ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadValidStatusIcon); DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDownloadIcon); DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDeleteIcon); + + FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); + FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); + FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); + FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); + FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); + FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); + FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); + FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); + FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); + FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); + FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); + CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); + } + + /// + /// 点击下载按钮回调此方法 + /// + /// + /// + protected async Task OnClickDownload(UploadFile item) + { + if (OnDownload != null) + { + await OnDownload(item); + } + } + + /// + /// 点击取消按钮回调此方法 + /// + /// + /// + protected async Task OnClickCancel(UploadFile item) + { + if (OnCancel != null) + { + await OnCancel(item); + } + } + + /// + /// + /// + /// + protected override IDictionary GetUploadAdditionalAttributes() + { + var ret = base.GetUploadAdditionalAttributes(); + + if (IsMultiple) + { + ret.Add("multiple", "multiple"); + } + + if (IsDirectory) + { + ret.Add("directory", "dicrectory"); + ret.Add("webkitdirectory", "webkitdirectory"); + } + return ret; + } + + /// + /// + /// + /// + /// + private string? GetFileFormatClassString(UploadFile item) + { + var builder = CssBuilder.Default("file-icon"); + var fileExtension = Path.GetExtension(item.OriginFileName ?? item.FileName); + if (!string.IsNullOrEmpty(fileExtension)) + { + fileExtension = fileExtension.ToLowerInvariant(); + } + var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(); + builder.AddClass(icon); + return builder.Build(); + + // switch 关键字导致无法 100% 覆盖 + [ExcludeFromCodeCoverage] + string? GetFileExtensions() => fileExtension switch + { + ".csv" or ".xls" or ".xlsx" => FileIconExcel, + ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, + ".ppt" or ".pptx" => FileIconPPT, + ".wav" or ".mp3" => FileIconAudio, + ".mp4" or ".mov" or ".mkv" => FileIconVideo, + ".cs" or ".html" or ".vb" => FileIconCode, + ".pdf" => FileIconPdf, + ".zip" or ".rar" or ".iso" => FileIconZip, + ".txt" or ".log" => FileIconArchive, + ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, + _ => FileIconFile + }; } } diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUploadBase.cs b/src/BootstrapBlazor/Components/Upload/ButtonUploadBase.cs deleted file mode 100644 index eb37f1f6aeb..00000000000 --- a/src/BootstrapBlazor/Components/Upload/ButtonUploadBase.cs +++ /dev/null @@ -1,305 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.AspNetCore.Components.Forms; - -namespace BootstrapBlazor.Components; - -/// -/// 按钮上传组件基类 -/// -public abstract class ButtonUploadBase : SingleUploadBase -{ - /// - /// 获得/设置 是否上传整个目录 默认为 false - /// - [Parameter] - public bool IsDirectory { get; set; } - - /// - /// 获得/设置 是否允许多文件上传 默认 false 不允许 - /// - /// 多选文件时,所有文件处理完毕后,会额外触发一次 回调 - [Parameter] - public bool IsMultiple { get; set; } - - /// - /// 获得/设置 设置文件格式图标回调委托 - /// - [Parameter] - public Func? OnGetFileFormat { get; set; } - - /// - /// 获得/设置 是否显示下载按钮 默认 false - /// - [Parameter] - public bool ShowDownloadButton { get; set; } - - /// - /// 获得/设置 点击下载按钮回调方法 默认 null - /// - [Parameter] - public Func? OnDownload { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconExcel { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconDocx { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPPT { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconAudio { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconVideo { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconCode { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPdf { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconZip { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconArchive { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconImage { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconFile { get; set; } - - /// - /// 获得/设置 取消图标 - /// - [Parameter] - public string? CancelIcon { get; set; } - - /// - /// 获得/设置 点击取消按钮回调此方法 默认 null - /// - [Parameter] - public Func? OnCancel { get; set; } - - /// - /// 获得/设置 所有文件上传完毕回调方法 默认 null - /// - [Parameter] - public Func, Task>? OnAllFileUploaded { get; set; } - - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - - /// - /// OnInitialized 方法 - /// - protected override void OnInitialized() - { - base.OnInitialized(); - - // 上传文件夹时 开启 Multiple 属性 - if (IsDirectory) - { - IsMultiple = true; - } - } - - /// - /// - /// - protected override void OnParametersSet() - { - base.OnParametersSet(); - - FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); - FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); - FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); - FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); - FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); - FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); - FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); - FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); - FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); - FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); - FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); - CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); - } - - /// - /// - /// - /// - /// - protected override async Task OnFileChange(InputFileChangeEventArgs args) - { - if (IsMultiple) - { - var items = args.GetMultipleFiles(args.FileCount).Select(f => new UploadFile() - { - OriginFileName = f.Name, - Size = f.Size, - File = f, - FileCount = args.FileCount, - Uploaded = OnChange == null, - UpdateCallback = Update - }).ToList(); - UploadFiles.AddRange(items); - if (OnChange != null) - { - foreach (var item in items) - { - await OnChange(item); - item.Uploaded = true; - StateHasChanged(); - } - } - if (OnAllFileUploaded != null) - { - await OnAllFileUploaded(UploadFiles); - } - } - else - { - var file = new UploadFile() - { - OriginFileName = args.File.Name, - Size = args.File.Size, - File = args.File, - Uploaded = false, - UpdateCallback = Update - }; - UploadFiles.Add(file); - if (OnChange != null) - { - await OnChange(file); - } - file.Uploaded = true; - } - - //触发 ValueChange,以支持 bind-value - await base.OnFileChange(args); - } - - /// - /// - /// - /// - /// - protected string? GetFileFormatClassString(UploadFile item) - { - var builder = CssBuilder.Default("file-icon"); - var fileExtension = Path.GetExtension(item.OriginFileName ?? item.FileName); - if (!string.IsNullOrEmpty(fileExtension)) - { - fileExtension = fileExtension.ToLowerInvariant(); - } - var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(); - builder.AddClass(icon); - return builder.Build(); - - // switch 关键字导致无法 100% 覆盖 - [ExcludeFromCodeCoverage] - string? GetFileExtensions() => fileExtension switch - { - ".csv" or ".xls" or ".xlsx" => FileIconExcel, - ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, - ".ppt" or ".pptx" => FileIconPPT, - ".wav" or ".mp3" => FileIconAudio, - ".mp4" or ".mov" or ".mkv" => FileIconVideo, - ".cs" or ".html" or ".vb" => FileIconCode, - ".pdf" => FileIconPdf, - ".zip" or ".rar" or ".iso" => FileIconZip, - ".txt" or ".log" => FileIconArchive, - ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, - _ => FileIconFile - }; - } - - /// - /// - /// - /// - protected override IDictionary GetUploadAdditionalAttributes() - { - var ret = base.GetUploadAdditionalAttributes(); - - if (IsMultiple) - { - ret.Add("multiple", "multiple"); - } - - if (IsDirectory) - { - ret.Add("directory", "dicrectory"); - ret.Add("webkitdirectory", "webkitdirectory"); - } - return ret; - } - - /// - /// 点击下载按钮回调此方法 - /// - /// - /// - protected async Task OnClickDownload(UploadFile item) - { - if (OnDownload != null) - { - await OnDownload(item); - } - } - - /// - /// 点击取消按钮回调此方法 - /// - /// - /// - protected async Task OnClickCancel(UploadFile item) - { - if (OnCancel != null) - { - await OnCancel(item); - } - } -} diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 9a02c28b95f..27ae12a2288 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @typeparam TValue -@inherits ButtonUploadBase +@inherits UploadBase @if (IsShowLabel) { diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 90b847dab8d..9e722103089 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -10,6 +10,19 @@ namespace BootstrapBlazor.Components; ///
public partial class CardUpload { + private string? ClassString => CssBuilder.Default("upload") + .AddClassFromAttributes(AdditionalAttributes) + .Build(); + + private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-invalid", item.Code != 0) + .Build(); + private string? ItemClassString => CssBuilder.Default("upload-item") + .AddClass("is-single", IsSingle) + .AddClass("disabled", IsDisabled) + .Build(); + private string? BodyClassString => CssBuilder.Default("upload-body is-card") .AddClass("is-single", IsSingle) .Build(); @@ -102,6 +115,30 @@ public partial class CardUpload [Parameter] public bool IsUploadButtonAtFirst { get; set; } + /// + /// 获得/设置 是否显示下载按钮 默认 false + /// + [Parameter] + public bool ShowDownloadButton { get; set; } + + /// + /// 获得/设置 点击下载按钮回调方法 默认 null + /// + [Parameter] + public Func? OnDownload { get; set; } + + /// + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } @@ -166,4 +203,30 @@ private async Task OnClickZoom(UploadFile item) await OnZoomAsync(item); } } + + /// + /// 点击下载按钮回调此方法 + /// + /// + /// + protected async Task OnClickDownload(UploadFile item) + { + if (OnDownload != null) + { + await OnDownload(item); + } + } + + /// + /// 点击取消按钮回调此方法 + /// + /// + /// + protected async Task OnClickCancel(UploadFile item) + { + if (OnCancel != null) + { + await OnCancel(item); + } + } } diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index e78bb0ee8f3..84a2532e49d 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -1,11 +1,11 @@ @namespace BootstrapBlazor.Components -@inherits SingleUploadBase +@inherits UploadBase @if (IsShowLabel) { } -
+
@if (BodyTemplate != null) { diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index f508f531d5b..9a79d0c19c3 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.AspNetCore.Components.Forms; using Microsoft.Extensions.Localization; namespace BootstrapBlazor.Components; @@ -72,8 +71,7 @@ public partial class DropUpload [NotNull] private IStringLocalizer>? Localizer { get; set; } - private string? DropUploadClassString => CssBuilder.Default(ClassString) - .AddClass("is-drop") + private string? ClassString => CssBuilder.Default("upload is-drop") .AddClassFromAttributes(AdditionalAttributes) .Build(); @@ -88,27 +86,4 @@ protected override void OnParametersSet() UploadText ??= Localizer["DropUploadText"]; FooterText ??= Localizer["DropFooterText"]; } - - /// - /// - /// - /// - /// - protected override async Task OnFileChange(InputFileChangeEventArgs args) - { - var file = new UploadFile() - { - OriginFileName = args.File.Name, - Size = args.File.Size, - File = args.File, - Uploaded = false, - UpdateCallback = Update - }; - UploadFiles.Add(file); - if (OnChange != null) - { - await OnChange(file); - } - file.Uploaded = true; - } } diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index bcecdf40a2a..f0fabad5eec 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.AspNetCore.Components.Forms; using Microsoft.Extensions.Localization; namespace BootstrapBlazor.Components; @@ -13,22 +12,6 @@ namespace BootstrapBlazor.Components; ///
public partial class InputUpload { - private string? InputValueClassString => CssBuilder.Default("form-control") - .AddClass(CssClass).AddClass(ValidCss) - .Build(); - - private string? RemoveButtonClassString => CssBuilder.Default() - .AddClass(DeleteButtonClass) - .Build(); - - private bool IsDeleteButtonDisabled => IsDisabled || CurrentFile == null; - - private string? BrowserButtonClassString => CssBuilder.Default("btn-browser") - .AddClass(BrowserButtonClass) - .Build(); - - private string? GetFileName() => CurrentFile?.GetFileName() ?? Value?.ToString(); - /// /// 获得/设置 浏览按钮图标 /// @@ -87,16 +70,25 @@ public partial class InputUpload [NotNull] private IIconTheme? IconTheme { get; set; } - /// - /// - /// - protected override void OnInitialized() - { - base.OnInitialized(); + private string? InputValueClassString => CssBuilder.Default("form-control") + .AddClass(CssClass).AddClass(ValidCss) + .Build(); - DeleteButtonText ??= Localizer[nameof(DeleteButtonText)]; - BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; - } + private string? RemoveButtonClassString => CssBuilder.Default() + .AddClass(DeleteButtonClass) + .Build(); + + private bool IsDeleteButtonDisabled => IsDisabled || CurrentFile == null; + + private string? BrowserButtonClassString => CssBuilder.Default("btn-browser") + .AddClass(BrowserButtonClass) + .Build(); + + private string? GetFileName() => CurrentFile?.GetFileName() ?? Value?.ToString(); + + private string? ClassString => CssBuilder.Default("upload") + .AddClassFromAttributes(AdditionalAttributes) + .Build(); /// /// @@ -105,37 +97,13 @@ protected override void OnParametersSet() { base.OnParametersSet(); + DeleteButtonText ??= Localizer[nameof(DeleteButtonText)]; + BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; + BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadBrowserButtonIcon); DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } - /// - /// 上传文件改变时回调方法 - /// - /// - /// - protected override async Task OnFileChange(InputFileChangeEventArgs args) - { - CurrentFile = new UploadFile() - { - OriginFileName = args.File.Name, - Size = args.File.Size, - File = args.File, - Uploaded = false - }; - - UploadFiles.Clear(); - UploadFiles.Add(CurrentFile); - - await base.OnFileChange(args); - - if (OnChange != null) - { - await OnChange(CurrentFile); - } - CurrentFile.Uploaded = true; - } - private async Task OnDeleteFile() { if (CurrentFile != null) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss similarity index 100% rename from src/BootstrapBlazor/Components/Upload/UploadBase.razor.scss rename to src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss diff --git a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs deleted file mode 100644 index eef0a2756d7..00000000000 --- a/src/BootstrapBlazor/Components/Upload/MultipleUploadBase.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -namespace BootstrapBlazor.Components; - -/// -/// MultipleUploadBase 基类 -/// -public abstract class MultipleUploadBase : UploadBase -{ - /// - /// - /// - /// - /// - protected string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item.Uploaded && item.Code == 0) - .AddClass("is-invalid", item.Code != 0) - .AddClass("disabled", IsDisabled) - .Build(); - - /// - /// - /// - protected virtual string? ItemClassString => CssBuilder.Default("upload-item") - .Build(); - - /// - /// 获得/设置 已上传文件集合 - /// - [Parameter] - public List? DefaultFileList { get; set; } - - /// - /// 获得/设置 是否显示上传进度 默认为 false - /// - [Parameter] - public bool ShowProgress { get; set; } - - /// - /// OnFileDelete 回调委托 - /// - /// - /// - protected override async Task OnFileDelete(UploadFile item) - { - var ret = await base.OnFileDelete(item); - if (ret) - { - UploadFiles.Remove(item); - if (!string.IsNullOrEmpty(item.ValidateId)) - { - await RemoveValidResult(item.ValidateId); - } - DefaultFileList?.Remove(item); - } - return ret; - } - - /// - /// 是否显示进度条方法 - /// - /// - /// - protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; - - /// - /// 清空上传列表方法 - /// - public override void Reset() - { - DefaultFileList?.Clear(); - base.Reset(); - } -} diff --git a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs deleted file mode 100644 index 4cfac7b9513..00000000000 --- a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -namespace BootstrapBlazor.Components; - -/// -/// SingleUploadBase 基类 -/// -/// -public abstract class SingleUploadBase : MultipleUploadBase -{ - /// - /// 获得/设置 是否仅上传一次 默认 false - /// - [Parameter] - public bool IsSingle { get; set; } - - /// - /// 获得/设置 最大上传个数 默认为最大值 - /// - [Parameter] - public int Max { get; set; } = int.MaxValue; - - /// - /// 是否显示上传组件 - /// - protected bool CheckCanUpload() - { - var count = GetUploadFiles().Count; - return IsSingle ? count < 1 : count < Max; - } - - /// - /// 获得当前图片集合 - /// - /// - protected virtual List GetUploadFiles() - { - var ret = new List(); - if (IsSingle) - { - if (DefaultFileList != null && DefaultFileList.Count != 0) - { - ret.Add(DefaultFileList.First()); - } - if (ret.Count == 0 && UploadFiles.Count != 0) - { - ret.Add(UploadFiles.First()); - } - } - else - { - if (DefaultFileList != null) - { - ret.AddRange(DefaultFileList); - } - ret.AddRange(UploadFiles); - } - return ret; - } - - /// - /// OnFileDelete 回调委托 - /// - /// - /// - protected override async Task OnFileDelete(UploadFile item) - { - var ret = await base.OnFileDelete(item); - if (ret) - { - if (IsSingle) - { - UploadFiles.Clear(); - } - else - { - UploadFiles.Remove(item); - } - if (!string.IsNullOrEmpty(item.ValidateId)) - { - await RemoveValidResult(item.ValidateId); - } - RemoveItem(); - } - - void RemoveItem() - { - if (DefaultFileList != null) - { - if (IsSingle) - { - DefaultFileList.Clear(); - } - else - { - DefaultFileList.Remove(item); - } - } - } - return ret; - } - - /// - /// 更新上传进度方法 - /// - /// - protected void Update(UploadFile file) - { - if (GetShowProgress(file)) - { - StateHasChanged(); - } - } -} diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 3e6da1db6e3..9857bb3756d 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -14,11 +14,28 @@ namespace BootstrapBlazor.Components; public abstract class UploadBase : ValidateBase, IUpload { /// - /// 获得 组件样式 + /// 获得/设置 是否仅上传一次 默认 false /// - protected string? ClassString => CssBuilder.Default("upload") - .AddClassFromAttributes(AdditionalAttributes) - .Build(); + [Parameter] + public bool IsSingle { get; set; } + + /// + /// 获得/设置 最大上传个数 默认为最大值 + /// + [Parameter] + public int Max { get; set; } = int.MaxValue; + + /// + /// 获得/设置 所有文件上传完毕回调方法 默认 null + /// + [Parameter] + public Func, Task>? OnAllFileUploaded { get; set; } + + /// + /// 获得/设置 已上传文件集合 + /// + [Parameter] + public List? DefaultFileList { get; set; } /// /// 获得/设置 当前上传文件 @@ -32,6 +49,12 @@ public abstract class UploadBase : ValidateBase, IUpload List IUpload.UploadFiles { get => UploadFiles; } + /// + /// 获得/设置 是否显示上传进度 默认为 false + /// + [Parameter] + public bool ShowProgress { get; set; } + /// /// 获得/设置 上传接收的文件格式 默认为 null 接收任意格式 /// @@ -99,27 +122,18 @@ protected virtual async Task OnFileDelete(UploadFile item) ret = await OnDelete(item); } ErrorMessage = null; - return ret; - } - /// - /// 上传文件改变时回调此方法 - /// - /// - /// - protected virtual Task OnFileChange(InputFileChangeEventArgs args) - { - // 判定可为空 - var type = NullableUnderlyingType ?? typeof(TValue); - if (type.IsAssignableTo(typeof(IBrowserFile))) - { - CurrentValue = (TValue)args.File; - } - if (type.IsAssignableTo(typeof(List))) + if (ret) { - CurrentValue = (TValue)(object)UploadFiles.Select(f => f.File).ToList(); + UploadFiles.Remove(item); + if (!string.IsNullOrEmpty(item.ValidateId)) + { + await RemoveValidResult(item.ValidateId); + } + DefaultFileList?.Remove(item); } - return Task.CompletedTask; + return ret; + } /// @@ -148,7 +162,108 @@ protected virtual IDictionary GetUploadAdditionalAttributes() /// public virtual void Reset() { + DefaultFileList?.Clear(); UploadFiles.Clear(); StateHasChanged(); } + + /// + /// 是否显示进度条方法 + /// + /// + /// + protected bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; + + /// + /// 更新上传进度方法 + /// + /// + protected void Update(UploadFile file) + { + if (GetShowProgress(file)) + { + StateHasChanged(); + } + } + + /// + /// + /// + /// + /// + protected virtual async Task OnFileChange(InputFileChangeEventArgs args) + { + // init UploadFiles + var items = args.GetMultipleFiles(args.FileCount).Select(f => new UploadFile() + { + OriginFileName = f.Name, + Size = f.Size, + File = f, + FileCount = args.FileCount, + Uploaded = OnChange == null, + UpdateCallback = Update + }).ToList(); + UploadFiles.AddRange(items); + + // trigger OnChange event callback + if (OnChange != null) + { + foreach (var item in items) + { + await OnChange(item); + item.Uploaded = true; + StateHasChanged(); + } + } + + // trigger OnAllFileUploaded event callback + if (OnAllFileUploaded != null) + { + await OnAllFileUploaded(UploadFiles); + } + + var type = NullableUnderlyingType ?? typeof(TValue); + if (type.IsAssignableTo(typeof(List))) + { + CurrentValue = (TValue)(object)UploadFiles.Select(f => f.File).ToList(); + } + } + + /// + /// 是否显示上传组件 + /// + protected bool CheckCanUpload() + { + var count = GetUploadFiles().Count; + return IsSingle ? count < 1 : count < Max; + } + + /// + /// 获得当前图片集合 + /// + /// + protected virtual List GetUploadFiles() + { + var ret = new List(); + if (IsSingle) + { + if (DefaultFileList != null && DefaultFileList.Count != 0) + { + ret.Add(DefaultFileList.First()); + } + if (ret.Count == 0 && UploadFiles.Count != 0) + { + ret.Add(UploadFiles.First()); + } + } + else + { + if (DefaultFileList != null) + { + ret.AddRange(DefaultFileList); + } + ret.AddRange(UploadFiles); + } + return ret; + } } diff --git a/src/BootstrapBlazor/wwwroot/scss/components.scss b/src/BootstrapBlazor/wwwroot/scss/components.scss index cb52a9e2678..da15073286f 100644 --- a/src/BootstrapBlazor/wwwroot/scss/components.scss +++ b/src/BootstrapBlazor/wwwroot/scss/components.scss @@ -72,7 +72,7 @@ @import "../../Components/Pagination/Pagination.razor.scss"; @import "../../Components/Popover/Popover.razor.scss"; @import "../../Components/QueryBuilder/QueryBuilder.razor.scss"; -@import "../../Components/Upload/UploadBase.razor.scss"; +@import "../../Components/Upload/InputUpload.razor.scss"; @import "../../Components/ValidateForm/ValidateForm.razor.scss"; @import "../../Components/Radio/RadioList.razor.scss"; @import "../../Components/Rate/Rate.razor.scss"; From dc2234d8fd47e5ff41ac34719b6aebbad5e0076d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 16:16:48 +0800 Subject: [PATCH 004/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Uploads.razor | 8 -------- src/BootstrapBlazor.Server/Locales/en-US.json | 2 -- src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 -- 3 files changed, 12 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index 17dc5ab1615..e432ebec96e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -16,14 +16,6 @@ Introduction="@Localizer["UploadNormalIntro"]" Name="Normal">
-
- - -
-
- - -
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 04a5dd1a7cc..17a52c9848a 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3448,8 +3448,6 @@ "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", "UploadNormalTitle": "Basic usage", "UploadNormalIntro": "The InputUpload component is used with other form components to display the file name, select the file and upload it by clicking the browse button, and by setting the ShowRemoveButton parameter, display the delete button, click the delete button to call back onDelete delegate method", - "UploadNormalLabelName": "Name:", - "UploadNormalLabelAddress": "Address:", "UploadNormalLabelPhoto": "Photo:", "UploadFormSettingsTitle": "FormSettings", "UploadFormSettingsIntro": "Use the file upload component to constrain the file format within the form", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index c5478c69f93..6050c55b34e 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3448,8 +3448,6 @@ "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "UploadNormalTitle": "基础用法", "UploadNormalIntro": "InputUpload 组件与其他表单组件一起使用,显示文件名称,点击 浏览 按钮后选择文件并上传;通过设置 ShowRemoveButton 参数,显示 删除 按钮,点击删除按钮时回调 OnDelete 委托方法", - "UploadNormalLabelName": "姓名:", - "UploadNormalLabelAddress": "地址:", "UploadNormalLabelPhoto": "照片:", "UploadFormSettingsTitle": "表单应用", "UploadFormSettingsIntro": "在表单内使用文件上传组件对文件格式进行约束", From 4d1a6298c14f16138eb25c246f48a3da7c65bf52 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 16:25:25 +0800 Subject: [PATCH 005/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadBase.cs | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 9857bb3756d..047c5617b54 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -45,7 +45,7 @@ public abstract class UploadBase : ValidateBase, IUpload /// /// 获得/设置 上传文件集合 /// - protected List UploadFiles { get; } = []; + protected List UploadFiles { get; set; } = []; List IUpload.UploadFiles { get => UploadFiles; } @@ -110,7 +110,50 @@ public override void ToggleMessage(IEnumerable results) } /// - /// + /// + /// + /// + /// + protected virtual async Task OnFileChange(InputFileChangeEventArgs args) + { + // init UploadFiles + var items = args.GetMultipleFiles(args.FileCount).Select(f => new UploadFile() + { + OriginFileName = f.Name, + Size = f.Size, + File = f, + FileCount = args.FileCount, + Uploaded = OnChange == null, + UpdateCallback = Update + }); + UploadFiles.AddRange(items); + + // trigger OnChange event callback + if (OnChange != null) + { + foreach (var item in items) + { + await OnChange(item); + item.Uploaded = true; + } + StateHasChanged(); + } + + // trigger OnAllFileUploaded event callback + if (OnAllFileUploaded != null) + { + await OnAllFileUploaded(UploadFiles); + } + + var type = NullableUnderlyingType ?? typeof(TValue); + if (type.IsAssignableTo(typeof(List))) + { + CurrentValue = (TValue)(object)UploadFiles.Select(f => f.File).ToList(); + } + } + + /// + /// Delete file method. /// /// /// @@ -137,7 +180,7 @@ protected virtual async Task OnFileDelete(UploadFile item) } /// - /// + /// append html attribute method. /// /// protected virtual IDictionary GetUploadAdditionalAttributes() @@ -157,16 +200,6 @@ protected virtual IDictionary GetUploadAdditionalAttributes() return ret; } - /// - /// 清空上传列表方法 - /// - public virtual void Reset() - { - DefaultFileList?.Clear(); - UploadFiles.Clear(); - StateHasChanged(); - } - /// /// 是否显示进度条方法 /// @@ -186,49 +219,6 @@ protected void Update(UploadFile file) } } - /// - /// - /// - /// - /// - protected virtual async Task OnFileChange(InputFileChangeEventArgs args) - { - // init UploadFiles - var items = args.GetMultipleFiles(args.FileCount).Select(f => new UploadFile() - { - OriginFileName = f.Name, - Size = f.Size, - File = f, - FileCount = args.FileCount, - Uploaded = OnChange == null, - UpdateCallback = Update - }).ToList(); - UploadFiles.AddRange(items); - - // trigger OnChange event callback - if (OnChange != null) - { - foreach (var item in items) - { - await OnChange(item); - item.Uploaded = true; - StateHasChanged(); - } - } - - // trigger OnAllFileUploaded event callback - if (OnAllFileUploaded != null) - { - await OnAllFileUploaded(UploadFiles); - } - - var type = NullableUnderlyingType ?? typeof(TValue); - if (type.IsAssignableTo(typeof(List))) - { - CurrentValue = (TValue)(object)UploadFiles.Select(f => f.File).ToList(); - } - } - /// /// 是否显示上传组件 /// @@ -266,4 +256,14 @@ protected virtual List GetUploadFiles() } return ret; } + + /// + /// 清空上传列表方法 + /// + public virtual void Reset() + { + DefaultFileList?.Clear(); + UploadFiles.Clear(); + StateHasChanged(); + } } From 8de6408376b7bed903b320132b09fec15d28e97a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 15 May 2025 18:06:42 +0800 Subject: [PATCH 006/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20InputU?= =?UTF-8?q?pload=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 16 ++--- .../Components/Upload/InputUpload.razor | 2 +- .../Components/Upload/InputUpload.razor.cs | 30 ++++++--- .../Components/Upload/UploadBase.cs | 62 +++++++++++++------ 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 8779d3c0a0f..39ce6c801ed 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -105,6 +105,8 @@ public partial class AvatarUpload .AddClass(InvalidStatusIcon) .Build(); + private UploadFile? _currentFile = null; + /// /// /// @@ -126,14 +128,14 @@ protected override void OnParametersSet() /// protected override async Task OnFileChange(InputFileChangeEventArgs args) { - CurrentFile = new UploadFile() + _currentFile = new UploadFile() { OriginFileName = args.File.Name, Size = args.File.Size, File = args.File, Uploaded = false }; - CurrentFile.ValidateId = $"{Id}_{CurrentFile.GetHashCode()}"; + _currentFile.ValidateId = $"{Id}_{_currentFile.GetHashCode()}"; if (IsSingle) { @@ -142,20 +144,20 @@ protected override async Task OnFileChange(InputFileChangeEventArgs args) UploadFiles.Clear(); } - UploadFiles.Add(CurrentFile); + UploadFiles.Add(_currentFile); await base.OnFileChange(args); // ValidateFile 后 IsValid 才有值 - CurrentFile.IsValid = IsValid; + _currentFile.IsValid = IsValid; if (OnChange != null) { - await OnChange(CurrentFile); + await OnChange(_currentFile); } else { - await CurrentFile.RequestBase64ImageFileAsync(CurrentFile.File.ContentType, 320, 240); + await _currentFile.RequestBase64ImageFileAsync(_currentFile.File.ContentType, 320, 240); } } @@ -163,5 +165,5 @@ protected override async Task OnFileChange(InputFileChangeEventArgs args) /// 获得 弹窗客户端 ID ///
/// - protected override string? RetrieveId() => CurrentFile?.ValidateId; + protected override string? RetrieveId() => _currentFile?.ValidateId; } diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor b/src/BootstrapBlazor/Components/Upload/InputUpload.razor index 4d408f48589..936fc16693f 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor @@ -8,7 +8,7 @@ }
- + @if (ShowDeleteButton) { @@ -148,11 +152,11 @@

@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)

- +

@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)

- +
@@ -160,13 +164,13 @@ - + - + @@ -180,7 +184,7 @@ - + From 0fc262b295323e942ab172c73866577fad6e6371 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 09:13:35 +0800 Subject: [PATCH 014/177] =?UTF-8?q?doc:=20=E6=96=87=E6=A1=A3=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index a77d27d25af..e7a6a84ca47 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -75,7 +75,7 @@ Introduction="@Localizer["UploadedFilesIntro"]" Name="UploadedFiles">
-
+
@@ -86,7 +86,7 @@ Introduction="@Localizer["UploadFolderIntro"]" Name="UploadFolder">
-
+
From 394fa6707043bfb120096b640d0b9a9d258eae82 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:18:24 +0800 Subject: [PATCH 015/177] =?UTF-8?q?style:=20=E8=B0=83=E6=95=B4=E9=97=B4?= =?UTF-8?q?=E8=B7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 4 ++-- src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 908aba728fe..581315c23b3 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -4,6 +4,7 @@ --bb-upload-body-list-item-padding: #{$bb-upload-body-list-item-padding}; --bb-upload-body-list-item-body-padding: #{$bb-upload-body-list-item-body-padding}; --bb-upload-body-list-item-hover-color: #{$bb-upload-body-list-item-hover-color}; + --bb-upload-body-list-grap: #{$bb-upload-body-list-grap}; --bb-upload-card-width: #{$bb-upload-card-width}; --bb-upload-card-height: #{$bb-upload-card-height}; --bb-upload-card-shadow: #{$bb-upload-card-shadow}; @@ -102,6 +103,7 @@ margin: 0; display: flex; flex-wrap: wrap; + gap: 1rem; } .upload .upload-body.is-avatar .upload-item { @@ -109,8 +111,6 @@ position: relative; border: 1px dashed var(--bs-border-color); border-radius: 6px; - margin-inline-end: 1rem; - margin-block-end: 1rem; overflow: hidden; cursor: pointer; } diff --git a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss index ba4954600d9..949ca5445b0 100644 --- a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss +++ b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss @@ -689,6 +689,7 @@ $bb-tree-disabled-opacity: .5; // Upload $bb-upload-body-margin-top: 10px; +$bb-upload-body-list-grap: 1rem; $bb-upload-body-list-max-height: 240px; $bb-upload-body-list-item-padding: 3px 5px; $bb-upload-body-list-item-body-padding: 0 5px; From dcbbb7657501024c4225a6264a06712e300715c0 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:18:36 +0800 Subject: [PATCH 016/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor | 2 +- src/BootstrapBlazor.Server/Locales/en-US.json | 4 ++-- src/BootstrapBlazor.Server/Locales/zh-CN.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index e7a6a84ca47..37a68a64782 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -97,7 +97,7 @@ Name="AvatarUpload">
-

@Localizer["AvatarUploadTips1"]

+

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 17a52c9848a..5309ecaa925 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3465,7 +3465,7 @@ "UploadFolderIntro": "Use DefaultFileList to set up uploaded content", "AvatarUploadTitle": "User profile picture upload", "AvatarUploadIntro": "AvatarUpload component, using the OnChange to limit the format and size of images uploaded by users. In this example, only jpg/png/bmp/jpeg/gif five picture formats are allowed", - "AvatarUploadTips1": "Card form avatar box", + "AvatarUploadTips1": "Card form avatar box. Allow multiple selections by setting IsMultiple=\"true\". Mostly used for photo walls", "AvatarUploadTips2": "Round avatar frame", "AvatarUploadTips3": "When you set up IsSingle, you can upload only one image or file", "AvatarUploadTips4": "
The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication
", @@ -3482,7 +3482,7 @@ "UploadPreCardStyleLink": "Interested students can view their knowledge of Upload components through the wiki in the open source repository related resources of the [The portal]", "UploadPreCardStyleValidation": "In this example, server-side verification prompts the file for too much prompt when the file size exceeds 5MB", "UploadPreCardStyleTips1": "In this example, the ShowProgress=true display upload progress bar", - "UploadPreCardStyleTips2": "When you set up IsSingle, you can upload only one image or file", + "UploadPreCardStyleTips2": "When you set up IsMultiple=\"false\", you can upload only one image or file", "UploadFileIconTitle": "The file icon", "UploadFileIconIntro": "Icons are displayed in different file formats", "UploadFileIconTemplateTitle": "Custom file icon", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 6050c55b34e..0e66d1bb0b3 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3465,7 +3465,7 @@ "UploadFolderIntro": "使用 DefaultFileList 设置已上传的内容", "AvatarUploadTitle": "用户头像上传", "AvatarUploadIntro": "AvatarUpload 组件,使用 OnChange 限制用户上传的图片格式和大小。本例中仅允许上传 jpg/png/bmp/jpeg/gif 五种图片格式", - "AvatarUploadTips1": "卡片形式头像框", + "AvatarUploadTips1": "卡片形式头像框,通过设置 IsMultiple=\"true\" 允许多选。多用于照片墙", "AvatarUploadTips2": "圆形头像框", "AvatarUploadTips3": "设置 IsSingle 时,仅可以上传一张图片或者文件", "AvatarUploadTips4": "
组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证
", @@ -3482,7 +3482,7 @@ "UploadPreCardStyleLink": "有兴趣的同学可以通过开源仓库中的 wiki 文档中相关资源查看关于 Upload 组件的相关知识技巧 [传送门]", "UploadPreCardStyleValidation": "本例中通过服务器端验证当文件大小超过 5MB 时,提示文件太大提示信息", "UploadPreCardStyleTips1": "本例中设置 ShowProgress=true 显示上传进度条", - "UploadPreCardStyleTips2": "设置 IsSingle 时,仅可以上传一张图片或者文件", + "UploadPreCardStyleTips2": "设置 IsMultiple=\"false\" 时,仅可以上传一张图片或者文件", "UploadFileIconTitle": "文件图标", "UploadFileIconIntro": "不同文件格式显示的图标不同", "UploadFileIconTemplateTitle": "自定义文件图标", From 1788107fde547dca53b34508497415d46106d707 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:18:58 +0800 Subject: [PATCH 017/177] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E6=96=B9=E6=B3=95=E9=BB=98=E8=AE=A4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Extensions/UploadFileExtensions.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index 54d84ac82e0..b99c620ffb3 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -21,15 +21,17 @@ public static class UploadFileExtensions /// /// /// - [ExcludeFromCodeCoverage] - public static async Task RequestBase64ImageFileAsync(this UploadFile upload, string format, int maxWidth, int maxHeight, long maxAllowedSize = 512000, CancellationToken token = default) + public static async Task RequestBase64ImageFileAsync(this UploadFile upload, string? format = null, int maxWidth = 320, int maxHeight = 240, long? maxAllowedSize = null, CancellationToken token = default) { if (upload.File != null) { try { + format ??= upload.File.ContentType; var imageFile = await upload.File.RequestImageFileAsync(format, maxWidth, maxHeight); - using var fileStream = imageFile.OpenReadStream(maxAllowedSize, token); + + maxAllowedSize ??= upload.File.Size; + using var fileStream = imageFile.OpenReadStream(maxAllowedSize.Value, token); using var memoryStream = new MemoryStream(); await fileStream.CopyToAsync(memoryStream, token); upload.PrevUrl = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}"; From 5549f58ffde6c9495d878f4fa27084692d2a6064 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:19:16 +0800 Subject: [PATCH 018/177] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E5=A4=B4?= =?UTF-8?q?=E5=83=8F=E4=B8=8A=E4=BC=A0=E7=BB=84=E4=BB=B6=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 56 ++++++++----------- .../Components/Upload/UploadBase.cs | 2 +- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 39ce6c801ed..11b19603ea8 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.AspNetCore.Components.Forms; - namespace BootstrapBlazor.Components; /// @@ -84,7 +82,7 @@ public partial class AvatarUpload private string? ItemClassString => CssBuilder.Default("upload-item") .AddClass("is-circle", IsCircle) - .AddClass("is-single", IsSingle) + .AddClass("is-single", IsMultiple == false) .AddClass("disabled", IsDisabled) .Build(); @@ -105,8 +103,6 @@ public partial class AvatarUpload .AddClass(InvalidStatusIcon) .Build(); - private UploadFile? _currentFile = null; - /// /// /// @@ -124,46 +120,40 @@ protected override void OnParametersSet() /// /// /// - /// /// - protected override async Task OnFileChange(InputFileChangeEventArgs args) + protected override bool CheckCanUpload() { - _currentFile = new UploadFile() + // 允许多上传 + if(IsMultiple == true) { - OriginFileName = args.File.Name, - Size = args.File.Size, - File = args.File, - Uploaded = false - }; - _currentFile.ValidateId = $"{Id}_{_currentFile.GetHashCode()}"; - - if (IsSingle) - { - // 单图片模式 - DefaultFileList?.Clear(); - UploadFiles.Clear(); + return true; } - UploadFiles.Add(_currentFile); - - await base.OnFileChange(args); + // 只允许单个上传 + return UploadFiles.Count == 0; + } - // ValidateFile 后 IsValid 才有值 - _currentFile.IsValid = IsValid; + /// + /// + /// + /// + protected override async Task OnFileUpload(List items) + { + await base.OnFileUpload(items); - if (OnChange != null) + foreach (var item in items) { - await OnChange(_currentFile); - } - else - { - await _currentFile.RequestBase64ImageFileAsync(_currentFile.File.ContentType, 320, 240); + item.ValidateId = $"{Id}_{item.GetHashCode()}"; + if (OnChange != null) + { + await item.RequestBase64ImageFileAsync(); + } } } /// - /// 获得 弹窗客户端 ID + /// /// /// - protected override string? RetrieveId() => _currentFile?.ValidateId; + //protected override string? RetrieveId() => _currentFile?.ValidateId; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 62d28413fe4..b9059c50023 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -272,7 +272,7 @@ protected void Update(UploadFile file) /// /// 是否可以上传 /// - protected bool CheckCanUpload() + protected virtual bool CheckCanUpload() { if (IsDisabled) { From 5a289e8f871c062ad5467534c2bde6a30ad79295 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:48:52 +0800 Subject: [PATCH 019/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/CardUpload.razor | 2 +- .../Components/Upload/CardUpload.razor.cs | 68 ++++++++----------- .../Extensions/UploadFileExtensions.cs | 50 ++++++++++++++ 3 files changed, 78 insertions(+), 42 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 27ae12a2288..4bf2b9302cd 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -16,7 +16,7 @@ {
- @if (IsImage(item)) + @if (item.IsImage(AllowExtensions, CanPreviewCallback)) { prevUrl } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 9e722103089..a5d8ff4ebcb 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -6,7 +6,7 @@ namespace BootstrapBlazor.Components; /// -/// 卡片式上传组件 +/// CardUpload component /// public partial class CardUpload { @@ -19,12 +19,12 @@ public partial class CardUpload .AddClass("is-invalid", item.Code != 0) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") - .AddClass("is-single", IsSingle) + .AddClass("is-single", IsMultiple == false) .AddClass("disabled", IsDisabled) .Build(); private string? BodyClassString => CssBuilder.Default("upload-body is-card") - .AddClass("is-single", IsSingle) + .AddClass("is-single", IsMultiple == false) .Build(); private string? GetDisabledString(UploadFile item) => (!IsDisabled && item.Uploaded && item.Code == 0) ? null : "disabled"; @@ -133,12 +133,24 @@ public partial class CardUpload [Parameter] public Func? OnCancel { get; set; } + /// + /// 获得/设置 点击 Zoom 图标回调方法 + /// + [Parameter] + public Func? OnZoomAsync { get; set; } + /// /// 获得/设置 取消图标 /// [Parameter] public string? CancelIcon { get; set; } + /// + /// 获得/设置 图标文件扩展名集合 ".png" + /// + [Parameter] + public List? AllowExtensions { get; set; } + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } @@ -158,38 +170,22 @@ protected override void OnParametersSet() ZoomIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadZoomIcon); } - private bool IsImage(UploadFile item) + /// + /// + /// + /// + protected override bool CheckCanUpload() { - bool ret; - if (item.File != null) - { - ret = item.File.ContentType.Contains("image", StringComparison.OrdinalIgnoreCase) || CheckExtensions(item.File.Name); - } - else if (CanPreviewCallback != null) + // 允许多上传 + if (IsMultiple == true) { - ret = CanPreviewCallback(item); - } - else - { - ret = IsBase64Format() || CheckExtensions(item.FileName ?? item.PrevUrl ?? ""); + return true; } - bool IsBase64Format() => !string.IsNullOrEmpty(item.PrevUrl) && item.PrevUrl.StartsWith("data:image/", StringComparison.OrdinalIgnoreCase); - - bool CheckExtensions(string fileName) => Path.GetExtension(fileName).ToLowerInvariant() switch - { - ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" or ".webp" => true, - _ => false - }; - return ret; + // 只允许单个上传 + return UploadFiles.Count == 0; } - /// - /// 获得/设置 点击 Zoom 图标回调方法 - /// - [Parameter] - public Func? OnZoomAsync { get; set; } - private async Task OnCardFileDelete(UploadFile item) { await OnFileDelete(item); @@ -204,12 +200,7 @@ private async Task OnClickZoom(UploadFile item) } } - /// - /// 点击下载按钮回调此方法 - /// - /// - /// - protected async Task OnClickDownload(UploadFile item) + private async Task OnClickDownload(UploadFile item) { if (OnDownload != null) { @@ -217,12 +208,7 @@ protected async Task OnClickDownload(UploadFile item) } } - /// - /// 点击取消按钮回调此方法 - /// - /// - /// - protected async Task OnClickCancel(UploadFile item) + private async Task OnClickCancel(UploadFile item) { if (OnCancel != null) { diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index b99c620ffb3..5c127889ac3 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -183,4 +183,54 @@ public static async Task SaveToFileAsync(this UploadFile upload, string fi } return ret; } + + /// + /// Check item whether is image extension method. + /// + /// + /// + /// + /// + public static bool IsImage(this UploadFile item, List? allowExtensions, Func? _callback = null) + { + bool ret; + if (_callback != null) + { + ret = _callback(item); + } + else if (item.File != null) + { + ret = item.File.ContentType.Contains("image", StringComparison.OrdinalIgnoreCase) || item.IsAllowExtensions(allowExtensions); + } + else + { + ret = item.IsBase64Format() || item.IsAllowExtensions(allowExtensions); + } + return ret; + } + + /// + /// Check item whether is base64 format image extension method. + /// + /// + /// + public static bool IsBase64Format(this UploadFile item) => !string.IsNullOrEmpty(item.PrevUrl) && item.PrevUrl.StartsWith("data:image/", StringComparison.OrdinalIgnoreCase); + + /// + /// Check the extension whether in the allowExtensions list. + /// + /// + /// + /// + public static bool IsAllowExtensions(this UploadFile item, List? allowExtensions = null) + { + var ret = false; + allowExtensions ??= [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff", ".webp"]; + var fileName = item.File?.Name ?? item.FileName ?? item.PrevUrl; + if (!string.IsNullOrEmpty(fileName)) + { + ret = allowExtensions.Contains(Path.GetExtension(fileName), StringComparer.OrdinalIgnoreCase); + } + return ret; + } } From 45b431d28288a37f262a6177575fdc879fc789bb Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:49:03 +0800 Subject: [PATCH 020/177] =?UTF-8?q?doc:=20=E8=B0=83=E6=95=B4=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Uploads.razor | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index 37a68a64782..63ab70240bd 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -58,12 +58,12 @@ OnChange="@OnClickToUpload" OnDelete="@(fileName => Task.FromResult(true))">
-

@((MarkupString)Localizer["UploadClickUploadTips2"].Value)

+

@((MarkupString)Localizer["UploadClickUploadTips2"].Value)

-

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

+

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

@@ -142,14 +142,14 @@ Introduction="@Localizer["UploadPreCardStyleIntro"]" Name="PreCardStyle">
-
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
+

@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)

@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)
+

@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)

@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
-
+

@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)

From 236fad830f0877177a81cc626e1d501e98f2fc97 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 10:55:27 +0800 Subject: [PATCH 021/177] =?UTF-8?q?doc:=20=E4=BF=AE=E5=A4=8D=E9=94=AE?= =?UTF-8?q?=E5=80=BC=E4=B8=8D=E6=AD=A3=E7=A1=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Inputs.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Inputs.razor b/src/BootstrapBlazor.Server/Components/Samples/Inputs.razor index 53d9edee2fb..8a37d514352 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Inputs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Inputs.razor @@ -224,7 +224,7 @@ + Name="IsClearable">
From 5ee07514c641dab4e2b9189b56fef59df39f0d40 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:07:03 +0800 Subject: [PATCH 022/177] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/CardUpload.razor | 2 +- src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 4bf2b9302cd..cc29ff1c309 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -62,7 +62,7 @@
@if (GetShowProgress(item)) { - + } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index a5d8ff4ebcb..24c04f4894b 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -15,7 +15,7 @@ public partial class CardUpload .Build(); private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-valid", item is { Uploaded: true, Code: 0 }) .AddClass("is-invalid", item.Code != 0) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") @@ -27,7 +27,7 @@ public partial class CardUpload .AddClass("is-single", IsMultiple == false) .Build(); - private string? GetDisabledString(UploadFile item) => (!IsDisabled && item.Uploaded && item.Code == 0) ? null : "disabled"; + private string? GetDisabledString(UploadFile item) => (!IsDisabled && item is { Uploaded: true, Code: 0 }) ? null : "disabled"; private bool ShowPreviewList => GetUploadFiles().Count != 0; @@ -177,7 +177,7 @@ protected override void OnParametersSet() protected override bool CheckCanUpload() { // 允许多上传 - if (IsMultiple == true) + if (IsMultiple) { return true; } From 8ec170833a47f2fa4855cac40fbab520a8188249 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:07:12 +0800 Subject: [PATCH 023/177] =?UTF-8?q?doc:=20=E8=B0=83=E6=95=B4=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index 63ab70240bd..33460ff178c 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -142,9 +142,9 @@ Introduction="@Localizer["UploadPreCardStyleIntro"]" Name="PreCardStyle">
-

@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)

-
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
-

@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)

+
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)
@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
From f79363819e6129bd2cffeb3de168117d4be6bb22 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:18:57 +0800 Subject: [PATCH 024/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Uploads.razor | 1 - .../Components/Samples/Uploads.razor.cs | 44 +++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index 33460ff178c..f4da37d6633 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -2,7 +2,6 @@ @inject IOptionsMonitor WebsiteOption @inject IStringLocalizer Localizer @inject ToastService ToastService -@implements IDisposable

@Localizer["UploadsTitle"]

diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs index e641cc263b3..2440fccaaf1 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs @@ -10,7 +10,7 @@ namespace BootstrapBlazor.Server.Components.Samples; /// /// Uploads /// -public sealed partial class Uploads +public sealed partial class Uploads : IDisposable { [NotNull] private ConsoleLogger? Logger1 { get; set; } @@ -18,7 +18,7 @@ public sealed partial class Uploads [NotNull] private ConsoleLogger? Logger2 { get; set; } - private static readonly Random random = new(); + private static readonly Random Random = new(); private CancellationTokenSource? ReadToken { get; set; } @@ -34,21 +34,21 @@ public sealed partial class Uploads private List DefaultFormatFileList { get; } = [ - new UploadFile { FileName = "Test.xls" }, - new UploadFile { FileName = "Test.doc" }, - new UploadFile { FileName = "Test.ppt" }, - new UploadFile { FileName = "Test.mp3" }, - new UploadFile { FileName = "Test.mp4" }, - new UploadFile { FileName = "Test.pdf" }, - new UploadFile { FileName = "Test.cs" }, - new UploadFile { FileName = "Test.zip" }, - new UploadFile { FileName = "Test.txt" }, - new UploadFile { FileName = "Test.dat" } + new() { FileName = "Test.xls" }, + new() { FileName = "Test.doc" }, + new() { FileName = "Test.ppt" }, + new() { FileName = "Test.mp3" }, + new() { FileName = "Test.mp4" }, + new() { FileName = "Test.pdf" }, + new() { FileName = "Test.cs" }, + new() { FileName = "Test.zip" }, + new() { FileName = "Test.txt" }, + new() { FileName = "Test.dat" } ]; private List Base64FormatFileList { get; } = [ - new UploadFile { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" }, + new() { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" }, ]; /// @@ -58,10 +58,10 @@ protected override void OnInitialized() { base.OnInitialized(); - PreviewFileList.AddRange(new[] - { + PreviewFileList.AddRange( + [ new UploadFile { PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/Argo.png" } - }); + ]); } private Task OnFileChange(UploadFile file) @@ -88,7 +88,7 @@ private static Task OnSubmit(EditContext context) private async Task OnClickToUpload(UploadFile file) { // 示例代码,模拟 80% 几率保存成功 - var error = random.Next(1, 100) > 80; + var error = Random.Next(1, 100) > 80; if (error) { file.Code = 1; @@ -105,12 +105,11 @@ private async Task OnClickToUploadNoUploadList(UploadFile file) await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success."); } - private async Task SaveToFile(UploadFile file) + private async Task SaveToFile(UploadFile file) { // Server Side 使用 // Web Assembly 模式下必须使用 WebApi 方式去保存文件到服务器或者数据库中 // 生成写入文件名称 - var ret = false; if (!string.IsNullOrEmpty(WebsiteOption.CurrentValue.WebRootPath)) { var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader"); @@ -118,7 +117,7 @@ private async Task SaveToFile(UploadFile file) var fileName = Path.Combine(uploaderFolder, file.FileName); ReadToken ??= new CancellationTokenSource(); - ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token); + var ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token); if (ret) { @@ -139,7 +138,6 @@ private async Task SaveToFile(UploadFile file) file.Error = Localizer["UploadsWasmError"]; await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]); } - return ret; } private async Task OnDownload(UploadFile item) @@ -156,7 +154,7 @@ private async Task OnUploadFolder(UploadFile file) private async Task OnAvatarUpload(UploadFile file) { // 示例代码,使用 base64 格式 - if (file != null && file.File != null) + if (file is { File: not null }) { var format = file.File.ContentType; if (CheckValidAvatarFormat(format)) @@ -196,7 +194,7 @@ private Task OnAvatarValidSubmit(EditContext context) private async Task OnCardUpload(UploadFile file) { - if (file != null && file.File != null) + if (file is { File: not null }) { // 服务器端验证当文件大于 5MB 时提示文件太大信息 if (file.Size > MaxFileLength) From 4a511c5a38aefc5cf2b677456bebc1c40aea9bd1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:34:53 +0800 Subject: [PATCH 025/177] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20GC=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs index 2440fccaaf1..6aca17dd830 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs @@ -217,7 +217,6 @@ public void Dispose() { ReadToken?.Cancel(); ReadAvatarToken?.Cancel(); - GC.SuppressFinalize(this); } private List GetInputAttributes() => From 856c7dda75814de7e78a61a71649cf36c9ce6cd9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:35:07 +0800 Subject: [PATCH 026/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Locales/en-US.json | 2 +- src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 5309ecaa925..64e65d3f653 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3488,7 +3488,7 @@ "UploadFileIconTemplateTitle": "Custom file icon", "UploadFileIconTemplateIntro": "By setting the IconTemplate parameter and using the FileIcon component, you can further customize the file icon [FileIcon example]", "UploadBase64Title": "Base64 format", - "UploadBase64Intro": "use data:image/xxx;base64,xxx format data string as PrevUrl value", + "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", "UploadsShowDeleteButton": "Whether to display the Delete button", "UploadsShowDownloadButton": "Whether to display the Download button", "UploadsIsDisabled": "Whether to disable it", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 0e66d1bb0b3..c3b4850fb3c 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3488,7 +3488,7 @@ "UploadFileIconTemplateTitle": "自定义文件图标", "UploadFileIconTemplateIntro": "通过设置 IconTemplate 参数,使用 FileIcon 组件可以对文件图标进行进一步自定义 [FileIcon 示例]", "UploadBase64Title": "Base64 格式文件", - "UploadBase64Intro": "使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", + "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", "UploadsShowDeleteButton": "是否显示删除按钮", "UploadsShowDownloadButton": "是否显示下载按钮", "UploadsIsDisabled": "是否禁用", From a080026af034c03ea57947c891a9fcae8e01c46c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:39:45 +0800 Subject: [PATCH 027/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs index 6aca17dd830..e59c8cf39a9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs @@ -211,12 +211,13 @@ private async Task OnCardUpload(UploadFile file) } /// - /// Dispose + /// /// public void Dispose() { ReadToken?.Cancel(); ReadAvatarToken?.Cancel(); + GC.SuppressFinalize(this); } private List GetInputAttributes() => From 22994a1e7557739d3a6b869ae1c5838ecd9f9f26 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:53:36 +0800 Subject: [PATCH 028/177] =?UTF-8?q?style:=20=E6=9B=B4=E6=96=B0=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 581315c23b3..67c868adc19 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -321,7 +321,7 @@ } .upload-drop-text { - margin-top: 1rem; + margin-block-start: 1rem; } em { @@ -332,7 +332,7 @@ .upload-drop-footer { font-size: var(--bb-upload-drop-footer-font-size); - margin-top: var(--bb-upload-drop-footer-margin-top); + margin-block-start: var(--bb-upload-drop-footer-margin-top); } .upload-drop-list { From daed39dc748b92736f7d1a9baba0f1c632c3bcc2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:53:50 +0800 Subject: [PATCH 029/177] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=B8=8A=E4=BC=A0=E5=88=97=E8=A1=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/DropUpload.razor | 29 ++++++++++--------- .../Components/Upload/DropUpload.razor.cs | 6 ++++ .../Components/Upload/UploadBase.cs | 22 +++----------- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 84a2532e49d..a2a0b529aab 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -48,20 +48,23 @@ }
} -
    - @foreach (var item in GetUploadFiles()) - { - @if (GetShowProgress(item)) + @if (ShowUploadFileList) + { +
      + @foreach (var item in GetUploadFiles()) { -
    • -
      - @item.GetFileName() - (@item.Size.ToFileSizeString()) -
      - -
    • + @if (GetShowProgress(item)) + { +
    • +
      + @item.GetFileName() + (@item.Size.ToFileSizeString()) +
      + +
    • + } } - } -
    +
+ }
diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 9a79d0c19c3..a8bc16041c6 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -63,6 +63,12 @@ public partial class DropUpload [NotNull] public string? FooterText { get; set; } + /// + /// 获得/设置 是否显示上传列表 默认 true + /// + [Parameter] + public bool ShowUploadFileList { get; set; } = true; + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index b9059c50023..582ef388f53 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -291,28 +291,14 @@ protected virtual bool CheckCanUpload() /// 获得当前图片集合 ///
/// - protected virtual List GetUploadFiles() + protected List GetUploadFiles() { var ret = new List(); - if (IsMultiple) - { - if (DefaultFileList != null) - { - ret.AddRange(DefaultFileList); - } - ret.AddRange(UploadFiles); - } - else + if (DefaultFileList != null) { - if (DefaultFileList != null && DefaultFileList.Count != 0) - { - ret.Add(DefaultFileList.First()); - } - if (ret.Count == 0 && UploadFiles.Count != 0) - { - ret.Add(UploadFiles.First()); - } + ret.AddRange(DefaultFileList); } + ret.AddRange(UploadFiles); return ret; } From 7c14a9271c0a5ce2792fd65cce02d426781d5672 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:54:09 +0800 Subject: [PATCH 030/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor | 3 ++- src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index f4da37d6633..06ca0106ecb 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -187,7 +187,8 @@ - + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs index e59c8cf39a9..0f2772e4fe1 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs @@ -206,6 +206,7 @@ private async Task OnCardUpload(UploadFile file) else { await SaveToFile(file); + await ToastService.Success(Localizer["UploadsFileMsg"], $"{file.File!.Name} {Localizer["UploadsSuccess"]}"); } } } From 47ea5608a5e58941eb87e319ae551fd0a7be4840 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 11:58:47 +0800 Subject: [PATCH 031/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 582ef388f53..25bd9197588 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -244,7 +244,7 @@ protected virtual IDictionary GetUploadAdditionalAttributes() } if (IsDirectory) { - ret.Add("directory", "dicrectory"); + ret.Add("directory", "directory"); ret.Add("webkitdirectory", "webkitdirectory"); } return ret; From 9819e7b7242c0e4f33e613e9abb74001966d0591 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 12:21:54 +0800 Subject: [PATCH 032/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 33 +--- .../Components/Upload/UploadBase.cs | 175 +++++++++--------- 2 files changed, 91 insertions(+), 117 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 11b19603ea8..e0f93d40c60 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -115,6 +115,13 @@ protected override void OnParametersSet() AddIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadAddIcon); ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadValidStatusIcon); InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadInvalidStatusIcon); + + // 头像上传时如果用户没有设置 OnChanged 回调,需要使用内置方法将文件头像转化未 Base64 格式用于预览 + OnChange ??= new Func(async item => + { + item.ValidateId = $"{Id}_{item.GetHashCode()}"; + await item.RequestBase64ImageFileAsync(); + }); } /// @@ -124,7 +131,7 @@ protected override void OnParametersSet() protected override bool CheckCanUpload() { // 允许多上传 - if(IsMultiple == true) + if (IsMultiple == true) { return true; } @@ -132,28 +139,4 @@ protected override bool CheckCanUpload() // 只允许单个上传 return UploadFiles.Count == 0; } - - /// - /// - /// - /// - protected override async Task OnFileUpload(List items) - { - await base.OnFileUpload(items); - - foreach (var item in items) - { - item.ValidateId = $"{Id}_{item.GetHashCode()}"; - if (OnChange != null) - { - await item.RequestBase64ImageFileAsync(); - } - } - } - - /// - /// - /// - /// - //protected override string? RetrieveId() => _currentFile?.ValidateId; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 25bd9197588..089c6157c0c 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -42,18 +42,11 @@ public abstract class UploadBase : ValidateBase, IUpload public Func, Task>? OnAllFileUploaded { get; set; } /// - /// 获得/设置 已上传文件集合 + /// 获得/设置 已上传文件集合,可用于组件初始化 /// [Parameter] public List? DefaultFileList { get; set; } - /// - /// 获得/设置 上传文件集合 - /// - protected List UploadFiles { get; } = []; - - List IUpload.UploadFiles { get => UploadFiles; } - /// /// 获得/设置 是否显示上传进度 默认为 false /// @@ -91,52 +84,24 @@ public abstract class UploadBase : ValidateBase, IUpload public Func>? OnDelete { get; set; } /// - /// 获得/设置 点击浏览按钮时回调此方法 默认 null + /// 获得/设置 点击浏览按钮时回调此方法,如果多文件上传此回调会触发多次 默认 null /// [Parameter] public Func? OnChange { get; set; } /// - /// 显示/隐藏验证结果方法 + /// 获得/设置 已上传文件集合,此集合中数据是用户上传文件集合 /// - /// - public override void ToggleMessage(IEnumerable results) - { - if (FieldIdentifier != null) - { - var messages = results.Where(item => item.MemberNames.Any(m => UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false))); - if (messages.Any()) - { - IsValid = false; - - // TODO: 提示 - //if (CurrentFile != null) - //{ - // var msg = messages.FirstOrDefault(m => m.MemberNames.Any(f => f.Equals(CurrentFile.ValidateId, StringComparison.OrdinalIgnoreCase))); - // if (msg != null) - // { - // ErrorMessage = msg.ErrorMessage; - // } - //} - } - else - { - ErrorMessage = null; - IsValid = true; - } - OnValidate(IsValid); - } - } + public List UploadFiles { get; } = []; /// /// /// /// /// - protected virtual async Task OnFileChange(InputFileChangeEventArgs args) + protected async Task OnFileChange(InputFileChangeEventArgs args) { - // TODO: 超过文件个数限制时需要提示 - // init UploadFiles + UploadFiles.Clear(); var fileCount = MaxFileCount ?? args.FileCount; var items = args.GetMultipleFiles(fileCount).Select(f => new UploadFile() { @@ -148,14 +113,17 @@ protected virtual async Task OnFileChange(InputFileChangeEventArgs args) UpdateCallback = Update }).ToList(); - // trigger OnChange event callback - if (OnChange != null) + foreach (var item in items) { - foreach (var item in items) + UploadFiles.Add(item); + + // trigger OnChange event callback + // 回调给用户,用于存储文件并生成预览地址给 PreUrl + if (OnChange != null) { await OnChange(item); - item.Uploaded = true; } + item.Uploaded = true; StateHasChanged(); } @@ -166,31 +134,22 @@ protected virtual async Task OnFileChange(InputFileChangeEventArgs args) } var type = NullableUnderlyingType ?? typeof(TValue); - if (type.IsAssignableTo(typeof(IBrowserFile))) + if (type.IsAssignableTo(typeof(IEnumerable))) { - CurrentValue = default; + CurrentValue = (TValue)(object)items.Select(f => f.File).ToList(); } - else if (type.IsAssignableTo(typeof(IEnumerable))) + else if (type.IsAssignableTo(typeof(IEnumerable))) { - CurrentValue = (TValue)(object)items.Select(f => f.File).ToList(); + CurrentValue = (TValue)(object)string.Join(";", items.Select(f => f.OriginFileName)).ToList(); + } + else if (type == typeof(IBrowserFile)) + { + CurrentValue = (TValue)(object)items[0].File!; } else if (type == typeof(string)) { CurrentValue = (TValue)(object)string.Join(";", items.Select(f => f.OriginFileName)); } - - await OnFileUpload(items); - } - - /// - /// 文件上传回调方法用于组件处理自定义逻辑 - /// - /// - /// - protected virtual Task OnFileUpload(List items) - { - UploadFiles.AddRange(items); - return Task.CompletedTask; } /// @@ -220,36 +179,6 @@ protected virtual async Task OnFileDelete(UploadFile item) } - /// - /// append html attribute method. - /// - /// - protected virtual IDictionary GetUploadAdditionalAttributes() - { - var ret = new Dictionary - { - { "hidden", "hidden" } - }; - if (!string.IsNullOrEmpty(Accept)) - { - ret.Add("accept", Accept); - } - if (!string.IsNullOrEmpty(Capture)) - { - ret.Add("capture", Capture); - } - if (IsMultiple) - { - ret.Add("multiple", "multiple"); - } - if (IsDirectory) - { - ret.Add("directory", "directory"); - ret.Add("webkitdirectory", "webkitdirectory"); - } - return ret; - } - /// /// 是否显示进度条方法 /// @@ -311,4 +240,66 @@ public virtual void Reset() UploadFiles.Clear(); StateHasChanged(); } + + /// + /// 显示/隐藏验证结果方法 + /// + /// + public override void ToggleMessage(IEnumerable results) + { + if (FieldIdentifier != null) + { + var messages = results.Where(item => item.MemberNames.Any(m => UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false))); + if (messages.Any()) + { + IsValid = false; + + // TODO: 提示 + //if (CurrentFile != null) + //{ + // var msg = messages.FirstOrDefault(m => m.MemberNames.Any(f => f.Equals(CurrentFile.ValidateId, StringComparison.OrdinalIgnoreCase))); + // if (msg != null) + // { + // ErrorMessage = msg.ErrorMessage; + // } + //} + } + else + { + ErrorMessage = null; + IsValid = true; + } + OnValidate(IsValid); + } + } + + /// + /// append html attribute method. + /// + /// + protected IDictionary GetUploadAdditionalAttributes() + { + var ret = new Dictionary + { + { "hidden", "hidden" } + }; + if (!string.IsNullOrEmpty(Accept)) + { + ret.Add("accept", Accept); + } + if (!string.IsNullOrEmpty(Capture)) + { + ret.Add("capture", Capture); + } + if (IsMultiple) + { + ret.Add("multiple", "multiple"); + } + if (IsDirectory) + { + ret.Add("directory", "directory"); + ret.Add("webkitdirectory", "webkitdirectory"); + } + return ret; + } } From 4eaa8cc9d3b2ada9ae34992c9cd05ec3c56337db Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 12:24:24 +0800 Subject: [PATCH 033/177] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 2 -- src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss | 1 - 2 files changed, 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 67c868adc19..9fe8431c2df 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -9,7 +9,6 @@ --bb-upload-card-height: #{$bb-upload-card-height}; --bb-upload-card-shadow: #{$bb-upload-card-shadow}; --bb-upload-card-padding: #{$bb-upload-card-padding}; - --bb-upload-card-margin: #{$bb-upload-card-margin}; --bb-upload-card-item-width: #{$bb-upload-card-item-width}; --bb-upload-drop-height: #{$bb-upload-drop-height}; --bb-upload-drop-footer-font-size: #{$bb-upload-drop-footer-font-size}; @@ -183,7 +182,6 @@ height: var(--bb-upload-card-height); position: relative; cursor: pointer; - margin: var(--bb-upload-card-margin); overflow: hidden; } diff --git a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss index 949ca5445b0..f936c39522f 100644 --- a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss +++ b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss @@ -698,7 +698,6 @@ $bb-upload-card-width: 240px; $bb-upload-card-height: 280px; $bb-upload-card-shadow: 0 0 10px 0 rgba(0,0,0,.2); $bb-upload-card-padding: 1rem; -$bb-upload-card-margin: 0 1rem 1rem 0; $bb-upload-card-item-width: 168px; $bb-upload-drop-height: 140px; $bb-upload-drop-footer-font-size: 12px; From ef86ee2749846a68eac5ded38b21da8803116083 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 12:44:46 +0800 Subject: [PATCH 034/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20DropUp?= =?UTF-8?q?load=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/DropUpload.razor | 18 ------------------ .../Components/Upload/DropUpload.razor.cs | 6 ------ .../Components/Upload/UploadFile.cs | 4 ++-- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index a2a0b529aab..1b5665e8b88 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -48,23 +48,5 @@ }
} - @if (ShowUploadFileList) - { -
    - @foreach (var item in GetUploadFiles()) - { - @if (GetShowProgress(item)) - { -
  • -
    - @item.GetFileName() - (@item.Size.ToFileSizeString()) -
    - -
  • - } - } -
- }
diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index a8bc16041c6..9a79d0c19c3 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -63,12 +63,6 @@ public partial class DropUpload [NotNull] public string? FooterText { get; set; } - /// - /// 获得/设置 是否显示上传列表 默认 true - /// - [Parameter] - public bool ShowUploadFileList { get; set; } = true; - [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index ee9c2763e08..1d0ba2a29eb 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -13,7 +13,7 @@ namespace BootstrapBlazor.Components; public class UploadFile { /// - /// 获得/设置 文件名 + /// 获得/设置 文件名 由用户指定 上传文件时此参数未设置 默认为 null /// public string? FileName { get; set; } @@ -81,7 +81,7 @@ public class UploadFile /// 获得 UploadFile 文件名 ///
/// - public string? GetFileName() => OriginFileName ?? FileName; + public string? GetFileName() => FileName ?? OriginFileName; /// /// 获得 UploadFile 文件扩展名 From 5a622049b7f2a48541d4f3715f78f06bd9644fb2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 12:47:24 +0800 Subject: [PATCH 035/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Uploads.razor | 39 ++++++++++++------- .../Components/Samples/Uploads.razor.cs | 8 ++++ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor index 06ca0106ecb..1cf51bd6861 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor @@ -21,7 +21,7 @@ OnChange="@OnFileChange" OnDelete="@OnFileDelete"> - +
- +
- +
@@ -64,8 +64,9 @@

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

+ ShowUploadFileList="false" BrowserButtonText="Upload" + BrowserButtonIcon="fa-solid fa-cloud-arrow-up" + OnChange="@OnClickToUploadNoUploadList">
@@ -122,7 +123,7 @@
- +
@@ -134,7 +135,7 @@
- + - + - + - + @@ -187,12 +190,18 @@ - + +
+ @foreach (var file in _dropFiles) + { +
@file.GetFileName()
+ } +
- + - + - + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs index 0f2772e4fe1..1d275f249e4 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs @@ -211,6 +211,14 @@ private async Task OnCardUpload(UploadFile file) } } + private readonly List _dropFiles = []; + private Task OnDropUpload(UploadFile file) + { + _dropFiles.Add(file); + StateHasChanged(); + return Task.CompletedTask; + } + /// /// /// From 0a2cacd2aa02e77ef0562ca83bf20ff9065db3f4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 12:49:55 +0800 Subject: [PATCH 036/177] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E5=AD=97?= =?UTF-8?q?=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exclusion.dic | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exclusion.dic b/exclusion.dic index d639525ab3d..fee70b79c99 100644 --- a/exclusion.dic +++ b/exclusion.dic @@ -114,3 +114,5 @@ inputmode Totp otpauth Hotp +univer +rdkit From 1ad8b5eec6ebf425f46c1a1627cc0c4414d26b11 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 14:06:13 +0800 Subject: [PATCH 037/177] =?UTF-8?q?doc:=20=E6=8B=86=E5=88=86=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 60 +++ .../Components/Samples/UploadAvatars.razor.cs | 170 ++++++ .../Components/Samples/UploadButtons.razor | 59 +++ .../Components/Samples/UploadButtons.razor.cs | 214 ++++++++ .../Components/Samples/UploadCards.razor | 65 +++ .../Components/Samples/UploadCards.razor.cs | 59 +++ .../Components/Samples/UploadDrops.razor | 25 + .../Components/Samples/UploadDrops.razor.cs | 26 + .../Components/Samples/UploadInputs.razor | 50 ++ .../Components/Samples/UploadInputs.razor.cs | 151 ++++++ .../Components/Samples/Uploads.razor | 207 -------- .../Components/Samples/Uploads.razor.cs | 499 ------------------ 12 files changed, 879 insertions(+), 706 deletions(-) create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor create mode 100644 src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs delete mode 100644 src/BootstrapBlazor.Server/Components/Samples/Uploads.razor delete mode 100644 src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor new file mode 100644 index 00000000000..46d7dddb8b0 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -0,0 +1,60 @@ +@page "/upload-avatar" +@inject IOptionsMonitor WebsiteOption +@inject IStringLocalizer Localizer +@inject ToastService ToastService + +

@Localizer["UploadsTitle"]

+ +

@Localizer["UploadsSubTitle"]

+ +

@((MarkupString)Localizer["UploadsNote"].Value)

+ +
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+ + +
+
+

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

+ +
+
+

@Localizer["AvatarUploadTips2"]

+ +
+
+

@((MarkupString)Localizer["AvatarUploadTips3"].Value)

+ +

@((MarkupString)Localizer["AvatarUploadTips5"].Value)

+ +
+
+

@((MarkupString)Localizer["AvatarUploadTips6"].Value)

+ +
+
+

@((MarkupString)Localizer["AvatarUploadTips7"].Value)

+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs new file mode 100644 index 00000000000..d86069f036b --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; + +namespace BootstrapBlazor.Server.Components.Samples; + +/// +/// AvatarUpload sample code +/// +public partial class UploadAvatars : IDisposable +{ + private CancellationTokenSource? ReadAvatarToken { get; set; } + + private static long MaxFileLength => 5 * 1024 * 1024; + + private List PreviewFileList { get; } = []; + + private Person Foo2 { get; set; } = new Person(); + + [NotNull] + private ConsoleLogger? Logger2 { get; set; } + + /// + /// + /// + protected override void OnInitialized() + { + base.OnInitialized(); + + PreviewFileList.AddRange( + [ + new UploadFile { PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/Argo.png" } + ]); + } + + private async Task OnAvatarUpload(UploadFile file) + { + // 示例代码,使用 base64 格式 + if (file is { File: not null }) + { + var format = file.File.ContentType; + if (file.IsImage()) + { + ReadAvatarToken ??= new CancellationTokenSource(); + if (ReadAvatarToken.IsCancellationRequested) + { + ReadAvatarToken.Dispose(); + ReadAvatarToken = new CancellationTokenSource(); + } + + await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token); + } + else + { + file.Code = 1; + file.Error = Localizer["UploadsFormatError"]; + } + + if (file.Code != 0) + { + await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}"); + } + } + } + + private Task OnAvatarValidSubmit(EditContext context) + { + Logger2.Log(Foo2.Picture?.Name ?? ""); + return Task.CompletedTask; + } + + /// + /// + /// + public void Dispose() + { + ReadAvatarToken?.Cancel(); + GC.SuppressFinalize(this); + } + + private List GetAttributes() => + [ + new() + { + Name = "Width", + Description = Localizer["UploadsWidth"], + Type = "int", + ValueList = " — ", + DefaultValue = "0" + }, + new() + { + Name = "Height", + Description = Localizer["UploadsHeight"], + Type = "int", + ValueList = "—", + DefaultValue = "0" + }, + new() + { + Name = "IsCircle", + Description = Localizer["UploadsIsCircle"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsSingle", + Description = Localizer["UploadsIsSingle"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "ShowProgress", + Description = Localizer["UploadsShowProgress"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "Accept", + Description = Localizer["UploadsAccept"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "DefaultFileList", + Description = Localizer["UploadsDefaultFileList"], + Type = "List", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnDelete", + Description = Localizer["UploadsOnDelete"], + Type = "Func>", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnChange", + Description = Localizer["UploadsOnChange"], + Type = "Func", + ValueList = " — ", + DefaultValue = " — " + } + ]; + + class Person + { + [Required] + [StringLength(20, MinimumLength = 2)] + public string Name { get; set; } = "Blazor"; + + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 5 * 1024 * 1024)] + public IBrowserFile? Picture { get; set; } + } +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor new file mode 100644 index 00000000000..f6b7e2bf5a8 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -0,0 +1,59 @@ +@page "/upload-button" +@inject IOptionsMonitor WebsiteOption +@inject IStringLocalizer Localizer +@inject ToastService ToastService + +

@Localizer["UploadsTitle"]

+ +

@Localizer["UploadsSubTitle"]

+ +

@((MarkupString)Localizer["UploadsNote"].Value)

+ +
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+ + +
+
+

@((MarkupString)Localizer["UploadClickUploadTips1"].Value)

+ +
+
+

@((MarkupString)Localizer["UploadClickUploadTips2"].Value)

+ +
+
+

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

+ +
+
+
+ + +
+
+ +
+
+
+ + +
+
+ +
+
+
+ + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs new file mode 100644 index 00000000000..1dca21363d4 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Server.Components.Samples; + +/// +/// ButtonUpload sample code +/// +public partial class UploadButtons +{ + private static readonly Random Random = new(); + private CancellationTokenSource? ReadToken { get; set; } + private static long MaxFileLength => 5 * 1024 * 1024; + + private List DefaultFormatFileList { get; } = + [ + new() { FileName = "Test.xls" }, + new() { FileName = "Test.doc" }, + new() { FileName = "Test.ppt" }, + new() { FileName = "Test.mp3" }, + new() { FileName = "Test.mp4" }, + new() { FileName = "Test.pdf" }, + new() { FileName = "Test.cs" }, + new() { FileName = "Test.zip" }, + new() { FileName = "Test.txt" }, + new() { FileName = "Test.dat" } + ]; + + private async Task OnClickToUpload(UploadFile file) + { + // 示例代码,模拟 80% 几率保存成功 + var error = Random.Next(1, 100) > 80; + if (error) + { + file.Code = 1; + file.Error = Localizer["UploadsError"]; + } + else + { + await SaveToFile(file); + } + } + + private async Task OnClickToUploadNoUploadList(UploadFile file) + { + await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success."); + } + + private async Task OnUploadFolder(UploadFile file) + { + // 上传文件夹时会多次回调此方法 + await SaveToFile(file); + } + + private async Task OnDownload(UploadFile item) + { + await ToastService.Success("文件下载", $"下载 {item.FileName} 成功"); + } + + private async Task SaveToFile(UploadFile file) + { + // Server Side 使用 + // Web Assembly 模式下必须使用 WebApi 方式去保存文件到服务器或者数据库中 + // 生成写入文件名称 + if (!string.IsNullOrEmpty(WebsiteOption.CurrentValue.WebRootPath)) + { + var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, + $"images{Path.DirectorySeparatorChar}uploader"); + file.FileName = + $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; + var fileName = Path.Combine(uploaderFolder, file.FileName); + + ReadToken ??= new CancellationTokenSource(); + var ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token); + + if (ret) + { + // 保存成功 + file.PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/uploader/{file.FileName}"; + } + else + { + var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}"; + file.Code = 1; + file.Error = errorMessage; + await ToastService.Error(Localizer["UploadFile"], errorMessage); + } + } + else + { + file.Code = 1; + file.Error = Localizer["UploadsWasmError"]; + await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]); + } + } + + private List GetAttributes() => + [ + new() + { + Name = "IsDirectory", + Description = Localizer["UploadsIsDirectory"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsMultiple", + Description = Localizer["UploadsIsMultiple"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsSingle", + Description = Localizer["UploadsIsSingle"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "ShowProgress", + Description = Localizer["UploadsShowProgress"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "Accept", + Description = Localizer["UploadsAccept"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "BrowserButtonClass", + Description = Localizer["UploadsBrowserButtonClass"], + Type = "string", + ValueList = " — ", + DefaultValue = "btn-primary" + }, + new() + { + Name = "BrowserButtonIcon", + Description = Localizer["UploadsBrowserButtonIcon"], + Type = "string", + ValueList = " — ", + DefaultValue = "fa-regular fa-folder-open" + }, + new() + { + Name = "BrowserButtonText", + Description = Localizer["UploadsBrowserButtonText"], + Type = "string", + ValueList = " — ", + DefaultValue = "" + }, + new() + { + Name = "DefaultFileList", + Description = Localizer["UploadsDefaultFileList"], + Type = "List", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnGetFileFormat", + Description = Localizer["UploadsOnGetFileFormat"], + Type = "Func", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnDelete", + Description = Localizer["UploadsOnDelete"], + Type = "Func>", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnChange", + Description = Localizer["UploadsOnChange"], + Type = "Func", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnDownload", + Description = Localizer["UploadsOnDownload"], + Type = "Func", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "IconTemplate", + Description = Localizer["UploadsIconTemplate"], + Type = "RenderFragment", + ValueList = " — ", + DefaultValue = " — " + } + ]; +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor new file mode 100644 index 00000000000..bc26cba0db3 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -0,0 +1,65 @@ +@page "/upload-card" +@inject IOptionsMonitor WebsiteOption +@inject IStringLocalizer Localizer +@inject ToastService ToastService + +

@Localizer["UploadsTitle"]

+ +

@Localizer["UploadsSubTitle"]

+ +

@((MarkupString)Localizer["UploadsNote"].Value)

+ +
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+ + +
+
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
+
+
+
+

@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)

+ +
+
+

@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs new file mode 100644 index 00000000000..e4021f55f7c --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Server.Components.Samples; + +/// +/// CardUpload sample code +/// +public partial class UploadCards +{ + private List DefaultFormatFileList { get; } = + [ + new() { FileName = "Test.xls" }, + new() { FileName = "Test.doc" }, + new() { FileName = "Test.ppt" }, + new() { FileName = "Test.mp3" }, + new() { FileName = "Test.mp4" }, + new() { FileName = "Test.pdf" }, + new() { FileName = "Test.cs" }, + new() { FileName = "Test.zip" }, + new() { FileName = "Test.txt" }, + new() { FileName = "Test.dat" } + ]; + + private List Base64FormatFileList { get; } = + [ + new() { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" }, + ]; + + private static long MaxFileLength => 5 * 1024 * 1024; + + private async Task OnCardUpload(UploadFile file) + { + if (file is { File: not null }) + { + // 服务器端验证当文件大于 5MB 时提示文件太大信息 + if (file.Size > MaxFileLength) + { + await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]); + file.Code = 1; + file.Error = Localizer["UploadsFileError"]; + } + else + { + // 模拟保存成功 + await Task.Delay(100); + //await SaveToFile(file); + await ToastService.Success(Localizer["UploadsFileMsg"], $"{file.File!.Name} {Localizer["UploadsSuccess"]}"); + } + } + } + + private List GetAttributes() => + [ + + ]; +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor new file mode 100644 index 00000000000..41cec2e04d6 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor @@ -0,0 +1,25 @@ +@page "/upload-drop" +@inject IOptionsMonitor WebsiteOption +@inject IStringLocalizer Localizer +@inject ToastService ToastService + +

@Localizer["UploadsTitle"]

+ +

@Localizer["UploadsSubTitle"]

+ +

@((MarkupString)Localizer["UploadsNote"].Value)

+ +
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+ + + +
+ @foreach (var file in _dropFiles) + { +
@file.GetFileName()
+ } +
+
+ + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs new file mode 100644 index 00000000000..db3a67c4829 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Server.Components.Samples; + +/// +/// DropUpload sampel code +/// +public partial class UploadDrops +{ + private readonly List _dropFiles = []; + + private Task OnDropUpload(UploadFile file) + { + _dropFiles.Add(file); + StateHasChanged(); + return Task.CompletedTask; + } + + private List GetAttributes() => + [ + + ]; +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor new file mode 100644 index 00000000000..8631d8409c7 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor @@ -0,0 +1,50 @@ +@page "/upload-input" +@inject IOptionsMonitor WebsiteOption +@inject IStringLocalizer Localizer +@inject ToastService ToastService + +

@Localizer["UploadsTitle"]

+ +

@Localizer["UploadsSubTitle"]

+ +

@((MarkupString)Localizer["UploadsNote"].Value)

+ +
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+ + +
+
+ +
+
+ +
+ +
+
    +
  • @((MarkupString)Localizer["UploadFormSettingsLi1"].Value)
  • +
  • @((MarkupString)Localizer["UploadFormSettingsLi2"].Value)
  • +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs new file mode 100644 index 00000000000..c041421ccc7 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; + +namespace BootstrapBlazor.Server.Components.Samples; + +/// +/// InputUpload sample code +/// +public partial class UploadInputs +{ + [NotNull] + private ConsoleLogger? Logger1 { get; set; } + + private Person Foo1 { get; set; } = new Person(); + + private Task OnFileChange(UploadFile file) + { + // 未真正保存文件 + // file.SaveToFile() + Logger1.Log($"{file.File!.Name} {Localizer["UploadsSuccess"]}"); + return Task.CompletedTask; + } + + private Task OnFileDelete(UploadFile item) + { + Logger1.Log($"{item.OriginFileName} {Localizer["UploadsRemoveMsg"]}"); + return Task.FromResult(true); + } + + private static Task OnSubmit(EditContext context) + { + // 示例代码请根据业务情况自行更改 + // var fileName = Foo.Picture?.Name; + return Task.CompletedTask; + } + + private List GetAttributes() => + [ + new() + { + Name = "ShowDeleteButton", + Description = Localizer["UploadsShowDeleteButton"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsDisabled", + Description = Localizer["UploadsIsDisabled"], + Type = "boolean", + ValueList = "true / false", + DefaultValue = "false" + }, + new() + { + Name = "PlaceHolder", + Description = Localizer["UploadsPlaceHolder"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "Accept", + Description = Localizer["UploadsAccept"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "BrowserButtonClass", + Description = Localizer["UploadsBrowserButtonClass"], + Type = "string", + ValueList = " — ", + DefaultValue = "btn-primary" + }, + new() + { + Name = "BrowserButtonIcon", + Description = Localizer["UploadsBrowserButtonIcon"], + Type = "string", + ValueList = " — ", + DefaultValue = "fa-regular fa-folder-open" + }, + new() + { + Name = "BrowserButtonText", + Description = Localizer["UploadsBrowserButtonText"], + Type = "string", + ValueList = " — ", + DefaultValue = "" + }, + new() + { + Name = "DeleteButtonClass", + Description = Localizer["UploadsDeleteButtonClass"], + Type = "string", + ValueList = " — ", + DefaultValue = "btn-danger" + }, + new() + { + Name = "DeleteButtonIcon", + Description = Localizer["UploadsDeleteButtonIcon"], + Type = "string", + ValueList = " — ", + DefaultValue = "fa-regular fa-trash" + }, + new() + { + Name = "DeleteButtonText", + Description = Localizer["UploadsDeleteButtonText"], + Type = "string", + ValueList = " — ", + DefaultValue = Localizer["UploadsDeleteButtonTextDefaultValue"] + }, + new() + { + Name = "OnDelete", + Description = Localizer["UploadsOnDelete"], + Type = "Func>", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "OnChange", + Description = Localizer["UploadsOnChange"], + Type = "Func", + ValueList = " — ", + DefaultValue = " — " + } + ]; + + class Person + { + [Required] + [StringLength(20, MinimumLength = 2)] + public string Name { get; set; } = "Blazor"; + + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 5 * 1024 * 1024)] + public IBrowserFile? Picture { get; set; } + } +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor deleted file mode 100644 index 1cf51bd6861..00000000000 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor +++ /dev/null @@ -1,207 +0,0 @@ -@page "/upload" -@inject IOptionsMonitor WebsiteOption -@inject IStringLocalizer Localizer -@inject ToastService ToastService - -

@Localizer["UploadsTitle"]

- -

@Localizer["UploadsSubTitle"]

- -

@((MarkupString)Localizer["UploadsNote"].Value)

- -
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
- - -
-
- -
-
- -
- -
-
    -
  • @((MarkupString)Localizer["UploadFormSettingsLi1"].Value)
  • -
  • @((MarkupString)Localizer["UploadFormSettingsLi2"].Value)
  • -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
-
-

@((MarkupString)Localizer["UploadClickUploadTips1"].Value)

- -
-
-

@((MarkupString)Localizer["UploadClickUploadTips2"].Value)

- -
-
-

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

- -
-
-
- - -
-
- -
-
-
- - -
-
- -
-
-
- - -
-
-

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

- -
-
-

@Localizer["AvatarUploadTips2"]

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips3"].Value)

- -

@((MarkupString)Localizer["AvatarUploadTips5"].Value)

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips6"].Value)

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips7"].Value)

- -
-
- -
-
- -
-
- -
-
-
-
-
- -
- - -
-
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
-
-
-
-

@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)

- -
-
-

@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - -
- @foreach (var file in _dropFiles) - { -
@file.GetFileName()
- } -
-
- - - - - - diff --git a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs deleted file mode 100644 index 1d275f249e4..00000000000 --- a/src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs +++ /dev/null @@ -1,499 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.AspNetCore.Components.Forms; - -namespace BootstrapBlazor.Server.Components.Samples; - -/// -/// Uploads -/// -public sealed partial class Uploads : IDisposable -{ - [NotNull] - private ConsoleLogger? Logger1 { get; set; } - - [NotNull] - private ConsoleLogger? Logger2 { get; set; } - - private static readonly Random Random = new(); - - private CancellationTokenSource? ReadToken { get; set; } - - private static long MaxFileLength => 5 * 1024 * 1024; - - private Person Foo1 { get; set; } = new Person(); - - private Person Foo2 { get; set; } = new Person(); - - private List PreviewFileList { get; } = []; - - private CancellationTokenSource? ReadAvatarToken { get; set; } - - private List DefaultFormatFileList { get; } = - [ - new() { FileName = "Test.xls" }, - new() { FileName = "Test.doc" }, - new() { FileName = "Test.ppt" }, - new() { FileName = "Test.mp3" }, - new() { FileName = "Test.mp4" }, - new() { FileName = "Test.pdf" }, - new() { FileName = "Test.cs" }, - new() { FileName = "Test.zip" }, - new() { FileName = "Test.txt" }, - new() { FileName = "Test.dat" } - ]; - - private List Base64FormatFileList { get; } = - [ - new() { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" }, - ]; - - /// - /// - /// - protected override void OnInitialized() - { - base.OnInitialized(); - - PreviewFileList.AddRange( - [ - new UploadFile { PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/Argo.png" } - ]); - } - - private Task OnFileChange(UploadFile file) - { - // 未真正保存文件 - // file.SaveToFile() - Logger1.Log($"{file.File!.Name} {Localizer["UploadsSuccess"]}"); - return Task.CompletedTask; - } - - private Task OnFileDelete(UploadFile item) - { - Logger1.Log($"{item.OriginFileName} {Localizer["UploadsRemoveMsg"]}"); - return Task.FromResult(true); - } - - private static Task OnSubmit(EditContext context) - { - // 示例代码请根据业务情况自行更改 - // var fileName = Foo.Picture?.Name; - return Task.CompletedTask; - } - - private async Task OnClickToUpload(UploadFile file) - { - // 示例代码,模拟 80% 几率保存成功 - var error = Random.Next(1, 100) > 80; - if (error) - { - file.Code = 1; - file.Error = Localizer["UploadsError"]; - } - else - { - await SaveToFile(file); - } - } - - private async Task OnClickToUploadNoUploadList(UploadFile file) - { - await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success."); - } - - private async Task SaveToFile(UploadFile file) - { - // Server Side 使用 - // Web Assembly 模式下必须使用 WebApi 方式去保存文件到服务器或者数据库中 - // 生成写入文件名称 - if (!string.IsNullOrEmpty(WebsiteOption.CurrentValue.WebRootPath)) - { - var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader"); - file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; - var fileName = Path.Combine(uploaderFolder, file.FileName); - - ReadToken ??= new CancellationTokenSource(); - var ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token); - - if (ret) - { - // 保存成功 - file.PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/uploader/{file.FileName}"; - } - else - { - var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}"; - file.Code = 1; - file.Error = errorMessage; - await ToastService.Error(Localizer["UploadFile"], errorMessage); - } - } - else - { - file.Code = 1; - file.Error = Localizer["UploadsWasmError"]; - await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]); - } - } - - private async Task OnDownload(UploadFile item) - { - await ToastService.Success("文件下载", $"下载 {item.FileName} 成功"); - } - - private async Task OnUploadFolder(UploadFile file) - { - // 上传文件夹时会多次回调此方法 - await SaveToFile(file); - } - - private async Task OnAvatarUpload(UploadFile file) - { - // 示例代码,使用 base64 格式 - if (file is { File: not null }) - { - var format = file.File.ContentType; - if (CheckValidAvatarFormat(format)) - { - ReadAvatarToken ??= new CancellationTokenSource(); - if (ReadAvatarToken.IsCancellationRequested) - { - ReadAvatarToken.Dispose(); - ReadAvatarToken = new CancellationTokenSource(); - } - - await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token); - } - else - { - file.Code = 1; - file.Error = Localizer["UploadsFormatError"]; - } - - if (file.Code != 0) - { - await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}"); - } - } - } - - private static bool CheckValidAvatarFormat(string format) - { - return "jpg;png;bmp;gif;jpeg".Split(';').Any(f => format.Contains(f, StringComparison.OrdinalIgnoreCase)); - } - - private Task OnAvatarValidSubmit(EditContext context) - { - Logger2.Log(Foo2.Picture?.Name ?? ""); - return Task.CompletedTask; - } - - private async Task OnCardUpload(UploadFile file) - { - if (file is { File: not null }) - { - // 服务器端验证当文件大于 5MB 时提示文件太大信息 - if (file.Size > MaxFileLength) - { - await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]); - file.Code = 1; - file.Error = Localizer["UploadsFileError"]; - } - else - { - await SaveToFile(file); - await ToastService.Success(Localizer["UploadsFileMsg"], $"{file.File!.Name} {Localizer["UploadsSuccess"]}"); - } - } - } - - private readonly List _dropFiles = []; - private Task OnDropUpload(UploadFile file) - { - _dropFiles.Add(file); - StateHasChanged(); - return Task.CompletedTask; - } - - /// - /// - /// - public void Dispose() - { - ReadToken?.Cancel(); - ReadAvatarToken?.Cancel(); - GC.SuppressFinalize(this); - } - - private List GetInputAttributes() => - [ - new() { - Name = "ShowDeleteButton", - Description = Localizer["UploadsShowDeleteButton"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "IsDisabled", - Description = Localizer["UploadsIsDisabled"], - Type = "boolean", - ValueList = "true / false", - DefaultValue = "false" - }, - new() { - Name = "PlaceHolder", - Description = Localizer["UploadsPlaceHolder"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "Accept", - Description = Localizer["UploadsAccept"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "BrowserButtonClass", - Description = Localizer["UploadsBrowserButtonClass"], - Type = "string", - ValueList = " — ", - DefaultValue = "btn-primary" - }, - new() { - Name = "BrowserButtonIcon", - Description = Localizer["UploadsBrowserButtonIcon"], - Type = "string", - ValueList = " — ", - DefaultValue = "fa-regular fa-folder-open" - }, - new() { - Name = "BrowserButtonText", - Description = Localizer["UploadsBrowserButtonText"], - Type = "string", - ValueList = " — ", - DefaultValue = "" - }, - new() { - Name = "DeleteButtonClass", - Description = Localizer["UploadsDeleteButtonClass"], - Type = "string", - ValueList = " — ", - DefaultValue = "btn-danger" - }, - new() { - Name = "DeleteButtonIcon", - Description = Localizer["UploadsDeleteButtonIcon"], - Type = "string", - ValueList = " — ", - DefaultValue = "fa-regular fa-trash" - }, - new() { - Name = "DeleteButtonText", - Description = Localizer["UploadsDeleteButtonText"], - Type = "string", - ValueList = " — ", - DefaultValue = Localizer["UploadsDeleteButtonTextDefaultValue"] - }, - new() { - Name = "OnDelete", - Description = Localizer["UploadsOnDelete"], - Type = "Func>", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnChange", - Description = Localizer["UploadsOnChange"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - } - ]; - - private List GetButtonAttributes() => - [ - new() { - Name = "IsDirectory", - Description = Localizer["UploadsIsDirectory"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "IsMultiple", - Description = Localizer["UploadsIsMultiple"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "IsSingle", - Description = Localizer["UploadsIsSingle"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "Accept", - Description = Localizer["UploadsAccept"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "BrowserButtonClass", - Description = Localizer["UploadsBrowserButtonClass"], - Type = "string", - ValueList = " — ", - DefaultValue = "btn-primary" - }, - new() { - Name = "BrowserButtonIcon", - Description = Localizer["UploadsBrowserButtonIcon"], - Type = "string", - ValueList = " — ", - DefaultValue = "fa-regular fa-folder-open" - }, - new() { - Name = "BrowserButtonText", - Description = Localizer["UploadsBrowserButtonText"], - Type = "string", - ValueList = " — ", - DefaultValue = "" - }, - new() { - Name = "DefaultFileList", - Description = Localizer["UploadsDefaultFileList"], - Type = "List", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnGetFileFormat", - Description = Localizer["UploadsOnGetFileFormat"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnDelete", - Description = Localizer["UploadsOnDelete"], - Type = "Func>", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnChange", - Description = Localizer["UploadsOnChange"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnDownload", - Description = Localizer["UploadsOnDownload"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "IconTemplate", - Description = Localizer["UploadsIconTemplate"], - Type = "RenderFragment", - ValueList = " — ", - DefaultValue = " — " - } - ]; - - private List GetAvatarAttributes() => - [ - new() { - Name = "Width", - Description = Localizer["UploadsWidth"], - Type = "int", - ValueList = " — ", - DefaultValue = "0" - }, - new() { - Name = "Height", - Description = Localizer["UploadsHeight"], - Type = "int", - ValueList = "—", - DefaultValue = "0" - }, - new() { - Name = "IsCircle", - Description = Localizer["UploadsIsCircle"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "IsSingle", - Description = Localizer["UploadsIsSingle"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() { - Name = "Accept", - Description = Localizer["UploadsAccept"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "DefaultFileList", - Description = Localizer["UploadsDefaultFileList"], - Type = "List", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnDelete", - Description = Localizer["UploadsOnDelete"], - Type = "Func>", - ValueList = " — ", - DefaultValue = " — " - }, - new() { - Name = "OnChange", - Description = Localizer["UploadsOnChange"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - } - ]; - - private class Person - { - [Required] - [StringLength(20, MinimumLength = 2)] - public string Name { get; set; } = "Blazor"; - - [Required] - [FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 50 * 1024)] - public IBrowserFile? Picture { get; set; } - } -} From cbe55a149c26d957ac4d297e65095c0ebdd6a9fa Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 14:06:27 +0800 Subject: [PATCH 038/177] =?UTF-8?q?chore:=20=E5=A2=9E=E5=8A=A0=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/docs.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/docs.json b/src/BootstrapBlazor.Server/docs.json index b3dd5b46714..5f39de637c2 100644 --- a/src/BootstrapBlazor.Server/docs.json +++ b/src/BootstrapBlazor.Server/docs.json @@ -179,7 +179,11 @@ "transfer": "Transfers", "transition": "Transitions", "tree-view": "TreeViews", - "upload": "Uploads", + "upload-input": "Uploads", + "upload-button": "Uploads", + "upload-card": "Uploads", + "upload-avatar": "Uploads", + "upload-drop": "Uploads", "validate-form": "ValidateForms", "video-player": "VideoPlayers", "table": "Table\\Tables", From 43cd5849cffdfb6feb9997e1986a5a61de20a836 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 14:06:46 +0800 Subject: [PATCH 039/177] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E8=8F=9C?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/MenusLocalizerExtensions.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs index 01de5dff64b..bf4fc503b45 100644 --- a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs +++ b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs @@ -489,8 +489,28 @@ void AddForm(DemoMenuItem item) }, new() { - Text = Localizer["Upload"], - Url = "upload" + Text = Localizer["InputUpload"], + Url = "upload-input" + }, + new() + { + Text = Localizer["ButtonUpload"], + Url = "upload-button" + }, + new() + { + Text = Localizer["AvatarUpload"], + Url = "upload-avatar" + }, + new() + { + Text = Localizer["CardUpload"], + Url = "upload-card" + }, + new() + { + Text = Localizer["DropUpload"], + Url = "upload-drop" }, new() { From 4358855cfcca5df5b570025fcc0ec08749183589 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 14:06:55 +0800 Subject: [PATCH 040/177] =?UTF-8?q?chore:=20=E8=AE=BE=E7=BD=AE=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Extensions/UploadFileExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index 5c127889ac3..1bba8e08bed 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -191,7 +191,7 @@ public static async Task SaveToFileAsync(this UploadFile upload, string fi /// /// /// - public static bool IsImage(this UploadFile item, List? allowExtensions, Func? _callback = null) + public static bool IsImage(this UploadFile item, List? allowExtensions = null, Func? _callback = null) { bool ret; if (_callback != null) From dc25bbf1f19d00e987a1f98b6c036f2aea89cbd9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:15:39 +0800 Subject: [PATCH 041/177] =?UTF-8?q?style:=20=E6=9B=B4=E6=96=B0=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 3 ++- src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 9fe8431c2df..4a3f0c03f24 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -13,6 +13,7 @@ --bb-upload-drop-height: #{$bb-upload-drop-height}; --bb-upload-drop-footer-font-size: #{$bb-upload-drop-footer-font-size}; --bb-upload-drop-footer-margin-top: #{$bb-upload-drop-footer-margin-top}; + --bb-upload-item-border-radius: #{$bb-upload-item-border-radius}; } .upload .upload-body { @@ -124,7 +125,7 @@ } .upload .upload-body.is-avatar .upload-item.is-circle { - border-radius: 50%; + border-radius: var(--bb-upload-item-border-radius); } .upload .upload-body.is-avatar .upload-item:not(.is-form):hover, diff --git a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss index f936c39522f..90d59186914 100644 --- a/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss +++ b/src/BootstrapBlazor/wwwroot/scss/theme/bootstrapblazor.scss @@ -702,6 +702,7 @@ $bb-upload-card-item-width: 168px; $bb-upload-drop-height: 140px; $bb-upload-drop-footer-font-size: 12px; $bb-upload-drop-footer-margin-top: .25rem; +$bb-upload-item-border-radius: 50%; // ValidateForm $bb-form-control-padding: 0.375rem 0.75rem; From d5ed8b53230dc42d85cc40e7a5073dc56a8931c9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:15:57 +0800 Subject: [PATCH 042/177] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Radius=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/AvatarUpload.razor | 4 ++-- .../Components/Upload/AvatarUpload.razor.cs | 9 ++++++++- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 8c24c0fda81..0540a83ca39 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -14,7 +14,7 @@ } @foreach (var item in GetUploadFiles()) { -
+
@if (!IsDisabled) { @@ -49,7 +49,7 @@ @code { RenderFragment RenderAdd => - @
+ @
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index e0f93d40c60..917f861d089 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -28,6 +28,12 @@ public partial class AvatarUpload [Parameter] public bool IsCircle { get; set; } + /// + /// Gets or sets the border radius. Default is null. + /// + [Parameter] + public string? BorderRadius { get; set; } + /// /// 获得/设置 删除图标 /// @@ -89,10 +95,11 @@ public partial class AvatarUpload /// /// 获得/设置 预览框 Style 属性 /// - private string? PrevStyleString => CssBuilder.Default() + private string? ItemStyleString => CssBuilder.Default() .AddClass($"width: {Width}px;", Width > 0) .AddClass($"height: {Height}px;", Height > 0 && !IsCircle) .AddClass($"height: {Width}px;", IsCircle) + .AddClass($"--bb-upload-item-border-radius: {BorderRadius};", IsCircle && !string.IsNullOrEmpty(BorderRadius)) .Build(); private string? ValidStatusIconString => CssBuilder.Default("valid-icon valid") diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 089c6157c0c..7f16b1196b0 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -109,7 +109,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) Size = f.Size, File = f, FileCount = args.FileCount, - Uploaded = OnChange == null, + Uploaded = false, UpdateCallback = Update }).ToList(); From 9716f95a0ee650c559b72a8b8a89d2018566a5ec Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:16:17 +0800 Subject: [PATCH 043/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 95 +++++++++++-------- .../Components/Samples/UploadAvatars.razor.cs | 35 ++++--- 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index 46d7dddb8b0..06f890507ff 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -1,6 +1,6 @@ @page "/upload-avatar" @inject IOptionsMonitor WebsiteOption -@inject IStringLocalizer Localizer +@inject IStringLocalizer Localizer @inject ToastService ToastService

@Localizer["UploadsTitle"]

@@ -13,48 +13,61 @@ -
-
-

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

- + Name="Normal"> +
+

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
-
-

@Localizer["AvatarUploadTips2"]

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips3"].Value)

- -

@((MarkupString)Localizer["AvatarUploadTips5"].Value)

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips6"].Value)

- -
-
-

@((MarkupString)Localizer["AvatarUploadTips7"].Value)

- -
-
- -
-
- -
-
- -
-
-
+
+ + + + + + + + + +
+
+ +
+
+ +
+
+ +
-
- + diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index d86069f036b..ebcddf804e5 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -12,16 +12,16 @@ namespace BootstrapBlazor.Server.Components.Samples; ///
public partial class UploadAvatars : IDisposable { - private CancellationTokenSource? ReadAvatarToken { get; set; } + private static long MaxFileLength = 5 * 1024 * 1024; + private CancellationTokenSource? _token; + private List _previewFileList = []; + private Person _foo = new(); + private bool _isMultiple = true; + private bool _isUploadButtonAtFirst; + private bool _isCircle; + private int _radius = 49; - private static long MaxFileLength => 5 * 1024 * 1024; - - private List PreviewFileList { get; } = []; - - private Person Foo2 { get; set; } = new Person(); - - [NotNull] - private ConsoleLogger? Logger2 { get; set; } + private string? RadiusString => $"{_radius}px"; /// /// @@ -30,13 +30,13 @@ protected override void OnInitialized() { base.OnInitialized(); - PreviewFileList.AddRange( + _previewFileList.AddRange( [ new UploadFile { PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/Argo.png" } ]); } - private async Task OnAvatarUpload(UploadFile file) + private async Task OnChange(UploadFile file) { // 示例代码,使用 base64 格式 if (file is { File: not null }) @@ -44,14 +44,14 @@ private async Task OnAvatarUpload(UploadFile file) var format = file.File.ContentType; if (file.IsImage()) { - ReadAvatarToken ??= new CancellationTokenSource(); - if (ReadAvatarToken.IsCancellationRequested) + _token ??= new CancellationTokenSource(); + if (_token.IsCancellationRequested) { - ReadAvatarToken.Dispose(); - ReadAvatarToken = new CancellationTokenSource(); + _token.Dispose(); + _token = new CancellationTokenSource(); } - await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token); + await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, _token.Token); } else { @@ -68,7 +68,6 @@ private async Task OnAvatarUpload(UploadFile file) private Task OnAvatarValidSubmit(EditContext context) { - Logger2.Log(Foo2.Picture?.Name ?? ""); return Task.CompletedTask; } @@ -77,7 +76,7 @@ private Task OnAvatarValidSubmit(EditContext context) /// public void Dispose() { - ReadAvatarToken?.Cancel(); + _token?.Cancel(); GC.SuppressFinalize(this); } From f77dbff5ede8781e9681070b2cbb4d32fbf80836 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:16:29 +0800 Subject: [PATCH 044/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Locales/en-US.json | 28 +++++++++++-------- src/BootstrapBlazor.Server/Locales/zh-CN.json | 28 +++++++++++-------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 64e65d3f653..0fb6890fd40 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3442,7 +3442,23 @@ "RightHeaderTemplate": "the right panel Header template", "RightItemTemplate": "the right panel Item template" }, - "BootstrapBlazor.Server.Components.Samples.Uploads": { + "BootstrapBlazor.Server.Components.Samples.UploadAvatars": { + "UploadsTitle": "AvatarUpload", + "UploadsSubTitle": "Click to upload a file, usually used to upload a preview of one or a group of avatar-like images", + "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", + "AvatarUploadTitle": "User profile picture upload", + "AvatarUploadIntro": "AvatarUpload component, using the OnChange to limit the format and size of images uploaded by users. In this example, only jpg/png/bmp/jpeg/gif five picture formats are allowed", + "AvatarUploadTips3": "When you set up IsSingle, you can upload only one image or file", + "AvatarUploadTips5": "RELATED: [Accept] [Media Types]", + "AvatarUploadTips6": "Set the preview address PrevUrl with the DefaultFileList property", + "AvatarUploadTips7": "Verify that an example of using a picture box is used in the form", + "AvatarUploadButtonText": "Submit", + "AvatarUploadValidateTitle": "ValidateForm", + "AvatarUploadValidateIntro": "Place it in ValidateForm to integrate automatic data validation function. For details, please refer to ValidateForm component", + "AvatarUploadAcceptTitle": "Accept", + "AvatarUploadAcceptIntro": "The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication" + }, + "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload", "UploadsSubTitle": "Upload the file by clicking", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", @@ -3463,16 +3479,6 @@ "UploadedFilesIntro": "Use DefaultFileList to set up uploaded content", "UploadFolderTitle": "Upload a folder", "UploadFolderIntro": "Use DefaultFileList to set up uploaded content", - "AvatarUploadTitle": "User profile picture upload", - "AvatarUploadIntro": "AvatarUpload component, using the OnChange to limit the format and size of images uploaded by users. In this example, only jpg/png/bmp/jpeg/gif five picture formats are allowed", - "AvatarUploadTips1": "Card form avatar box. Allow multiple selections by setting IsMultiple=\"true\". Mostly used for photo walls", - "AvatarUploadTips2": "Round avatar frame", - "AvatarUploadTips3": "When you set up IsSingle, you can upload only one image or file", - "AvatarUploadTips4": "
The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication
", - "AvatarUploadTips5": "RELATED: [Accept] [Media Types]", - "AvatarUploadTips6": "Set the preview address PrevUrl with the DefaultFileList property", - "AvatarUploadTips7": "Verify that an example of using a picture box is used in the form", - "AvatarUploadButtonText": "Submit", "UploadPreCardStyleTitle": "Preview the card style", "UploadPreCardStyleIntro": "CardUpload components and rendered in card-style band preview mode", "UploadPreCardStyleSSR": "SSR mode ", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index c3b4850fb3c..221104df7f6 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3442,7 +3442,23 @@ "RightHeaderTemplate": "右侧数据 Header 模板", "RightItemTemplate": "右侧数据项模板" }, - "BootstrapBlazor.Server.Components.Samples.Uploads": { + "BootstrapBlazor.Server.Components.Samples.UploadAvatars": { + "UploadsTitle": "AvatarUpload 头像上传组件", + "UploadsSubTitle": "通过点击上传文件,通常用作上传预览一个或者一组类似头像的图片", + "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", + "AvatarUploadTitle": "基本用法", + "AvatarUploadIntro": "通过设置 IsMultiple 控制是否允许多文件上传,通过设置 IsCircle 控制是否为圆角,通过设置 BorderRadius 控制圆角曲率", + "AvatarUploadTips3": "设置 IsSingle 时,仅可以上传一张图片或者文件", + "AvatarUploadTips5": "相关文档:[Accept 属性详解] [Media Types 详细列表]", + "AvatarUploadTips6": "通过 DefaultFileList 属性设置预览地址 PrevUrl 即可", + "AvatarUploadTips7": "验证表单内使用头像框示例", + "AvatarUploadButtonText": "提交", + "AvatarUploadValidateTitle": "ValidateForm", + "AvatarUploadValidateIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件", + "AvatarUploadAcceptTitle": "Accept", + "AvatarUploadAcceptIntro": "组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证" + }, + "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload 上传", "UploadsSubTitle": "通过点击上传文件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", @@ -3463,16 +3479,6 @@ "UploadedFilesIntro": "使用 DefaultFileList 设置已上传的内容", "UploadFolderTitle": "上传文件夹", "UploadFolderIntro": "使用 DefaultFileList 设置已上传的内容", - "AvatarUploadTitle": "用户头像上传", - "AvatarUploadIntro": "AvatarUpload 组件,使用 OnChange 限制用户上传的图片格式和大小。本例中仅允许上传 jpg/png/bmp/jpeg/gif 五种图片格式", - "AvatarUploadTips1": "卡片形式头像框,通过设置 IsMultiple=\"true\" 允许多选。多用于照片墙", - "AvatarUploadTips2": "圆形头像框", - "AvatarUploadTips3": "设置 IsSingle 时,仅可以上传一张图片或者文件", - "AvatarUploadTips4": "
组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证
", - "AvatarUploadTips5": "相关文档:[Accept 属性详解] [Media Types 详细列表]", - "AvatarUploadTips6": "通过 DefaultFileList 属性设置预览地址 PrevUrl 即可", - "AvatarUploadTips7": "验证表单内使用头像框示例", - "AvatarUploadButtonText": "提交", "UploadPreCardStyleTitle": "预览卡片式", "UploadPreCardStyleIntro": "CardUpload 组件,呈现为卡片式带预览模式", "UploadPreCardStyleSSR": "SSR 模式", From 73ec5f31d2e7faaa9061747837f88dfde3accf58 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:16:38 +0800 Subject: [PATCH 045/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/docs.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/docs.json b/src/BootstrapBlazor.Server/docs.json index 5f39de637c2..9728a7dcb1a 100644 --- a/src/BootstrapBlazor.Server/docs.json +++ b/src/BootstrapBlazor.Server/docs.json @@ -179,11 +179,11 @@ "transfer": "Transfers", "transition": "Transitions", "tree-view": "TreeViews", - "upload-input": "Uploads", - "upload-button": "Uploads", - "upload-card": "Uploads", - "upload-avatar": "Uploads", - "upload-drop": "Uploads", + "upload-input": "UploadInputs", + "upload-button": "UploadButtons", + "upload-card": "UploadCards", + "upload-avatar": "UploadAvatars", + "upload-drop": "UploadDrops", "validate-form": "ValidateForms", "video-player": "VideoPlayers", "table": "Table\\Tables", From e5ace888bb6fc12e7513814a835cb40e9fbae812 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:23:35 +0800 Subject: [PATCH 046/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 4 ++-- .../Components/Samples/UploadCards.razor | 2 +- src/BootstrapBlazor.Server/Locales/en-US.json | 20 +++++++++---------- src/BootstrapBlazor.Server/Locales/zh-CN.json | 20 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index ebcddf804e5..170fd6a5457 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -108,8 +108,8 @@ private List GetAttributes() => }, new() { - Name = "IsSingle", - Description = Localizer["UploadsIsSingle"], + Name = "IsMultiple", + Description = Localizer["UploadsIsMultiple"], Type = "bool", ValueList = "true|false", DefaultValue = "false" diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index bc26cba0db3..158fe19fd07 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -13,7 +13,7 @@ + Name="Normal">
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 0fb6890fd40..e512c95c307 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3456,7 +3456,16 @@ "AvatarUploadValidateTitle": "ValidateForm", "AvatarUploadValidateIntro": "Place it in ValidateForm to integrate automatic data validation function. For details, please refer to ValidateForm component", "AvatarUploadAcceptTitle": "Accept", - "AvatarUploadAcceptIntro": "The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication" + "AvatarUploadAcceptIntro": "The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication", + "UploadsWidth": "The width of the preview box", + "UploadsHeight": "The height of the preview box", + "UploadsIsCircle": "Whether it is circular avatar mode", + "UploadsIsMultiple": "Whether to allow multiple file uploads", + "UploadsShowProgress": "Whether to display the upload progress", + "UploadsDefaultFileList": "The collection of files has been uploaded", + "UploadsAccept": "Upload the received file format", + "UploadsOnDelete": "Call back this method when you click the Delete button", + "UploadsOnChange": "Call back this method when you click the Browse button" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload", @@ -3499,7 +3508,6 @@ "UploadsShowDownloadButton": "Whether to display the Download button", "UploadsIsDisabled": "Whether to disable it", "UploadsPlaceHolder": "The place-in string", - "UploadsAccept": "Upload the received file format", "UploadsBrowserButtonClass": "Upload button style", "UploadsBrowserButtonIcon": "Browse the button icon", "UploadsBrowserButtonText": "The browse button displays text", @@ -3507,18 +3515,10 @@ "UploadsDeleteButtonIcon": "Remove the button icon", "UploadsDeleteButtonText": "Delete the button text", "UploadsDeleteButtonTextDefaultValue": "Delete", - "UploadsOnDelete": "Call back this method when you click the Delete button", - "UploadsOnChange": "Call back this method when you click the Browse button", "UploadsOnDownload": "Call back this method when you click the Download button", "UploadsIsDirectory": "Whether to upload the entire directory", - "UploadsIsMultiple": "Whether to allow multiple file uploads", "UploadsIsSingle": "Whether to upload only once", - "UploadsShowProgress": "Whether to display the upload progress", - "UploadsDefaultFileList": "The collection of files has been uploaded", "UploadsOnGetFileFormat": "Set the file format icon to call back the delegate", - "UploadsWidth": "The width of the preview box", - "UploadsHeight": "The height of the preview box", - "UploadsIsCircle": "Whether it is circular avatar mode", "UploadsSuccess": "The upload was successful", "UploadsError": "The simulated upload failed", "UploadsFormatError": "The file format is incorrect", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 221104df7f6..8d46f86fa1b 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3456,7 +3456,16 @@ "AvatarUploadValidateTitle": "ValidateForm", "AvatarUploadValidateIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件", "AvatarUploadAcceptTitle": "Accept", - "AvatarUploadAcceptIntro": "组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证" + "AvatarUploadAcceptIntro": "组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证", + "UploadsWidth": "预览框宽度", + "UploadsHeight": "预览框高度", + "UploadsIsCircle": "是否为圆形头像模式", + "UploadsIsMultiple": "是否允许多文件上传", + "UploadsShowProgress": "是否显示上传进度", + "UploadsDefaultFileList": "已上传文件集合", + "UploadsAccept": "上传接收的文件格式", + "UploadsOnDelete": "点击删除按钮时回调此方法", + "UploadsOnChange": "点击浏览按钮时回调此方法" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload 上传", @@ -3499,7 +3508,6 @@ "UploadsShowDownloadButton": "是否显示下载按钮", "UploadsIsDisabled": "是否禁用", "UploadsPlaceHolder": "占位字符串", - "UploadsAccept": "上传接收的文件格式", "UploadsBrowserButtonClass": "上传按钮样式", "UploadsBrowserButtonIcon": "浏览按钮图标", "UploadsBrowserButtonText": "浏览按钮显示文字", @@ -3507,18 +3515,10 @@ "UploadsDeleteButtonIcon": "删除按钮图标", "UploadsDeleteButtonText": "删除按钮文字", "UploadsDeleteButtonTextDefaultValue": "删除", - "UploadsOnDelete": "点击删除按钮时回调此方法", - "UploadsOnChange": "点击浏览按钮时回调此方法", "UploadsOnDownload": "点击下载按钮时回调此方法", "UploadsIsDirectory": "是否上传整个目录", - "UploadsIsMultiple": "是否允许多文件上传", "UploadsIsSingle": "是否仅上传一次", - "UploadsShowProgress": "是否显示上传进度", - "UploadsDefaultFileList": "已上传文件集合", "UploadsOnGetFileFormat": "设置文件格式图标回调委托", - "UploadsWidth": "预览框宽度", - "UploadsHeight": "预览框高度", - "UploadsIsCircle": "是否为圆形头像模式", "UploadsSuccess": "上传成功", "UploadsError": "模拟上传失败", "UploadsFormatError": "文件格式不正确", From 717f10a9372fa72afa79b6b3a05139e69d5f1f93 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:25:15 +0800 Subject: [PATCH 047/177] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Locales/en-US.json | 3 ++- src/BootstrapBlazor.Server/Locales/zh-CN.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index e512c95c307..7164e242ed7 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3465,7 +3465,8 @@ "UploadsDefaultFileList": "The collection of files has been uploaded", "UploadsAccept": "Upload the received file format", "UploadsOnDelete": "Call back this method when you click the Delete button", - "UploadsOnChange": "Call back this method when you click the Browse button" + "UploadsOnChange": "Call back this method when you click the Browse button", + "UploadsBorderRadius": "Border radius" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 8d46f86fa1b..a8d683a06e2 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3465,7 +3465,8 @@ "UploadsDefaultFileList": "已上传文件集合", "UploadsAccept": "上传接收的文件格式", "UploadsOnDelete": "点击删除按钮时回调此方法", - "UploadsOnChange": "点击浏览按钮时回调此方法" + "UploadsOnChange": "点击浏览按钮时回调此方法", + "UploadsBorderRadius": "预览框圆角曲率" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload 上传", From b8a3f15cee9bea35507d5fc49847f143c4edcdf8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:30:09 +0800 Subject: [PATCH 048/177] =?UTF-8?q?doc:=20=E8=A1=A5=E5=85=85=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 12 ++++++++++-- src/BootstrapBlazor.Server/Locales/en-US.json | 7 ++++++- src/BootstrapBlazor.Server/Locales/zh-CN.json | 7 ++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index 170fd6a5457..627e53b7229 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -95,8 +95,8 @@ private List GetAttributes() => Name = "Height", Description = Localizer["UploadsHeight"], Type = "int", - ValueList = "—", - DefaultValue = "0" + ValueList = " — ", + DefaultValue = " — " }, new() { @@ -107,6 +107,14 @@ private List GetAttributes() => DefaultValue = "false" }, new() + { + Name = "BorderRadius", + Description = Localizer["UploadsBorderRadius"], + Type = "string?", + ValueList = " — ", + DefaultValue = " — " + }, + new() { Name = "IsMultiple", Description = Localizer["UploadsIsMultiple"], diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 7164e242ed7..242efac71dd 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -4934,7 +4934,12 @@ "TotpService": "ITotpService", "VideoDevice": "IVideoDevice", "AudioDevice": "IAudioDevice", - "FullScreenButton": "FullScreenButton" + "FullScreenButton": "FullScreenButton", + "InputUpload": "InputUpload", + "ButtonUpload": "ButtonUpload", + "AvatarUpload": "AvatarUpload", + "CardUpload": "CardUpload", + "DropUpload": "DropUpload" }, "BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": { "TablesHeaderTitle": "Header grouping function", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index a8d683a06e2..f08be238e44 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -4934,7 +4934,12 @@ "TotpService": "时间密码验证服务 ITotpService", "VideoDevice": "视频设备服务 IVideoDevice", "AudioDevice": "音频设备服务 IAudioDevice", - "FullScreenButton": "全屏按钮 FullScreenButton" + "FullScreenButton": "全屏按钮 FullScreenButton", + "InputUpload": "上传组件 InputUpload", + "ButtonUpload": "按钮上传组件 ButtonUpload", + "AvatarUpload": "头像上传组件 AvatarUpload", + "CardUpload": "卡片上传组件 CardUpload", + "DropUpload": "拖动上传组件 DropUpload" }, "BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": { "TablesHeaderTitle": "表头分组功能", From d4fcae60d3c1cbb1115a724e021b63da5320a532 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 15:57:00 +0800 Subject: [PATCH 049/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 1 - src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index 06f890507ff..7ca511898fc 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -15,7 +15,6 @@ Introduction="@Localizer["AvatarUploadIntro"]" Name="Normal">
-

@((MarkupString)Localizer["AvatarUploadTips1"].Value)

diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index f08be238e44..3ffc3a8a548 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3447,7 +3447,7 @@ "UploadsSubTitle": "通过点击上传文件,通常用作上传预览一个或者一组类似头像的图片", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "AvatarUploadTitle": "基本用法", - "AvatarUploadIntro": "通过设置 IsMultiple 控制是否允许多文件上传,通过设置 IsCircle 控制是否为圆角,通过设置 BorderRadius 控制圆角曲率", + "AvatarUploadIntro": "通过设置 IsMultiple 控制是否允许多文件上传,通过设置 IsCircle 控制是否为圆角,通过设置 BorderRadius 控制圆角曲率", "AvatarUploadTips3": "设置 IsSingle 时,仅可以上传一张图片或者文件", "AvatarUploadTips5": "相关文档:[Accept 属性详解] [Media Types 详细列表]", "AvatarUploadTips6": "通过 DefaultFileList 属性设置预览地址 PrevUrl 即可", From bb0fa13c9a968d14ac5bec568115290eeccb44fd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 16:23:58 +0800 Subject: [PATCH 050/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor | 10 +++++----- src/BootstrapBlazor.Server/Locales/en-US.json | 11 +++++++++-- src/BootstrapBlazor.Server/Locales/zh-CN.json | 9 ++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor index f6b7e2bf5a8..a62d4155a63 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -11,19 +11,19 @@
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
- +

@((MarkupString)Localizer["UploadClickUploadTips1"].Value)

+ OnChange="@OnClickToUpload">

@((MarkupString)Localizer["UploadClickUploadTips2"].Value)

+ OnChange="@OnClickToUpload">

@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 242efac71dd..f22691be94d 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3446,8 +3446,8 @@ "UploadsTitle": "AvatarUpload", "UploadsSubTitle": "Click to upload a file, usually used to upload a preview of one or a group of avatar-like images", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", - "AvatarUploadTitle": "User profile picture upload", - "AvatarUploadIntro": "AvatarUpload component, using the OnChange to limit the format and size of images uploaded by users. In this example, only jpg/png/bmp/jpeg/gif five picture formats are allowed", + "AvatarUploadTitle": "Basic usage", + "AvatarUploadIntro": "AvatarUpload component, using the OnChange to limit the format and size of images uploaded by users. In this example, only jpg/png/bmp/jpeg/gif five picture formats are allowed. The component processes user uploaded avatars by setting the OnChange callback function. If this callback is not provided, the component will use the built-in method to try to read the uploaded file and generate the preview data in base64 format.", "AvatarUploadTips3": "When you set up IsSingle, you can upload only one image or file", "AvatarUploadTips5": "RELATED: [Accept] [Media Types]", "AvatarUploadTips6": "Set the preview address PrevUrl with the DefaultFileList property", @@ -3468,6 +3468,13 @@ "UploadsOnChange": "Call back this method when you click the Browse button", "UploadsBorderRadius": "Border radius" }, + "BootstrapBlazor.Server.Components.Samples.UploadButtons": { + "UploadsTitle": "ButtonUpload", + "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", + "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", + "ButtonUploadTitle": "Basic usage", + "ButtonUploadIntro": "" + }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload", "UploadsSubTitle": "Upload the file by clicking", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 3ffc3a8a548..c8a7595c82d 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3447,7 +3447,7 @@ "UploadsSubTitle": "通过点击上传文件,通常用作上传预览一个或者一组类似头像的图片", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "AvatarUploadTitle": "基本用法", - "AvatarUploadIntro": "通过设置 IsMultiple 控制是否允许多文件上传,通过设置 IsCircle 控制是否为圆角,通过设置 BorderRadius 控制圆角曲率", + "AvatarUploadIntro": "通过设置 IsMultiple 控制是否允许多文件上传,通过设置 IsCircle 控制是否为圆角,通过设置 BorderRadius 控制圆角曲率。组件通过设置 OnChange 回调函数处理用户上传头像,如果未提供此回调时,将使用内置方法尝试读取上传文件生成 base64 格式预览数据", "AvatarUploadTips3": "设置 IsSingle 时,仅可以上传一张图片或者文件", "AvatarUploadTips5": "相关文档:[Accept 属性详解] [Media Types 详细列表]", "AvatarUploadTips6": "通过 DefaultFileList 属性设置预览地址 PrevUrl 即可", @@ -3468,6 +3468,13 @@ "UploadsOnChange": "点击浏览按钮时回调此方法", "UploadsBorderRadius": "预览框圆角曲率" }, + "BootstrapBlazor.Server.Components.Samples.UploadButtons": { + "UploadsTitle": "ButtonUpload 按钮上传组件", + "UploadsSubTitle": "通过点击上传文件,通常用作上传文件附件", + "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", + "ButtonUploadTitle": "基础用法", + "ButtonUploadIntro": "" + }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "Upload 上传", "UploadsSubTitle": "通过点击上传文件", From 3ce17e7ee747e638bae6654f685b7dc5aa0c6c20 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 May 2025 19:21:56 +0800 Subject: [PATCH 051/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadInputs.razor | 2 +- .../Components/Samples/UploadInputs.razor.cs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor index 8631d8409c7..36f91632fc7 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor @@ -21,8 +21,8 @@ OnChange="@OnFileChange" OnDelete="@OnFileDelete">
-
+ diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs index c041421ccc7..a170c69c10e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs @@ -12,9 +12,6 @@ namespace BootstrapBlazor.Server.Components.Samples; ///
public partial class UploadInputs { - [NotNull] - private ConsoleLogger? Logger1 { get; set; } - private Person Foo1 { get; set; } = new Person(); private Task OnFileChange(UploadFile file) From 68eec728f6dc53734760c62487ce5c3dd2bcd615 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 09:45:31 +0800 Subject: [PATCH 052/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=20UploadInput?= =?UTF-8?q?s=20=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadInputs.razor | 6 +-- .../Components/Samples/UploadInputs.razor.cs | 12 ++---- src/BootstrapBlazor.Server/Locales/en-US.json | 38 +++++++++++++------ src/BootstrapBlazor.Server/Locales/zh-CN.json | 38 +++++++++++++------ 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor index 36f91632fc7..f5eeb4c1d09 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor @@ -16,9 +16,9 @@ Name="Normal">
- + OnChange="@OnFileChange">
@@ -27,7 +27,7 @@ Introduction="@Localizer["UploadFormSettingsIntro"]" Name="FormSettings">
-
    +
    • @((MarkupString)Localizer["UploadFormSettingsLi1"].Value)
    • @((MarkupString)Localizer["UploadFormSettingsLi2"].Value)
    diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs index a170c69c10e..35c128beca9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs @@ -14,18 +14,12 @@ public partial class UploadInputs { private Person Foo1 { get; set; } = new Person(); - private Task OnFileChange(UploadFile file) + private async Task OnFileChange(UploadFile file) { // 未真正保存文件 // file.SaveToFile() - Logger1.Log($"{file.File!.Name} {Localizer["UploadsSuccess"]}"); - return Task.CompletedTask; - } - - private Task OnFileDelete(UploadFile item) - { - Logger1.Log($"{item.OriginFileName} {Localizer["UploadsRemoveMsg"]}"); - return Task.FromResult(true); + await Task.Delay(200); + await ToastService.Information(Localizer["UploadsSaveFile"], $"{file.File!.Name} {Localizer["UploadsSuccess"]}"); } private static Task OnSubmit(EditContext context) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 9c4daa41b84..5c0de5b4ddd 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3481,6 +3481,32 @@ "UploadsOnChange": "Call back this method when you click the Browse button", "UploadsBorderRadius": "Border radius" }, + "BootstrapBlazor.Server.Components.Samples.UploadInputs": { + "UploadsTitle": "InputUpload", + "UploadsSubTitle": "Select one or more files to upload by clicking the Browse button.", + "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", + "UploadNormalTitle": "Basic usage", + "UploadNormalIntro": "You can show the Delete button by setting ShowDeleteButton=\"true\"", + "UploadNormalLabelPhoto": "Select one or more files", + "UploadFormSettingsTitle": "ValidateForm", + "UploadFormSettingsIntro": "Use the file upload component to constrain the file format within the form", + "UploadFormSettingsLi1": "Using the ValidateForm form component, custom validation is set by setting the fileValidation label of the model properties to support file extensionsizevalidation, in this case with the extension .png .jpg .jpeg and the file size limit to 50K", + "UploadFormSettingsLi2": "After selecting the file and not starting to upload the file, click the submit button to verify that the data is legitimate, and then upload the file OnSubmit callback delegate, noting that the Pictureproperty type is IBrowserFile", + "UploadFormSettingsButtonText": "Submit", + "UploadsShowDeleteButton": "Whether to display the Delete button", + "UploadsIsDisabled": "Whether to disable it", + "UploadsPlaceHolder": "The place-in string", + "UploadsBrowserButtonClass": "Upload button style", + "UploadsBrowserButtonIcon": "Browse the button icon", + "UploadsBrowserButtonText": "The browse button displays text", + "UploadsDeleteButtonClass": "Remove the button style", + "UploadsDeleteButtonIcon": "Remove the button icon", + "UploadsDeleteButtonText": "Delete the button text", + "UploadsDeleteButtonTextDefaultValue": "Delete", + "UploadsAccept": "Upload the received file format", + "UploadsOnDelete": "Call back this method when you click the Delete button", + "UploadsOnChange": "Call back this method when you click the Browse button" + }, "BootstrapBlazor.Server.Components.Samples.UploadButtons": { "UploadsTitle": "ButtonUpload", "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", @@ -3488,7 +3514,7 @@ "ButtonUploadTitle": "Basic usage", "ButtonUploadIntro": "" }, - "BootstrapBlazor.Server.Components.Samples.UploadInputs": { + "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", "UploadsSubTitle": "Upload the file by clicking", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", @@ -3525,17 +3551,7 @@ "UploadFileIconTemplateIntro": "By setting the IconTemplate parameter and using the FileIcon component, you can further customize the file icon [FileIcon example]", "UploadBase64Title": "Base64 format", "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", - "UploadsShowDeleteButton": "Whether to display the Delete button", "UploadsShowDownloadButton": "Whether to display the Download button", - "UploadsIsDisabled": "Whether to disable it", - "UploadsPlaceHolder": "The place-in string", - "UploadsBrowserButtonClass": "Upload button style", - "UploadsBrowserButtonIcon": "Browse the button icon", - "UploadsBrowserButtonText": "The browse button displays text", - "UploadsDeleteButtonClass": "Remove the button style", - "UploadsDeleteButtonIcon": "Remove the button icon", - "UploadsDeleteButtonText": "Delete the button text", - "UploadsDeleteButtonTextDefaultValue": "Delete", "UploadsOnDownload": "Call back this method when you click the Download button", "UploadsIsDirectory": "Whether to upload the entire directory", "UploadsIsSingle": "Whether to upload only once", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index eabb27c99e0..066e46a226f 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3481,6 +3481,32 @@ "UploadsOnChange": "点击浏览按钮时回调此方法", "UploadsBorderRadius": "预览框圆角曲率" }, + "BootstrapBlazor.Server.Components.Samples.UploadInputs": { + "UploadsTitle": "InputUpload 上传组件", + "UploadsSubTitle": "通过点击浏览按钮选择一个或者多个文件进行上传", + "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", + "UploadNormalTitle": "基础用法", + "UploadNormalIntro": "可以通过设置 ShowDeleteButton=\"true\" 显示 删除 按钮", + "UploadNormalLabelPhoto": "选择一个或者多个文件", + "UploadFormSettingsTitle": "表单应用", + "UploadFormSettingsIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件", + "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K", + "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", + "UploadFormSettingsButtonText": "提交", + "UploadsShowDeleteButton": "是否显示删除按钮", + "UploadsIsDisabled": "是否禁用", + "UploadsPlaceHolder": "占位字符串", + "UploadsBrowserButtonClass": "上传按钮样式", + "UploadsBrowserButtonIcon": "浏览按钮图标", + "UploadsBrowserButtonText": "浏览按钮显示文字", + "UploadsDeleteButtonClass": "删除按钮样式", + "UploadsDeleteButtonIcon": "删除按钮图标", + "UploadsDeleteButtonText": "删除按钮文字", + "UploadsDeleteButtonTextDefaultValue": "删除", + "UploadsAccept": "上传接收的文件格式", + "UploadsOnDelete": "点击删除按钮时回调此方法", + "UploadsOnChange": "点击浏览按钮时回调此方法" + }, "BootstrapBlazor.Server.Components.Samples.UploadButtons": { "UploadsTitle": "ButtonUpload 按钮上传组件", "UploadsSubTitle": "通过点击上传文件,通常用作上传文件附件", @@ -3488,7 +3514,7 @@ "ButtonUploadTitle": "基础用法", "ButtonUploadIntro": "" }, - "BootstrapBlazor.Server.Components.Samples.UploadInputs": { + "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", "UploadsSubTitle": "通过点击上传文件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", @@ -3525,17 +3551,7 @@ "UploadFileIconTemplateIntro": "通过设置 IconTemplate 参数,使用 FileIcon 组件可以对文件图标进行进一步自定义 [FileIcon 示例]", "UploadBase64Title": "Base64 格式文件", "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", - "UploadsShowDeleteButton": "是否显示删除按钮", "UploadsShowDownloadButton": "是否显示下载按钮", - "UploadsIsDisabled": "是否禁用", - "UploadsPlaceHolder": "占位字符串", - "UploadsBrowserButtonClass": "上传按钮样式", - "UploadsBrowserButtonIcon": "浏览按钮图标", - "UploadsBrowserButtonText": "浏览按钮显示文字", - "UploadsDeleteButtonClass": "删除按钮样式", - "UploadsDeleteButtonIcon": "删除按钮图标", - "UploadsDeleteButtonText": "删除按钮文字", - "UploadsDeleteButtonTextDefaultValue": "删除", "UploadsOnDownload": "点击下载按钮时回调此方法", "UploadsIsDirectory": "是否上传整个目录", "UploadsIsSingle": "是否仅上传一次", From 7b0bfc7553baa28ff85c3ce9b7d8dcb32e6f1c0d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 09:45:42 +0800 Subject: [PATCH 053/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Toast/Toast.razor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Toast/Toast.razor.js b/src/BootstrapBlazor/Components/Toast/Toast.razor.js index c3f1a8d3f24..79be9cfe0db 100644 --- a/src/BootstrapBlazor/Components/Toast/Toast.razor.js +++ b/src/BootstrapBlazor/Components/Toast/Toast.razor.js @@ -30,7 +30,9 @@ export function init(id, invoke, callback) { invoke.invokeMethodAsync(toast.callback) }) EventHandler.on(progressElement, 'transitionend', e => { - toast.toast.hide(); + if (toast.toast._config.autohide === false) { + toast.toast.hide(); + } }); toast.toast.show(); @@ -42,8 +44,6 @@ export function update(id) { const autoHide = element.getAttribute('data-bs-autohide') !== 'false'; if (autoHide) { const delay = parseInt(element.getAttribute('data-bs-delay')); - - toast._config.autohide = autoHide; toast._config.delay = delay; progressElement.style.width = '100%'; From a4e2090dce3a2cadc94971b7637acc7192173640 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 10:15:57 +0800 Subject: [PATCH 054/177] =?UTF-8?q?doc:=20=E7=B2=BE=E7=AE=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor | 1 - 1 file changed, 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor index f5eeb4c1d09..0cde718133f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor @@ -1,5 +1,4 @@ @page "/upload-input" -@inject IOptionsMonitor WebsiteOption @inject IStringLocalizer Localizer @inject ToastService ToastService From 9fef5f3adda65f1c4132d8d7a89e5d837d217e0f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 10:16:20 +0800 Subject: [PATCH 055/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=20ButtonUploa?= =?UTF-8?q?d=20=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor | 84 ++++++++++--------- .../Components/Samples/UploadButtons.razor.cs | 7 ++ src/BootstrapBlazor.Server/Locales/en-US.json | 4 +- src/BootstrapBlazor.Server/Locales/zh-CN.json | 11 ++- 4 files changed, 59 insertions(+), 47 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor index a62d4155a63..c7b7f589b3a 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -1,6 +1,6 @@ @page "/upload-button" @inject IOptionsMonitor WebsiteOption -@inject IStringLocalizer Localizer +@inject IStringLocalizer Localizer @inject ToastService ToastService

    @Localizer["UploadsTitle"]

    @@ -14,46 +14,50 @@ -
    -
    -

    @((MarkupString)Localizer["UploadClickUploadTips1"].Value)

    - +
    +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    -
    -

    @((MarkupString)Localizer["UploadClickUploadTips2"].Value)

    - -
    -
    -

    @((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)

    - -
    -
    - - - -
    -
    - -
    -
    -
    - - -
    -
    - -
    -
    +
+ diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index 1dca21363d4..9fccb65ad06 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -14,6 +14,13 @@ public partial class UploadButtons private CancellationTokenSource? ReadToken { get; set; } private static long MaxFileLength => 5 * 1024 * 1024; + private bool _isMultiple = true; + private bool _showProgress = true; + private bool _showUploadFileList = true; + private bool _showDownloadButton = true; + private bool _isDirectory = false; + private bool _isDisabled = false; + private List DefaultFormatFileList { get; } = [ new() { FileName = "Test.xls" }, diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 5c0de5b4ddd..99abbe4267f 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3512,7 +3512,9 @@ "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", "ButtonUploadTitle": "Basic usage", - "ButtonUploadIntro": "" + "ButtonUploadIntro": "", + "UploadClickUploadTips2": "When you set up IsSingle, you can upload only one image or file", + "UploadClickUploadTips3ShowUploadList": "Set ShowUploadFileList value to false as normal button" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 066e46a226f..009cc258c2e 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3509,10 +3509,13 @@ }, "BootstrapBlazor.Server.Components.Samples.UploadButtons": { "UploadsTitle": "ButtonUpload 按钮上传组件", - "UploadsSubTitle": "通过点击上传文件,通常用作上传文件附件", + "UploadsSubTitle": "通过点击按钮弹出选择文件框进行上传操作文件,通常用作上传文件附件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", - "ButtonUploadIntro": "" + "ButtonUploadIntro": "", + "UploadClickUploadIntro": "ButtonUpload 组件,经典款式,用户点击按钮弹出文件选择框。", + "UploadClickUploadTips2": "设置 IsSingle 时,仅可以上传一张图片或者文件", + "UploadClickUploadTips3ShowUploadList": "设置 ShowUploadFileList 值为 false 组件即与普通按钮一样,可自行处理上传文件逻辑" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", @@ -3527,10 +3530,6 @@ "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", "UploadFormSettingsButtonText": "提交", "UploadClickUploadTitle": "点击上传", - "UploadClickUploadIntro": "ButtonUpload 组件,经典款式,用户点击按钮弹出文件选择框。", - "UploadClickUploadTips1": "点击 浏览按钮 选择文件上传,本例中设置 IsMultiple=true 可多选文件进行上传", - "UploadClickUploadTips2": "设置 IsSingle 时,仅可以上传一张图片或者文件", - "UploadClickUploadTips3ShowUploadList": "设置 ShowUploadFileList 值为 false 组件即与普通按钮一样,可自行处理上传文件逻辑", "UploadedFilesTitle": "已上传文件列表", "UploadedFilesIntro": "使用 DefaultFileList 设置已上传的内容", "UploadFolderTitle": "上传文件夹", From 6430faccdc5ef1922d7d4cb46a636cf96ddaff95 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 12:26:51 +0800 Subject: [PATCH 056/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/ButtonUpload.razor | 2 +- src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 89f7fe711cd..73d251623b2 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -25,7 +25,7 @@ { - + } else { diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 0b497f51e9b..d09725c9e78 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -71,7 +71,6 @@ public partial class ButtonUpload /// 获得/设置 浏览按钮颜色 /// [Parameter] - [NotNull] public Color BrowserButtonColor { get; set; } = Color.Primary; /// @@ -267,7 +266,7 @@ protected override void OnParametersSet() /// /// /// - protected async Task OnClickDownload(UploadFile item) + private async Task OnClickDownload(UploadFile item) { if (OnDownload != null) { @@ -280,7 +279,7 @@ protected async Task OnClickDownload(UploadFile item) /// /// /// - protected async Task OnClickCancel(UploadFile item) + private async Task OnClickCancel(UploadFile item) { if (OnCancel != null) { From 1c907979423942cd62c3cf38a4bbbf17bb833858 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 12:27:04 +0800 Subject: [PATCH 057/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor.cs | 88 +------------------ src/BootstrapBlazor.Server/Locales/en-US.json | 4 +- src/BootstrapBlazor.Server/Locales/zh-CN.json | 5 +- 3 files changed, 6 insertions(+), 91 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index 9fccb65ad06..dcbf27ff402 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -123,99 +123,19 @@ private List GetAttributes() => }, new() { - Name = "IsSingle", - Description = Localizer["UploadsIsSingle"], + Name = "ShowProgress", + Description = Localizer["UploadsShowProgress"], Type = "bool", ValueList = "true|false", DefaultValue = "false" }, new() { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], + Name = "ShowDownloadButton", + Description = Localizer["UploadsShowDownloadButton"], Type = "bool", ValueList = "true|false", DefaultValue = "false" - }, - new() - { - Name = "Accept", - Description = Localizer["UploadsAccept"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "BrowserButtonClass", - Description = Localizer["UploadsBrowserButtonClass"], - Type = "string", - ValueList = " — ", - DefaultValue = "btn-primary" - }, - new() - { - Name = "BrowserButtonIcon", - Description = Localizer["UploadsBrowserButtonIcon"], - Type = "string", - ValueList = " — ", - DefaultValue = "fa-regular fa-folder-open" - }, - new() - { - Name = "BrowserButtonText", - Description = Localizer["UploadsBrowserButtonText"], - Type = "string", - ValueList = " — ", - DefaultValue = "" - }, - new() - { - Name = "DefaultFileList", - Description = Localizer["UploadsDefaultFileList"], - Type = "List", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnGetFileFormat", - Description = Localizer["UploadsOnGetFileFormat"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnDelete", - Description = Localizer["UploadsOnDelete"], - Type = "Func>", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnChange", - Description = Localizer["UploadsOnChange"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnDownload", - Description = Localizer["UploadsOnDownload"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "IconTemplate", - Description = Localizer["UploadsIconTemplate"], - Type = "RenderFragment", - ValueList = " — ", - DefaultValue = " — " } ]; } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 99abbe4267f..edfb0a38ab5 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3512,9 +3512,7 @@ "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", "ButtonUploadTitle": "Basic usage", - "ButtonUploadIntro": "", - "UploadClickUploadTips2": "When you set up IsSingle, you can upload only one image or file", - "UploadClickUploadTips3ShowUploadList": "Set ShowUploadFileList value to false as normal button" + "ButtonUploadIntro": "By setting ShowUploadFileList=\"true\" you can display the uploaded file list, and setting ShowDeleteButton=\"true\" you can display the Delete button" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 009cc258c2e..6fbd988c225 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3512,10 +3512,7 @@ "UploadsSubTitle": "通过点击按钮弹出选择文件框进行上传操作文件,通常用作上传文件附件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", - "ButtonUploadIntro": "", - "UploadClickUploadIntro": "ButtonUpload 组件,经典款式,用户点击按钮弹出文件选择框。", - "UploadClickUploadTips2": "设置 IsSingle 时,仅可以上传一张图片或者文件", - "UploadClickUploadTips3ShowUploadList": "设置 ShowUploadFileList 值为 false 组件即与普通按钮一样,可自行处理上传文件逻辑" + "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", From 51eb786caba7444f94e0e398cbc2e9d8a4621fed Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 12:34:59 +0800 Subject: [PATCH 058/177] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor b/src/BootstrapBlazor/Components/Upload/InputUpload.razor index 936fc16693f..7620eb6e71e 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor @@ -11,9 +11,9 @@ @if (ShowDeleteButton) { - } - - + From 3715aa48348dc92aa163a0dbc469fd229d526c4e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 12:35:08 +0800 Subject: [PATCH 059/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor.cs | 8 ++++++++ .../Components/Samples/UploadInputs.razor.cs | 16 ++++++++++++++++ src/BootstrapBlazor.Server/Locales/zh-CN.json | 11 ++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index dcbf27ff402..e2e107dc32d 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -130,6 +130,14 @@ private List GetAttributes() => DefaultValue = "false" }, new() + { + Name = "ShowUploadFileList", + Description = Localizer["UploadsShowUploadFileList"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() { Name = "ShowDownloadButton", Description = Localizer["UploadsShowDownloadButton"], diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs index 35c128beca9..56412699741 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor.cs @@ -31,6 +31,22 @@ private static Task OnSubmit(EditContext context) private List GetAttributes() => [ + new() + { + Name = "IsDirectory", + Description = Localizer["UploadsIsDirectory"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsMultiple", + Description = Localizer["UploadsIsMultiple"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, new() { Name = "ShowDeleteButton", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 6fbd988c225..f8c40b071f9 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3493,6 +3493,9 @@ "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K", "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", "UploadFormSettingsButtonText": "提交", + "UploadsIsMultiple": "是否允许多文件上传", + "UploadsShowProgress": "是否显示上传进度", + "UploadsDefaultFileList": "已上传文件集合", "UploadsShowDeleteButton": "是否显示删除按钮", "UploadsIsDisabled": "是否禁用", "UploadsPlaceHolder": "占位字符串", @@ -3512,7 +3515,13 @@ "UploadsSubTitle": "通过点击按钮弹出选择文件框进行上传操作文件,通常用作上传文件附件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", - "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮" + "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮", + "UploadsIsMultiple": "是否允许多文件上传", + "UploadsShowProgress": "是否显示上传进度", + "UploadsDefaultFileList": "已上传文件集合", + "UploadsAccept": "上传接收的文件格式", + "UploadsOnDelete": "点击删除按钮时回调此方法", + "UploadsOnChange": "点击浏览按钮时回调此方法" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", From b0add020f02220944dce796950af8210b63a46c0 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 12:37:51 +0800 Subject: [PATCH 060/177] =?UTF-8?q?refactor:=20=E6=B6=88=E9=99=A4=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index 627e53b7229..66d3a742ef9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -12,10 +12,10 @@ namespace BootstrapBlazor.Server.Components.Samples; /// public partial class UploadAvatars : IDisposable { - private static long MaxFileLength = 5 * 1024 * 1024; + private static readonly long MaxFileLength = 5 * 1024 * 1024; private CancellationTokenSource? _token; - private List _previewFileList = []; - private Person _foo = new(); + private readonly List _previewFileList = []; + private readonly Person _foo = new(); private bool _isMultiple = true; private bool _isUploadButtonAtFirst; private bool _isCircle; From 7b0d36f95a083cef9876e529e87baee7cb806908 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 17:20:26 +0800 Subject: [PATCH 061/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 8 ++++++++ .../Components/Samples/UploadButtons.razor.cs | 4 ++-- src/BootstrapBlazor.Server/Locales/en-US.json | 17 +++++++++++++++-- src/BootstrapBlazor.Server/Locales/zh-CN.json | 6 +++++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index 66d3a742ef9..ab44352cca0 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -115,6 +115,14 @@ private List GetAttributes() => DefaultValue = " — " }, new() + { + Name = "IsDirectory", + Description = Localizer["UploadsIsDirectory"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() { Name = "IsMultiple", Description = Localizer["UploadsIsMultiple"], diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index e2e107dc32d..a1c59ffb079 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -135,12 +135,12 @@ private List GetAttributes() => Description = Localizer["UploadsShowUploadFileList"], Type = "bool", ValueList = "true|false", - DefaultValue = "false" + DefaultValue = "true" }, new() { Name = "ShowDownloadButton", - Description = Localizer["UploadsShowDownloadButton"], + Description = Localizer["UploadsShowDeleteButton"], Type = "bool", ValueList = "true|false", DefaultValue = "false" diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index edfb0a38ab5..fcb2e30dd51 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3473,6 +3473,7 @@ "UploadsWidth": "The width of the preview box", "UploadsHeight": "The height of the preview box", "UploadsIsCircle": "Whether it is circular avatar mode", + "UploadsIsDirectory": "Whether to upload the entire directory", "UploadsIsMultiple": "Whether to allow multiple file uploads", "UploadsShowProgress": "Whether to display the upload progress", "UploadsDefaultFileList": "The collection of files has been uploaded", @@ -3493,6 +3494,10 @@ "UploadFormSettingsLi1": "Using the ValidateForm form component, custom validation is set by setting the fileValidation label of the model properties to support file extensionsizevalidation, in this case with the extension .png .jpg .jpeg and the file size limit to 50K", "UploadFormSettingsLi2": "After selecting the file and not starting to upload the file, click the submit button to verify that the data is legitimate, and then upload the file OnSubmit callback delegate, noting that the Pictureproperty type is IBrowserFile", "UploadFormSettingsButtonText": "Submit", + "UploadsIsDirectory": "Whether to upload the entire directory", + "UploadsIsMultiple": "Whether to allow multiple file uploads", + "UploadsShowProgress": "Whether to display the upload progress", + "UploadsDefaultFileList": "The collection of files has been uploaded", "UploadsShowDeleteButton": "Whether to display the Delete button", "UploadsIsDisabled": "Whether to disable it", "UploadsPlaceHolder": "The place-in string", @@ -3512,7 +3517,16 @@ "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", "ButtonUploadTitle": "Basic usage", - "ButtonUploadIntro": "By setting ShowUploadFileList=\"true\" you can display the uploaded file list, and setting ShowDeleteButton=\"true\" you can display the Delete button" + "ButtonUploadIntro": "By setting ShowUploadFileList=\"true\" you can display the uploaded file list, and setting ShowDeleteButton=\"true\" you can display the Delete button", + "UploadsIsDirectory": "Whether to upload the entire directory", + "UploadsIsMultiple": "Whether to allow multiple file uploads", + "UploadsShowProgress": "Whether to display the upload progress", + "UploadsDefaultFileList": "The collection of files has been uploaded", + "UploadsShowUploadFileList": "Whether show the upload file list", + "UploadsAccept": "Upload the received file format", + "UploadsShowDeleteButton": "Whether to display the Delete button", + "UploadsOnDelete": "Call back this method when you click the Delete button", + "UploadsOnChange": "Call back this method when you click the Browse button" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", @@ -3553,7 +3567,6 @@ "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", "UploadsShowDownloadButton": "Whether to display the Download button", "UploadsOnDownload": "Call back this method when you click the Download button", - "UploadsIsDirectory": "Whether to upload the entire directory", "UploadsIsSingle": "Whether to upload only once", "UploadsOnGetFileFormat": "Set the file format icon to call back the delegate", "UploadsSuccess": "The upload was successful", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index f8c40b071f9..e11d2e55e4f 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3473,6 +3473,7 @@ "UploadsWidth": "预览框宽度", "UploadsHeight": "预览框高度", "UploadsIsCircle": "是否为圆形头像模式", + "UploadsIsDirectory": "是否上传整个目录", "UploadsIsMultiple": "是否允许多文件上传", "UploadsShowProgress": "是否显示上传进度", "UploadsDefaultFileList": "已上传文件集合", @@ -3493,6 +3494,7 @@ "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K", "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", "UploadFormSettingsButtonText": "提交", + "UploadsIsDirectory": "是否上传整个目录", "UploadsIsMultiple": "是否允许多文件上传", "UploadsShowProgress": "是否显示上传进度", "UploadsDefaultFileList": "已上传文件集合", @@ -3516,10 +3518,13 @@ "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮", + "UploadsIsDirectory": "是否上传整个目录", "UploadsIsMultiple": "是否允许多文件上传", "UploadsShowProgress": "是否显示上传进度", "UploadsDefaultFileList": "已上传文件集合", "UploadsAccept": "上传接收的文件格式", + "UploadsShowUploadFileList": "是否显示上传列表", + "UploadsShowDeleteButton": "是否显示删除按钮", "UploadsOnDelete": "点击删除按钮时回调此方法", "UploadsOnChange": "点击浏览按钮时回调此方法" }, @@ -3558,7 +3563,6 @@ "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", "UploadsShowDownloadButton": "是否显示下载按钮", "UploadsOnDownload": "点击下载按钮时回调此方法", - "UploadsIsDirectory": "是否上传整个目录", "UploadsIsSingle": "是否仅上传一次", "UploadsOnGetFileFormat": "设置文件格式图标回调委托", "UploadsSuccess": "上传成功", From b40364eb45d0b3950468d0ba2f51996e7e87e4b3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 17:52:46 +0800 Subject: [PATCH 062/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=20CardUpload?= =?UTF-8?q?=20=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadCards.razor | 18 ++----- src/BootstrapBlazor.Server/Locales/en-US.json | 47 +++++++++++------ src/BootstrapBlazor.Server/Locales/zh-CN.json | 51 ++++++++++++------- 3 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index 158fe19fd07..912d71d3599 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -1,6 +1,6 @@ @page "/upload-card" @inject IOptionsMonitor WebsiteOption -@inject IStringLocalizer Localizer +@inject IStringLocalizer Localizer @inject ToastService ToastService

@Localizer["UploadsTitle"]

@@ -11,8 +11,8 @@
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
-
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
@@ -21,17 +21,9 @@
@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
+
@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)
-
-
-

@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)

- -
-
-

@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)

- -
-
+
signalR
communication interruption may be triggered. Please adjust the HubOptions configuration.", + "ButtonUploadTitle": "Basic usage", + "ButtonUploadIntro": "Use DefaultFileList to set up uploaded content", + "UploadPreCardStyleTitle": "Preview the card style", + "UploadPreCardStyleIntro": "CardUpload components and rendered in card-style band preview mode", + "UploadPreCardStyleSSR": "SSR mode ", + "UploadPreCardStyleServerSide": "Server Side mode, you can use the IWebHostEnvironment injection service to get to the wwwroot directory and save the file to the images/uploader, which does not require a direct call the controller secondary of MVCSaveToFile method", + "UploadPreCardStyleWasm": "Wasm mode ", + "UploadPreCardStyleWasmSide": "It wasn't available in wasm mode, IWebHostEnvironment needed to save files to the server side by calling webapi interface, and so on", + "UploadPreCardStyleLink": "Interested students can view their knowledge of Upload components through the wiki in the open source repository related resources of the [The portal]", + "UploadPreCardStyleValidation": "In this example, server-side verification prompts the file for too much prompt when the file size exceeds 5MB", + "UploadPreCardStyleTips1": "In this example, the ShowProgress=true display upload progress bar", + "UploadFileIconTitle": "The file icon", + "UploadFileIconIntro": "Icons are displayed in different file formats", + "UploadFileIconTemplateTitle": "Custom file icon", + "UploadFileIconTemplateIntro": "By setting the IconTemplate parameter and using the FileIcon component, you can further customize the file icon [FileIcon example]", + "UploadBase64Title": "Base64 format", + "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", + "UploadsIsDirectory": "Whether to upload the entire directory", + "UploadsIsMultiple": "Whether to allow multiple file uploads", + "UploadsShowProgress": "Whether to display the upload progress", + "UploadsDefaultFileList": "The collection of files has been uploaded", + "UploadsShowUploadFileList": "Whether show the upload file list", + "UploadsAccept": "Upload the received file format", + "UploadsShowDeleteButton": "Whether to display the Delete button", + "UploadsOnDelete": "Call back this method when you click the Delete button", + "UploadsOnChange": "Call back this method when you click the Browse button" + }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", "UploadsSubTitle": "Upload the file by clicking", @@ -3549,22 +3580,6 @@ "UploadedFilesIntro": "Use DefaultFileList to set up uploaded content", "UploadFolderTitle": "Upload a folder", "UploadFolderIntro": "Use DefaultFileList to set up uploaded content", - "UploadPreCardStyleTitle": "Preview the card style", - "UploadPreCardStyleIntro": "CardUpload components and rendered in card-style band preview mode", - "UploadPreCardStyleSSR": "SSR mode ", - "UploadPreCardStyleServerSide": "Server Side mode, you can use the IWebHostEnvironment injection service to get to the wwwroot directory and save the file to the images/uploader, which does not require a direct call the controller secondary of MVCSaveToFile method", - "UploadPreCardStyleWasm": "Wasm mode ", - "UploadPreCardStyleWasmSide": "It wasn't available in wasm mode, IWebHostEnvironment needed to save files to the server side by calling webapi interface, and so on", - "UploadPreCardStyleLink": "Interested students can view their knowledge of Upload components through the wiki in the open source repository related resources of the [The portal]", - "UploadPreCardStyleValidation": "In this example, server-side verification prompts the file for too much prompt when the file size exceeds 5MB", - "UploadPreCardStyleTips1": "In this example, the ShowProgress=true display upload progress bar", - "UploadPreCardStyleTips2": "When you set up IsMultiple=\"false\", you can upload only one image or file", - "UploadFileIconTitle": "The file icon", - "UploadFileIconIntro": "Icons are displayed in different file formats", - "UploadFileIconTemplateTitle": "Custom file icon", - "UploadFileIconTemplateIntro": "By setting the IconTemplate parameter and using the FileIcon component, you can further customize the file icon [FileIcon example]", - "UploadBase64Title": "Base64 format", - "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", "UploadsShowDownloadButton": "Whether to display the Download button", "UploadsOnDownload": "Call back this method when you click the Download button", "UploadsIsSingle": "Whether to upload only once", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index e11d2e55e4f..290621f50a3 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3484,7 +3484,7 @@ }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "InputUpload 上传组件", - "UploadsSubTitle": "通过点击浏览按钮选择一个或者多个文件进行上传", + "UploadsSubTitle": "通过点击浏览按钮弹出选择文件框选择一个或者多个文件进行上传", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "UploadNormalTitle": "基础用法", "UploadNormalIntro": "可以通过设置 ShowDeleteButton=\"true\" 显示 删除 按钮", @@ -3514,7 +3514,7 @@ }, "BootstrapBlazor.Server.Components.Samples.UploadButtons": { "UploadsTitle": "ButtonUpload 按钮上传组件", - "UploadsSubTitle": "通过点击按钮弹出选择文件框进行上传操作文件,通常用作上传文件附件", + "UploadsSubTitle": "通过点击按钮弹出选择文件框选择一个或者多个文件,通常用作上传文件附件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮", @@ -3528,6 +3528,37 @@ "UploadsOnDelete": "点击删除按钮时回调此方法", "UploadsOnChange": "点击浏览按钮时回调此方法" }, + "BootstrapBlazor.Server.Components.Samples.UploadCards": { + "UploadsTitle": "CardUpload 卡片上传组件", + "UploadsSubTitle": "通过点击按钮弹出选择文件框选择一个或者多个文件,呈现为卡片式带预览模式", + "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", + "ButtonUploadTitle": "基础用法", + "ButtonUploadIntro": "使用 DefaultFileList 设置已上传的内容", + "UploadPreCardStyleTitle": "预览卡片式", + "UploadPreCardStyleIntro": "CardUpload 组件,呈现为卡片式带预览模式", + "UploadPreCardStyleSSR": "SSR 模式", + "UploadPreCardStyleServerSide": "Server Side 模式中可以使用 IWebHostEnvironment 注入服务获取到 wwwwroot 目录,保存文件到 images\\uploader 中,此功能无需 MVC 的控制器辅助进行文件的保存,直接调用 SaveToFile 方法即可", + "UploadPreCardStyleWasm": "Wasm 模式", + "UploadPreCardStyleWasmSide": "wasm 模式中无法使用 IWebHostEnvironment 需要调用 webapi 接口等形式将文件保存到服务器端", + "UploadPreCardStyleLink": "有兴趣的同学可以通过开源仓库中的 wiki 文档中相关资源查看关于 Upload 组件的相关知识技巧 [传送门]", + "UploadPreCardStyleValidation": "本例中通过服务器端验证当文件大小超过 5MB 时,提示文件太大提示信息", + "UploadPreCardStyleTips1": "本例中设置 ShowProgress=true 显示上传进度条,通过设置 IsMultiple=\"true\" 允许一次选择多张图片上传", + "UploadFileIconTitle": "文件图标", + "UploadFileIconIntro": "不同文件格式显示的图标不同", + "UploadFileIconTemplateTitle": "自定义文件图标", + "UploadFileIconTemplateIntro": "通过设置 IconTemplate 参数,使用 FileIcon 组件可以对文件图标进行进一步自定义 [FileIcon 示例]", + "UploadBase64Title": "Base64 格式文件", + "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", + "UploadsIsDirectory": "是否上传整个目录", + "UploadsIsMultiple": "是否允许多文件上传", + "UploadsShowProgress": "是否显示上传进度", + "UploadsDefaultFileList": "已上传文件集合", + "UploadsAccept": "上传接收的文件格式", + "UploadsShowUploadFileList": "是否显示上传列表", + "UploadsShowDeleteButton": "是否显示删除按钮", + "UploadsOnDelete": "点击删除按钮时回调此方法", + "UploadsOnChange": "点击浏览按钮时回调此方法" + }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", "UploadsSubTitle": "通过点击上传文件", @@ -3545,22 +3576,6 @@ "UploadedFilesIntro": "使用 DefaultFileList 设置已上传的内容", "UploadFolderTitle": "上传文件夹", "UploadFolderIntro": "使用 DefaultFileList 设置已上传的内容", - "UploadPreCardStyleTitle": "预览卡片式", - "UploadPreCardStyleIntro": "CardUpload 组件,呈现为卡片式带预览模式", - "UploadPreCardStyleSSR": "SSR 模式", - "UploadPreCardStyleServerSide": "Server Side 模式中可以使用 IWebHostEnvironment 注入服务获取到 wwwwroot 目录,保存文件到 images\\uploader 中,此功能无需 MVC 的控制器辅助进行文件的保存,直接调用 SaveToFile 方法即可", - "UploadPreCardStyleWasm": "Wasm 模式", - "UploadPreCardStyleWasmSide": "wasm 模式中无法使用 IWebHostEnvironment 需要调用 webapi 接口等形式将文件保存到服务器端", - "UploadPreCardStyleLink": "有兴趣的同学可以通过开源仓库中的 wiki 文档中相关资源查看关于 Upload 组件的相关知识技巧 [传送门]", - "UploadPreCardStyleValidation": "本例中通过服务器端验证当文件大小超过 5MB 时,提示文件太大提示信息", - "UploadPreCardStyleTips1": "本例中设置 ShowProgress=true 显示上传进度条", - "UploadPreCardStyleTips2": "设置 IsMultiple=\"false\" 时,仅可以上传一张图片或者文件", - "UploadFileIconTitle": "文件图标", - "UploadFileIconIntro": "不同文件格式显示的图标不同", - "UploadFileIconTemplateTitle": "自定义文件图标", - "UploadFileIconTemplateIntro": "通过设置 IconTemplate 参数,使用 FileIcon 组件可以对文件图标进行进一步自定义 [FileIcon 示例]", - "UploadBase64Title": "Base64 格式文件", - "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", "UploadsShowDownloadButton": "是否显示下载按钮", "UploadsOnDownload": "点击下载按钮时回调此方法", "UploadsIsSingle": "是否仅上传一次", From cd5f7e00bc33c80aca55ed55b7a53686bab08e7b Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 17:53:00 +0800 Subject: [PATCH 063/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E9=87=8D?= =?UTF-8?q?=E8=BF=9E=E7=BB=84=E4=BB=B6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Components/BlazorReconnector.razor | 2 +- .../Components/Samples/Reconnectors.razor | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor b/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor index 9034df81a09..0da4ffd7c76 100644 --- a/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor +++ b/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor @@ -67,7 +67,7 @@

一套基于 Bootstrap 样式的企业级 Blazor UI 组件库,支持 Server 与 WebAssembly

-

适配移动端支持各种主流浏览器以及移动端,适配 ABP,同时支持 NET6/NET7/NET8

+

适配移动端支持各种主流浏览器以及移动端,适配 ABP,同时支持 NET6/NET7/NET8/NET9

已提供项目模板方便快速上手 项目模板
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor b/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor index 69444cc93ba..0d0d14d8f01 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor @@ -97,7 +97,7 @@

基于 Bootstrap 样式的 Blazor UI 组件库

-

适配移动端支持各种主流浏览器,适配 ABP,同时支持 NET6/NET7/NET8,交流群 795206915

+

适配移动端支持各种主流浏览器,适配 ABP,同时支持 NET6/NET7/NET8/NET9,交流群 795206915

已提供项目模板方便快速上手 项目模板

@@ -126,7 +126,7 @@ <div class="d-flex"> <div class="flex-fill"> <div class="mb-2">基于 <b>Bootstrap</b> 样式的 <b>Blazor UI</b> 组件库</div> - <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8</b>,交流群 <b>795206915</b></div> + <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8/NET9</b>,交流群 <b>795206915</b></div> <div>已提供项目模板方便快速上手 <a class="connection-link" href="@TemplateUrl">项目模板</a></div> </div> <div class="connection-body-tail d-none d-sm-block"></div> @@ -187,7 +187,7 @@ <div class="d-flex"> <div class="flex-fill"> <div class="mb-2">基于 <b>Bootstrap</b> 样式的 <b>Blazor UI</b> 组件库</div> - <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8</b>,交流群 <b>795206915</b></div> + <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8/NET9</b>,交流群 <b>795206915</b></div> <div>已提供项目模板方便快速上手 <a class="connection-link" href="@TemplateUrl">项目模板</a></div> </div> <div class="connection-body-tail d-none d-sm-block"></div> @@ -248,7 +248,7 @@ <div class="d-flex"> <div class="flex-fill"> <div class="mb-2">基于 <b>Bootstrap</b> 样式的 <b>Blazor UI</b> 组件库</div> - <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8</b>,交流群 <b>795206915</b></div> + <div class="mb-2">适配移动端支持各种主流浏览器,适配 <b>ABP</b>,同时支持 <b>NET6/NET7/NET8/NET9</b>,交流群 <b>795206915</b></div> <div>已提供项目模板方便快速上手 <a class="connection-link" href="@TemplateUrl">项目模板</a></div> </div> <div class="connection-body-tail d-none d-sm-block"></div> From 1de80b9033d08597074dd7bf00382b58344ef4a2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 17 May 2025 18:04:24 +0800 Subject: [PATCH 064/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadCards.razor.cs | 49 ++++++++++++++++++- src/BootstrapBlazor.Server/Locales/en-US.json | 7 +-- src/BootstrapBlazor.Server/Locales/zh-CN.json | 7 +-- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs index e4021f55f7c..3fd49cdb8a4 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs @@ -54,6 +54,53 @@ private async Task OnCardUpload(UploadFile file) private List GetAttributes() => [ - + new() + { + Name = "IsDirectory", + Description = Localizer["UploadsIsDirectory"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsMultiple", + Description = Localizer["UploadsIsMultiple"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "ShowProgress", + Description = Localizer["UploadsShowProgress"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "ShowZoomButton", + Description = Localizer["UploadsShowZoomButton"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "true" + }, + new() + { + Name = "ShowDeletedButton", + Description = Localizer["UploadsShowDeleteButton"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "true" + }, + new() + { + Name = "ShowDownloadButton", + Description = Localizer["UploadsShowDownloadButton"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + } ]; } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 8c9b0f93d33..4ae559aad94 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3552,12 +3552,9 @@ "UploadsIsDirectory": "Whether to upload the entire directory", "UploadsIsMultiple": "Whether to allow multiple file uploads", "UploadsShowProgress": "Whether to display the upload progress", - "UploadsDefaultFileList": "The collection of files has been uploaded", - "UploadsShowUploadFileList": "Whether show the upload file list", - "UploadsAccept": "Upload the received file format", + "UploadsShowZoomButton": "Whether to display the Zoom button", "UploadsShowDeleteButton": "Whether to display the Delete button", - "UploadsOnDelete": "Call back this method when you click the Delete button", - "UploadsOnChange": "Call back this method when you click the Browse button" + "UploadsShowDownloadButton": "Whether to display the Download button" }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 290621f50a3..f5f79c04222 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3552,12 +3552,9 @@ "UploadsIsDirectory": "是否上传整个目录", "UploadsIsMultiple": "是否允许多文件上传", "UploadsShowProgress": "是否显示上传进度", - "UploadsDefaultFileList": "已上传文件集合", - "UploadsAccept": "上传接收的文件格式", - "UploadsShowUploadFileList": "是否显示上传列表", + "UploadsShowZoomButton": "是否显示放大按钮", "UploadsShowDeleteButton": "是否显示删除按钮", - "UploadsOnDelete": "点击删除按钮时回调此方法", - "UploadsOnChange": "点击浏览按钮时回调此方法" + "UploadsShowDownloadButton": "是否显示下载按钮", }, "BootstrapBlazor.Server.Components.Samples.Uploads": { "UploadsTitle": "Upload 上传", From fd3b65db4ab248c493cc87d73cd177e94436c950 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 10:57:04 +0800 Subject: [PATCH 065/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadDrops.razor | 6 +- .../Components/Samples/UploadDrops.razor.cs | 90 ++++++++++++++++++- src/BootstrapBlazor.Server/Locales/en-US.json | 58 ++++-------- src/BootstrapBlazor.Server/Locales/zh-CN.json | 54 ++++------- 4 files changed, 123 insertions(+), 85 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor index 41cec2e04d6..d5cc698e15e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor @@ -1,6 +1,6 @@ @page "/upload-drop" @inject IOptionsMonitor WebsiteOption -@inject IStringLocalizer Localizer +@inject IStringLocalizer Localizer @inject ToastService ToastService

@Localizer["UploadsTitle"]

@@ -11,9 +11,9 @@
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
- + + ShowProgress="true" ShowFooter="true" IsMultiple="false">
@foreach (var file in _dropFiles) { diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs index db3a67c4829..04ffcb6a8e1 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -6,21 +6,103 @@ namespace BootstrapBlazor.Server.Components.Samples; /// -/// DropUpload sampel code +/// DropUpload sample code /// public partial class UploadDrops { private readonly List _dropFiles = []; - private Task OnDropUpload(UploadFile file) + private async Task OnDropUpload(UploadFile file) { + // 模拟保存文件等处理 + await Task.Delay(1000); + + // 添加文件到集合中,用于 UI 呈现上传列表 _dropFiles.Add(file); StateHasChanged(); - return Task.CompletedTask; } private List GetAttributes() => [ - + new() + { + Name = "IsDirectory", + Description = Localizer["UploadsIsDirectory"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "IsMultiple", + Description = Localizer["UploadsIsMultiple"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "BodyTemplate", + Description = Localizer["UploadsBodyTemplate"], + Type = "RenderFragment", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "IconTemplate", + Description = Localizer["UploadsIconTemplate"], + Type = "RenderFragment", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "TextTemplate", + Description = Localizer["UploadsTextTemplate"], + Type = "RenderFragment", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "UploadIcon", + Description = Localizer["UploadsUploadIcon"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "UploadText", + Description = Localizer["UploadsUploadText"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "ShowFooter", + Description = Localizer["UploadsShowFooter"], + Type = "bool", + ValueList = "true|false", + DefaultValue = "false" + }, + new() + { + Name = "FooterTemplate", + Description = Localizer["UploadsFooterTemplate"], + Type = "RenderFragment", + ValueList = " — ", + DefaultValue = " — " + }, + new() + { + Name = "FooterText", + Description = Localizer["UploadsFooterText"], + Type = "string", + ValueList = " — ", + DefaultValue = " — " + } ]; } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 4ae559aad94..94af87061e5 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3556,47 +3556,23 @@ "UploadsShowDeleteButton": "Whether to display the Delete button", "UploadsShowDownloadButton": "Whether to display the Download button" }, - "BootstrapBlazor.Server.Components.Samples.Uploads": { - "UploadsTitle": "Upload", - "UploadsSubTitle": "Upload the file by clicking", - "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", - "UploadNormalTitle": "Basic usage", - "UploadNormalIntro": "The InputUpload component is used with other form components to display the file name, select the file and upload it by clicking the browse button, and by setting the ShowRemoveButton parameter, display the delete button, click the delete button to call back onDelete delegate method", - "UploadNormalLabelPhoto": "Photo:", - "UploadFormSettingsTitle": "FormSettings", - "UploadFormSettingsIntro": "Use the file upload component to constrain the file format within the form", - "UploadFormSettingsLi1": "Using the ValidateForm form component, custom validation is set by setting the fileValidation label of the model properties to support file extensionsizevalidation, in this case with the extension .png .jpg .jpeg and the file size limit to 50K", - "UploadFormSettingsLi2": "After selecting the file and not starting to upload the file, click the submit button to verify that the data is legitimate, and then upload the file OnSubmit callback delegate, noting that the Pictureproperty type is IBrowserFile", - "UploadFormSettingsButtonText": "Submit", - "UploadClickUploadTitle": "Click upload", - "UploadClickUploadIntro": "The ButtonUpload components, classic styles, user click button to pop up the file selection box.", - "UploadClickUploadTips1": "Click on the browse button select file upload, in this case set IsMultiple-true multiple-selectable file can be uploaded", - "UploadClickUploadTips2": "When you set up IsSingle, you can upload only one image or file", - "UploadClickUploadTips3ShowUploadList": "Set ShowUploadFileList value to false as normal button", - "UploadedFilesTitle": "A list of files has been uploaded", - "UploadedFilesIntro": "Use DefaultFileList to set up uploaded content", - "UploadFolderTitle": "Upload a folder", - "UploadFolderIntro": "Use DefaultFileList to set up uploaded content", - "UploadsShowDownloadButton": "Whether to display the Download button", - "UploadsOnDownload": "Call back this method when you click the Download button", - "UploadsIsSingle": "Whether to upload only once", - "UploadsOnGetFileFormat": "Set the file format icon to call back the delegate", - "UploadsSuccess": "The upload was successful", - "UploadsError": "The simulated upload failed", - "UploadsFormatError": "The file format is incorrect", - "UploadsAvatarMsg": "Avatar upload", - "UploadsFileMsg": "Upload the file", - "UploadsFileError": "The file size is greater than 5MB", - "UploadsSaveFileError": "Failed to save the file", - "UploadFile": "Upload the file", - "UploadsWasmError": "Wasm mode does not implement saving code", - "UploadsSaveFile": "Save the file", - "UploadsSaveFileMsg": "The current mode is WebAssembly, call Webapi mode to save files to the server side or database", - "UploadsRemoveMsg": "The removal was successful", - "UploadsIconTemplate": "The template of file icon", - "DropUploadTitle": "Drop to upload", - "DropUploadIntro": "Drag and drop files into the specified area to upload", - "DropUploadFooterText": "file size less than 5Mb" + "BootstrapBlazor.Server.Components.Samples.UploadDrops": { + "UploadsTitle": "CardDrop", + "UploadsSubTitle": "Upload one or more files by clicking on the component or by dragging or pasting", + "UploadsNote": "If the uploaded file is too large, it may trigger signalR communication interruption. Please adjust the HubOptions configuration yourself.", + "DropUploadTitle": "Basic usage", + "DropUploadIntro": "Handle all uploaded files via the OnChange callback", + "DropUploadFooterText": "File size should not exceed 5Mb", + "UploadsIsDirectory": "Whether to upload the entire directory", + "UploadsIsMultiple": "Whether to allow multiple file uploads", + "UploadsBodyTemplate": "Body Template", + "UploadsIconTemplate": "Icon Template", + "UploadsTextTemplate": "Text Template", + "UploadsUploadIcon": "Icon", + "UploadsUploadText": "Text", + "UploadsShowFooter": "Whether to display Footer", + "UploadsFooterTemplate": "Footer Text Template", + "UploadsFooterText": "Footer text" }, "BootstrapBlazor.Server.Components.Samples.ValidateForms": { "ChangeButtonText": "Change", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index f5f79c04222..010bbedd8a3 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3554,45 +3554,25 @@ "UploadsShowProgress": "是否显示上传进度", "UploadsShowZoomButton": "是否显示放大按钮", "UploadsShowDeleteButton": "是否显示删除按钮", - "UploadsShowDownloadButton": "是否显示下载按钮", + "UploadsShowDownloadButton": "是否显示下载按钮" }, - "BootstrapBlazor.Server.Components.Samples.Uploads": { - "UploadsTitle": "Upload 上传", - "UploadsSubTitle": "通过点击上传文件", + "BootstrapBlazor.Server.Components.Samples.UploadDrops": { + "UploadsTitle": "CardDrop 拖拽上传组件", + "UploadsSubTitle": "通过点击组件或者拖拽或者粘贴上传一个或者多个文件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", - "UploadNormalTitle": "基础用法", - "UploadNormalIntro": "InputUpload 组件与其他表单组件一起使用,显示文件名称,点击 浏览 按钮后选择文件并上传;通过设置 ShowRemoveButton 参数,显示 删除 按钮,点击删除按钮时回调 OnDelete 委托方法", - "UploadNormalLabelPhoto": "照片:", - "UploadFormSettingsTitle": "表单应用", - "UploadFormSettingsIntro": "在表单内使用文件上传组件对文件格式进行约束", - "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K", - "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", - "UploadFormSettingsButtonText": "提交", - "UploadClickUploadTitle": "点击上传", - "UploadedFilesTitle": "已上传文件列表", - "UploadedFilesIntro": "使用 DefaultFileList 设置已上传的内容", - "UploadFolderTitle": "上传文件夹", - "UploadFolderIntro": "使用 DefaultFileList 设置已上传的内容", - "UploadsShowDownloadButton": "是否显示下载按钮", - "UploadsOnDownload": "点击下载按钮时回调此方法", - "UploadsIsSingle": "是否仅上传一次", - "UploadsOnGetFileFormat": "设置文件格式图标回调委托", - "UploadsSuccess": "上传成功", - "UploadsError": "模拟上传失败", - "UploadsFormatError": "文件格式不正确", - "UploadsAvatarMsg": "头像上传", - "UploadsFileMsg": "上传文件", - "UploadsFileError": "文件大小超过 5MB", - "UploadsSaveFileError": "保存文件失败", - "UploadFile": "上传文件", - "UploadsWasmError": "Wasm 模式未实现保存代码", - "UploadsSaveFile": "保存文件", - "UploadsSaveFileMsg": "当前模式为 WebAssembly 模式,请调用 Webapi 模式保存文件到服务器端或数据库中", - "UploadsRemoveMsg": "成功移除", - "UploadsIconTemplate": "文件图标模板", - "DropUploadTitle": "拖拽上传", - "DropUploadIntro": "将文件拖拽到特定区域以进行上传", - "DropUploadFooterText": "文件大小不超过 5Mb" + "DropUploadTitle": "基础用法", + "DropUploadIntro": "通过 OnChange 回调处理所有上传文件", + "DropUploadFooterText": "文件大小不超过 5Mb", + "UploadsIsDirectory": "是否上传整个目录", + "UploadsIsMultiple": "是否允许多文件上传", + "UploadsBodyTemplate": "Body 模板", + "UploadsIconTemplate": "图标模板", + "UploadsTextTemplate": "文字模板", + "UploadsUploadIcon": "图标", + "UploadsUploadText": "上传文字", + "UploadsShowFooter": "是否显示 Footer", + "UploadsFooterTemplate": "Footer 字符串模板", + "UploadsFooterText": "Footer 字符串信息" }, "BootstrapBlazor.Server.Components.Samples.ValidateForms": { "ChangeButtonText": "更改组件", From 78c8bf2fab1ff51944ca967f92484a9bb6ecf862 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 11:06:34 +0800 Subject: [PATCH 066/177] =?UTF-8?q?chore:=20=E6=9B=B4=E6=AD=A3=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/docs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/docs.json b/src/BootstrapBlazor.Server/docs.json index 9728a7dcb1a..82bde2ae65c 100644 --- a/src/BootstrapBlazor.Server/docs.json +++ b/src/BootstrapBlazor.Server/docs.json @@ -233,7 +233,7 @@ "typed": "Typeds", "univer-sheet": "UniverSheets", "shield-badge": "ShieldBadges", - "opt-input": "OtpInputs", + "otp-input": "OtpInputs", "otp-service": "OtpServices", "video-device": "VideoDevices", "audio-device": "AudioDevices", From ba128bfacf54f6a6d885d534f6b96f313980eddf Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 11:27:22 +0800 Subject: [PATCH 067/177] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84c089267e6..df0b71c01ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,4 +42,4 @@ jobs: - name: Check Localizer run: | - dotnet test test/UnitTestLocalization + dotnet test test/UnitTest.Localization From 704b32257bb687c2dc3f5304c9b064bcd1b9d88f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:09:32 +0800 Subject: [PATCH 068/177] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 7f16b1196b0..333faf4aa8f 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -133,20 +133,19 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) await OnAllFileUploaded(items); } - var type = NullableUnderlyingType ?? typeof(TValue); - if (type.IsAssignableTo(typeof(IEnumerable))) + if (ValueType.IsAssignableTo(typeof(IEnumerable))) { CurrentValue = (TValue)(object)items.Select(f => f.File).ToList(); } - else if (type.IsAssignableTo(typeof(IEnumerable))) + else if (ValueType.IsAssignableTo(typeof(IEnumerable))) { CurrentValue = (TValue)(object)string.Join(";", items.Select(f => f.OriginFileName)).ToList(); } - else if (type == typeof(IBrowserFile)) + else if (ValueType == typeof(IBrowserFile)) { CurrentValue = (TValue)(object)items[0].File!; } - else if (type == typeof(string)) + else if (ValueType == typeof(string)) { CurrentValue = (TValue)(object)string.Join(";", items.Select(f => f.OriginFileName)); } From 0937de27650302bf2489d8763b35c38c1dd0f9a1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:09:47 +0800 Subject: [PATCH 069/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=80=BC?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 6f45ccabcc8..187d3a91161 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,6 +102,14 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } + /// + /// + /// + protected override string? FormatValueAsString(TValue? value) + { + return CurrentValue?.ToString(); + } + private async Task OnDeleteFile() { foreach (var item in UploadFiles) From 113985584cba39e0a43851fb3c44660872597bb4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:18:04 +0800 Subject: [PATCH 070/177] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E5=AD=97?= =?UTF-8?q?=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exclusion.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/exclusion.dic b/exclusion.dic index fee70b79c99..4820a3c3e44 100644 --- a/exclusion.dic +++ b/exclusion.dic @@ -116,3 +116,4 @@ otpauth Hotp univer rdkit +webkitdirectory From 037a478e9edfd78fff43287e20281b82758fcdb8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:18:24 +0800 Subject: [PATCH 071/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20ValueS?= =?UTF-8?q?tring=20=E6=A0=BC=E5=BC=8F=E5=8C=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor.cs | 8 ------ .../Components/Upload/UploadBase.cs | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 187d3a91161..6f45ccabcc8 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,14 +102,6 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } - /// - /// - /// - protected override string? FormatValueAsString(TValue? value) - { - return CurrentValue?.ToString(); - } - private async Task OnDeleteFile() { foreach (var item in UploadFiles) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 333faf4aa8f..69efd780cad 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -94,6 +94,33 @@ public abstract class UploadBase : ValidateBase, IUpload /// public List UploadFiles { get; } = []; + /// + /// + /// + protected override string? FormatValueAsString(TValue? value) + { + if (value is null) + { + return null; + } + else if (value is IEnumerable files) + { + return string.Join(";", files.Select(i => i.Name)); + } + else if (value is IBrowserFile file) + { + return file.Name; + } + else if (value is IEnumerable strings) + { + return string.Join(";", strings); + } + else + { + return base.FormatValueAsString(value); + } + } + /// /// /// From 734db33372f911fc3a3e5dbfecd739aa74147e26 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:36:12 +0800 Subject: [PATCH 072/177] =?UTF-8?q?refactor:=20=E4=BF=AE=E5=A4=8D=20InputU?= =?UTF-8?q?pload=20=E5=88=A0=E9=99=A4=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadInputs.razor | 4 ++-- .../Components/Upload/InputUpload.razor | 10 +++++++--- .../Components/Upload/InputUpload.razor.cs | 8 +++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor index 0cde718133f..201feac8a82 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadInputs.razor @@ -34,10 +34,10 @@
- +
- +
diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor b/src/BootstrapBlazor/Components/Upload/InputUpload.razor index 7620eb6e71e..1f60de761a1 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor @@ -8,12 +8,16 @@ }
- + @if (ShowDeleteButton) { - + } - +
diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 6f45ccabcc8..b8614897912 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,15 +102,13 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } - private async Task OnDeleteFile() + private async Task TriggerDeleteFile() { - foreach (var item in UploadFiles) + for (var index = UploadFiles.Count; index > 0; index--) { + var item = UploadFiles[index - 1]; await OnFileDelete(item); } - - // TODO: 需要验证文件删除结果 - UploadFiles.Clear(); CurrentValue = default; } From 502ea4fe94a985df7c2e6ae58099078647b3b551 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:42:32 +0800 Subject: [PATCH 073/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=96=87=E4=BB=B6=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs | 6 +++--- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index b8614897912..51caac8f22d 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -104,9 +104,10 @@ protected override void OnParametersSet() private async Task TriggerDeleteFile() { - for (var index = UploadFiles.Count; index > 0; index--) + var files = GetUploadFiles(); + for (var index = files.Count; index > 0; index--) { - var item = UploadFiles[index - 1]; + var item = files[index - 1]; await OnFileDelete(item); } CurrentValue = default; @@ -115,7 +116,6 @@ private async Task TriggerDeleteFile() /// /// /// - /// public override void ToggleMessage(IEnumerable results) { if (results.Any()) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 69efd780cad..b8d49b71482 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -194,11 +194,11 @@ protected virtual async Task OnFileDelete(UploadFile item) if (ret) { - UploadFiles.Remove(item); if (!string.IsNullOrEmpty(item.ValidateId)) { await RemoveValidResult(item.ValidateId); } + UploadFiles.Remove(item); DefaultFileList?.Remove(item); } return ret; @@ -243,7 +243,8 @@ protected virtual bool CheckCanUpload() } /// - /// 获得当前图片集合 + /// Get the files collection. + /// 获得当前文件集合 /// /// protected List GetUploadFiles() From a8635354dd2098b31bb0f922c0432c7293723fc3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 12:46:19 +0800 Subject: [PATCH 074/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Locales/en-US.json | 2 +- src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 94af87061e5..51e53e47cdf 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3491,7 +3491,7 @@ "UploadNormalLabelPhoto": "Select one or more files", "UploadFormSettingsTitle": "ValidateForm", "UploadFormSettingsIntro": "Use the file upload component to constrain the file format within the form", - "UploadFormSettingsLi1": "Using the ValidateForm form component, custom validation is set by setting the fileValidation label of the model properties to support file extensionsizevalidation, in this case with the extension .png .jpg .jpeg and the file size limit to 50K", + "UploadFormSettingsLi1": "Using the ValidateForm form component, custom validation is set by setting the fileValidation label of the model properties to support file extensionsizevalidation, in this case with the extension .png .jpg .jpeg and the file size limit to 5M", "UploadFormSettingsLi2": "After selecting the file and not starting to upload the file, click the submit button to verify that the data is legitimate, and then upload the file OnSubmit callback delegate, noting that the Pictureproperty type is IBrowserFile", "UploadFormSettingsButtonText": "Submit", "UploadsIsDirectory": "Whether to upload the entire directory", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 010bbedd8a3..388e35f2f43 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3491,7 +3491,7 @@ "UploadNormalLabelPhoto": "选择一个或者多个文件", "UploadFormSettingsTitle": "表单应用", "UploadFormSettingsIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件", - "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K", + "UploadFormSettingsLi1": "使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 5M", "UploadFormSettingsLi2": "选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile", "UploadFormSettingsButtonText": "提交", "UploadsIsDirectory": "是否上传整个目录", From 62437c1ee4d8717164b5ce73d75276e84f97c52a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 13:02:43 +0800 Subject: [PATCH 075/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadInput.cs | 167 ++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 test/UnitTest/Components/UploadInput.cs diff --git a/test/UnitTest/Components/UploadInput.cs b/test/UnitTest/Components/UploadInput.cs new file mode 100644 index 00000000000..d4bb02a5a80 --- /dev/null +++ b/test/UnitTest/Components/UploadInput.cs @@ -0,0 +1,167 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; + +namespace UnitTest.Components; + +public class UploadInputTest : BootstrapBlazorTestBase +{ + [Fact] + public async Task InputUpload_Ok() + { + UploadFile? uploadFile = null; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.PlaceHolder, "TestPlaceHolder"); + pb.Add(a => a.OnChange, file => + { + uploadFile = file; + return Task.CompletedTask; + }); + pb.Add(a => a.Value, "test.jpg"); + }); + cut.Contains("value=\"test.jpg\""); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + Assert.Equal("UploadTestFile", uploadFile!.OriginFileName); + cut.Contains("fa-regular fa-folder-open"); + cut.Contains("btn-primary"); + cut.Contains("TestPlaceHolder"); + + // 参数 + cut.SetParametersAndRender(pb => pb.Add(a => a.BrowserButtonIcon, "fa-solid fa-chrome")); + cut.Contains("fa-solid fa-chrome"); + + cut.SetParametersAndRender(pb => pb.Add(a => a.BrowserButtonClass, "btn btn-browser")); + cut.Contains("btn btn-browser"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ShowDeleteButton, true); + pb.Add(a => a.DeleteButtonText, "Delete-Test"); + pb.Add(a => a.DeleteButtonIcon, "fa-solid fa-trash"); + }); + cut.WaitForAssertion(() => cut.Contains("fa-solid fa-trash")); + cut.Contains("btn-danger"); + + // 删除逻辑 + var deleted = false; + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DeleteButtonClass, "btn btn-delete"); + pb.Add(a => a.OnDelete, file => + { + deleted = true; + return Task.FromResult(true); + }); + }); + cut.WaitForAssertion(() => cut.Contains("btn btn-delete")); + + var button = cut.Find(".input-group button"); + await cut.InvokeAsync(() => button.Click()); + Assert.True(deleted); + + // IsDisable + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, true); + }); + cut.WaitForAssertion(() => cut.Contains("btn btn-delete")); + } + + [Fact] + public async Task InputUpload_ValidateForm_Ok() + { + var invalid = false; + var foo = new Foo(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, foo.Name); + pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + }); + pb.Add(a => a.OnValidSubmit, context => + { + invalid = false; + return Task.CompletedTask; + }); + pb.Add(a => a.OnInvalidSubmit, context => + { + invalid = true; + return Task.CompletedTask; + }); + }); + + // 提交表单 + var form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.True(invalid); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + await cut.InvokeAsync(() => form.Submit()); + Assert.False(invalid); + } + + [Fact] + public void InputUpload_FileValidate_OK() + { + var foo = new Person(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, foo.Picture); + pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, nameof(Person.Picture), typeof(IBrowserFile))); + }); + }); + + var input = cut.FindComponent(); + cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + + // 提交表单 + var form = cut.Find("form"); + cut.InvokeAsync(() => form.Submit()); + } + + private class Person + { + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] + + public IBrowserFile? Picture { get; set; } + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} From 39a5dfaa49a83323da83d61b93be0d06c5df26d5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 14:32:35 +0800 Subject: [PATCH 076/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20UploadInpu?= =?UTF-8?q?tTest=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/{UploadInput.cs => UploadInputTest.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/UnitTest/Components/{UploadInput.cs => UploadInputTest.cs} (100%) diff --git a/test/UnitTest/Components/UploadInput.cs b/test/UnitTest/Components/UploadInputTest.cs similarity index 100% rename from test/UnitTest/Components/UploadInput.cs rename to test/UnitTest/Components/UploadInputTest.cs From 648c771ab27634c029edf6362b637918b2605ea1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 14:48:11 +0800 Subject: [PATCH 077/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor | 2 +- .../Components/Samples/UploadButtons.razor.cs | 71 +++++++++---------- .../Components/Upload/ButtonUpload.razor | 8 +-- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor index c7b7f589b3a..4230691f222 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -57,7 +57,7 @@ + OnChange="@OnClickToUpload" OnDownload="OnDownload"> diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index a1c59ffb079..9bd75a6eda0 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -8,11 +8,11 @@ namespace BootstrapBlazor.Server.Components.Samples; /// /// ButtonUpload sample code /// -public partial class UploadButtons +public partial class UploadButtons : IDisposable { private static readonly Random Random = new(); - private CancellationTokenSource? ReadToken { get; set; } - private static long MaxFileLength => 5 * 1024 * 1024; + private static readonly long MaxFileLength = 5 * 1024 * 1024; + private CancellationTokenSource? _token; private bool _isMultiple = true; private bool _showProgress = true; @@ -21,20 +21,6 @@ public partial class UploadButtons private bool _isDirectory = false; private bool _isDisabled = false; - private List DefaultFormatFileList { get; } = - [ - new() { FileName = "Test.xls" }, - new() { FileName = "Test.doc" }, - new() { FileName = "Test.ppt" }, - new() { FileName = "Test.mp3" }, - new() { FileName = "Test.mp4" }, - new() { FileName = "Test.pdf" }, - new() { FileName = "Test.cs" }, - new() { FileName = "Test.zip" }, - new() { FileName = "Test.txt" }, - new() { FileName = "Test.dat" } - ]; - private async Task OnClickToUpload(UploadFile file) { // 示例代码,模拟 80% 几率保存成功 @@ -50,17 +36,6 @@ private async Task OnClickToUpload(UploadFile file) } } - private async Task OnClickToUploadNoUploadList(UploadFile file) - { - await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success."); - } - - private async Task OnUploadFolder(UploadFile file) - { - // 上传文件夹时会多次回调此方法 - await SaveToFile(file); - } - private async Task OnDownload(UploadFile item) { await ToastService.Success("文件下载", $"下载 {item.FileName} 成功"); @@ -79,20 +54,27 @@ private async Task SaveToFile(UploadFile file) $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; var fileName = Path.Combine(uploaderFolder, file.FileName); - ReadToken ??= new CancellationTokenSource(); - var ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token); - - if (ret) + _token ??= new CancellationTokenSource(); + try { - // 保存成功 - file.PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/uploader/{file.FileName}"; + var ret = await file.SaveToFileAsync(fileName, MaxFileLength, _token.Token); + + if (ret) + { + // 保存成功 + file.PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/uploader/{file.FileName}"; + } + else + { + var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}"; + file.Code = 1; + file.Error = errorMessage; + await ToastService.Error(Localizer["UploadFile"], errorMessage); + } } - else + catch (OperationCanceledException) { - var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}"; - file.Code = 1; - file.Error = errorMessage; - await ToastService.Error(Localizer["UploadFile"], errorMessage); + } } else @@ -103,6 +85,17 @@ private async Task SaveToFile(UploadFile file) } } + /// + /// + /// + public void Dispose() + { + _token?.Cancel(); + _token?.Dispose(); + _token = null; + GC.SuppressFinalize(this); + } + private List GetAttributes() => [ new() diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 73d251623b2..77fd9fe1dec 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -30,12 +30,12 @@ else {
- @if (ShowDownloadButton) - { - - } @if (item.Code == 0) { + @if (ShowDownloadButton) + { + + } @if (!IsDisabled) { From 4126a72e278ea171f51f14fd6fa2a477de64895d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 14:48:20 +0800 Subject: [PATCH 078/177] =?UTF-8?q?test:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadInputTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index d4bb02a5a80..24272fce41f 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -145,7 +145,6 @@ private class Person { [Required] [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] - public IBrowserFile? Picture { get; set; } } From 5fcbb88e89e1e1c3cc12f309ea287c80a3c83a4f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 15:09:02 +0800 Subject: [PATCH 079/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20ButtonUplo?= =?UTF-8?q?ad=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor.cs | 34 +- test/UnitTest/Components/UploadButtonTest.cs | 384 ++++++++++++++++++ 2 files changed, 400 insertions(+), 18 deletions(-) create mode 100644 test/UnitTest/Components/UploadButtonTest.cs diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index d09725c9e78..33e20a50b88 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -295,25 +295,23 @@ private async Task OnClickCancel(UploadFile item) { fileExtension = fileExtension.ToLowerInvariant(); } - var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(); + var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(fileExtension); builder.AddClass(icon); return builder.Build(); - - // switch 关键字导致无法 100% 覆盖 - [ExcludeFromCodeCoverage] - string? GetFileExtensions() => fileExtension switch - { - ".csv" or ".xls" or ".xlsx" => FileIconExcel, - ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, - ".ppt" or ".pptx" => FileIconPPT, - ".wav" or ".mp3" => FileIconAudio, - ".mp4" or ".mov" or ".mkv" => FileIconVideo, - ".cs" or ".html" or ".vb" => FileIconCode, - ".pdf" => FileIconPdf, - ".zip" or ".rar" or ".iso" => FileIconZip, - ".txt" or ".log" => FileIconArchive, - ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, - _ => FileIconFile - }; } + + private string? GetFileExtensions(string? fileExtension) => fileExtension switch + { + ".csv" or ".xls" or ".xlsx" => FileIconExcel, + ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, + ".ppt" or ".pptx" => FileIconPPT, + ".wav" or ".mp3" => FileIconAudio, + ".mp4" or ".mov" or ".mkv" => FileIconVideo, + ".cs" or ".html" or ".vb" => FileIconCode, + ".pdf" => FileIconPdf, + ".zip" or ".rar" or ".iso" => FileIconZip, + ".txt" or ".log" => FileIconArchive, + ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, + _ => FileIconFile + }; } diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs new file mode 100644 index 00000000000..ed553b25c4c --- /dev/null +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -0,0 +1,384 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; + +namespace UnitTest.Components; + +public class UploadButtonTest : BootstrapBlazorTestBase +{ + [Fact] + public async Task ButtonUpload_Ok() + { + UploadFile? uploadFile = null; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.BrowserButtonClass, "browser-class"); + pb.Add(a => a.BrowserButtonIcon, "fa-solid fa-chrome"); + pb.Add(a => a.BrowserButtonColor, Color.Success); + }); + cut.Contains("fa-solid fa-chrome"); + cut.Contains("browser-class"); + cut.Contains("btn btn-success"); + cut.DoesNotContain("form-label"); + + // DefaultFileList + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, file => + { + uploadFile = file; + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + cut.DoesNotContain("cancel-icon"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.Size, Size.ExtraSmall); + }); + cut.Contains("btn-xs"); + } + + [Fact] + public void ButtonUpload_ChildContent() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ChildContent, builder => builder.AddContent(0, new MarkupString("
test-child-content
"))); + }); + cut.Contains("
test-child-content
"); + } + + [Fact] + public void ButtonUpload_IsDisabled_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsDisabled, true); + }); + var button = cut.Find(".btn-browser"); + Assert.Contains("disabled=\"disabled\"", button.ToMarkup()); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, false); + pb.Add(a => a.IsMultiple, true); + }); + Assert.DoesNotContain("disabled=\"disabled\"", button.ToMarkup()); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, false); + pb.Add(a => a.IsMultiple, false); + }); + Assert.DoesNotContain("disabled=\"disabled\"", button.ToMarkup()); + } + + [Fact] + public void ButtonUpload_ValidateForm_Ok() + { + var foo = new Foo(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, foo.Name); + pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + }); + }); + cut.Contains("form-label"); + + // ValidateId 为空情况 + var uploader = cut.FindComponent>(); + var pi = typeof(ButtonUpload).GetProperty("UploadFiles", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + Assert.NotNull(pi); + var filesValue = pi.GetValue(uploader.Instance); + + if (filesValue is List fs) + { + fs.Add(new UploadFile()); + } + + var results = new List() + { + new("test", ["bb_validate_123"]) + }; + uploader.Instance.ToggleMessage(results); + } + + [Fact] + public async Task ButtonUpload_ShowDownload() + { + var clicked = false; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowDownloadButton, true); + pb.Add(a => a.OnDownload, file => + { + clicked = true; + return Task.CompletedTask; + }); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File1.text" } + ]); + }); + + var button = cut.Find(".fa-download"); + await cut.InvokeAsync(() => button.Click()); + Assert.True(clicked); + } + + [Fact] + public async Task ButtonUpload_Validate_Ok() + { + var invalid = true; + var foo = new Foo + { + Name = "abc" + }; + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Accept, "Image"); + pb.Add(a => a.Value, foo.Name); + pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + }); + pb.Add(a => a.OnValidSubmit, context => + { + invalid = false; + return Task.CompletedTask; + }); + }); + + // 由于设置了属性 Name 值 Validate 方法通过 + var form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.False(invalid); + } + + [Fact] + public void ShowUploadList_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Accept, "Image"); + }); + + cut.Contains("upload-body is-list"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ShowUploadFileList, false); + }); + cut.WaitForState(() => !cut.Markup.Contains("upload-body is-list")); + cut.DoesNotContain("upload-body is-list"); + } + + [Fact] + public async Task ButtonUpload_OnDeleteFile_Ok() + { + UploadFile? deleteFile = null; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File" } + ]); + pb.Add(a => a.OnDelete, file => + { + deleteFile = file; + return Task.FromResult(true); + }); + }); + await cut.InvokeAsync(() => cut.Find(".delete-icon").Click()); + Assert.NotNull(deleteFile); + Assert.Null(deleteFile!.Error); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, null); + }); + // 增加代码覆盖率 + var ins = cut.Instance; + var pi = ins.GetType().GetMethod("OnFileDelete", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; + pi.Invoke(ins, [new UploadFile()]); + + deleteFile = null; + // 上传失败测试 + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File2", Code = 1001 } + ]); + }); + await cut.InvokeAsync(() => cut.Find(".delete-icon").Click()); + Assert.NotNull(deleteFile); + } + + [Fact] + public async Task ButtonUpload_ShowProgress_Ok() + { + var cancel = false; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async file => + { + await Task.Delay(100); + await file.SaveToFileAsync("1.txt"); + }); + pb.Add(a => a.OnCancel, file => + { + cancel = true; + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(async () => + { + _ = input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + })); + + var button = cut.Find(".cancel-icon"); + Assert.NotNull(button); + await cut.InvokeAsync(() => button.Click()); + Assert.True(cancel); + }); + } + + [Fact] + public async Task ButtonUpload_IsDirectory_Ok() + { + var fileCount = 0; + var fileNames = new List(); + List fileList = []; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsDirectory, true); + pb.Add(a => a.OnChange, file => + { + fileCount = file.FileCount; + fileNames.Add(file.OriginFileName!); + return Task.CompletedTask; + }); + pb.Add(a => a.OnAllFileUploaded, files => + { + fileList.AddRange(files); + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new(), + new("UploadTestFile2") + }))); + Assert.Equal(2, fileCount); + Assert.Equal(2, fileNames.Count); + Assert.Equal(2, fileList.Count); + } + + [Fact] + public void ButtonUpload_Accept_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Accept, ".jpg"); + }); + cut.Contains("accept=\".jpg\""); + } + + [Fact] + public void ButtonUpload_OnGetFileFormat_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "1.csv" }, + new() { FileName = "1.xls" }, + new() { FileName = "1.xlsx" }, + new() { FileName = "1.doc" }, + new() { FileName = "1.docx" }, + new() { FileName = "1.dot" }, + new() { FileName = "1.ppt" }, + new() { FileName = "1.pptx" }, + new() { FileName = "1.wav" }, + new() { FileName = "1.mp3" }, + new() { FileName = "1.mp4" }, + new() { FileName = "1.mov" }, + new() { FileName = "1.mkv" }, + new() { FileName = "1.cs" }, + new() { FileName = "1.html" }, + new() { FileName = "1.vb" }, + new() { FileName = "1.pdf" }, + new() { FileName = "1.zip" }, + new() { FileName = "1.rar" }, + new() { FileName = "1.iso" }, + new() { FileName = "1.txt" }, + new() { FileName = "1.log" }, + new() { FileName = "1.jpg" }, + new() { FileName = "1.jpeg" }, + new() { FileName = "1.png" }, + new() { FileName = "1.bmp" }, + new() { FileName = "1.gif" }, + new() { FileName = "1.test" }, + new() { FileName = "1" } + ]); + }); + cut.Contains("fa-regular fa-file-excel"); + cut.Contains("fa-regular fa-file-word"); + cut.Contains("fa-regular fa-file-powerpoint"); + cut.Contains("fa-regular fa-file-audio"); + cut.Contains("fa-regular fa-file-video"); + cut.Contains("fa-regular fa-file-code"); + cut.Contains("fa-regular fa-file-pdf"); + cut.Contains("fa-regular fa-file-archive"); + cut.Contains("fa-regular fa-file-text"); + cut.Contains("fa-regular fa-file-image"); + cut.Contains("fa-regular fa-file"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.OnGetFileFormat, extensions => + { + return "fa-format-test"; + }); + }); + cut.Contains("fa-format-test"); + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} From 3e344aded107818061ac89de1103151c595b46b5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 15:46:56 +0800 Subject: [PATCH 080/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 2 +- .../Components/Upload/AvatarUpload.razor.cs | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 0540a83ca39..64bae059de7 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -50,7 +50,7 @@ @code { RenderFragment RenderAdd => @
-
+
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 917f861d089..f426e52cd7e 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -79,11 +79,10 @@ public partial class AvatarUpload .Build(); private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", !IsDisabled && item.IsValid.HasValue && item.IsValid.Value) - .AddClass("is-invalid", !IsDisabled && item.IsValid.HasValue && !item.IsValid.Value) - .AddClass("is-valid", !IsDisabled && !item.IsValid.HasValue && item.Uploaded && item.Code == 0) - .AddClass("is-invalid", !IsDisabled && !item.IsValid.HasValue && item.Code != 0) - .AddClass("disabled", IsDisabled) + .AddClass("is-valid", !IsDisabled && item.IsValid is true) + .AddClass("is-invalid", !IsDisabled && item.IsValid is false) + .AddClass("is-valid", !IsDisabled && item is { IsValid: null, Uploaded: true, Code: 0 }) + .AddClass("is-invalid", !IsDisabled && item is { IsValid: null, Code: not 0 }) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") @@ -102,6 +101,10 @@ public partial class AvatarUpload .AddClass($"--bb-upload-item-border-radius: {BorderRadius};", IsCircle && !string.IsNullOrEmpty(BorderRadius)) .Build(); + private string? ActionClassString => CssBuilder.Default("upload-item-actions") + .AddClass("btn-browser", IsDisabled == false) + .Build(); + private string? ValidStatusIconString => CssBuilder.Default("valid-icon valid") .AddClass(ValidStatusIcon) .Build(); From 9ee2d2dd70e9b4eeb745f2f2b1d9d1df3a7d7d67 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 15:47:04 +0800 Subject: [PATCH 081/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadAvatarTest.cs | 151 +++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 test/UnitTest/Components/UploadAvatarTest.cs diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs new file mode 100644 index 00000000000..b9b91a40a20 --- /dev/null +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; + +namespace UnitTest.Components; + +public class UploadAvatarTest : BootstrapBlazorTestBase +{ + [Fact] + public async Task AvatarUpload_Ok() + { + UploadFile? uploadFile = null; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.OnChange, file => + { + uploadFile = file; + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + + // Height/Width + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.Height, 40); + pb.Add(a => a.Width, 50); + }); + cut.Contains("width: 50px;"); + cut.Contains("height: 40px;"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsCircle, true); + }); + cut.Contains("height: 50px;"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.Height, 0); + }); + cut.Contains("height: 50px;"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.BorderRadius, "10px"); + }); + cut.Contains("--bb-upload-item-border-radius: 10px;"); + + // DefaultFileList + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.OnChange, null); + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File" } + ]); + }); + input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + + // upload-item-delete + var button = cut.Find(".upload-item-delete"); + await cut.InvokeAsync(() => button.Click()); + + cut.Contains("upload-item-actions btn-browser"); + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, true); + }); + cut.Contains("upload-item-actions"); + + // IsUploadButtonAtFirst + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsUploadButtonAtFirst, true); + }); + } + + [Fact] + public async Task AvatarUpload_ValidateForm_Ok() + { + var invalid = false; + var foo = new Foo(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Accept, "Image"); + pb.Add(a => a.Value, foo.Name); + pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + }); + pb.Add(a => a.OnValidSubmit, context => + { + invalid = false; + return Task.CompletedTask; + }); + pb.Add(a => a.OnInvalidSubmit, context => + { + invalid = true; + return Task.CompletedTask; + }); + }); + + // 提交表单 + var form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.True(invalid); + + var input = cut.FindComponent(); + await cut.InvokeAsync(async () => + { + await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + })); + form.Submit(); + }); + Assert.False(invalid); + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} From 275e721c82ded779485b7cb9653f0232cac65312 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 15:47:17 +0800 Subject: [PATCH 082/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 9 ++++++++- .../Components/Samples/UploadAvatars.razor.cs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index 7ca511898fc..0f753735014 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -40,9 +40,16 @@
+
+ + + + +
- + $"{_radius}px"; From bc714ae487f0d737c6a5726f82bc25ec08fdfcbc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 16:39:11 +0800 Subject: [PATCH 083/177] =?UTF-8?q?refactor:=20=E7=B2=BE=E7=AE=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BD=BF=E7=94=A8=E7=88=B6=E7=B1=BB=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor | 2 +- .../Components/Upload/InputUpload.razor.cs | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor b/src/BootstrapBlazor/Components/Upload/InputUpload.razor index 1f60de761a1..41b836ac0cf 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor @@ -8,7 +8,7 @@ }
- @if (ShowDeleteButton) { diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 51caac8f22d..645436914e2 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -112,22 +112,4 @@ private async Task TriggerDeleteFile() } CurrentValue = default; } - - /// - /// - /// - public override void ToggleMessage(IEnumerable results) - { - if (results.Any()) - { - ErrorMessage = results.First().ErrorMessage; - IsValid = false; - } - else - { - ErrorMessage = null; - IsValid = true; - } - OnValidate(IsValid); - } } From 1e589b6e7b162c3b24d5c1b4c2a21ae429544a93 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 16:39:26 +0800 Subject: [PATCH 084/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Validate/ValidateBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs index 6245ba47840..5f2c2a55e4c 100644 --- a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs +++ b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs @@ -464,8 +464,8 @@ public virtual void ToggleMessage(IEnumerable results) { if (FieldIdentifier != null) { - var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.Value.FieldName)); - if (messages.Any()) + var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.Value.FieldName)).ToList(); + if (messages.Count > 0) { ErrorMessage = messages.First().ErrorMessage; IsValid = false; From 2914daf43385d4d97d85f1cd16b9c0b525573ddb Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 16:39:41 +0800 Subject: [PATCH 085/177] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=20Validate?= =?UTF-8?q?=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadBase.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index b8d49b71482..ec9e0091059 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -276,26 +276,24 @@ public override void ToggleMessage(IEnumerable results) { if (FieldIdentifier != null) { - var messages = results.Where(item => item.MemberNames.Any(m => UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false))); - if (messages.Any()) + var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.Value.FieldName)).ToList(); + if (messages.Count == 0) { + messages = results.Where(item => item.MemberNames.Any(m => + UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false))) + .ToList(); + } + if (messages.Count > 0) + { + ErrorMessage = messages.First().ErrorMessage; IsValid = false; - - // TODO: 提示 - //if (CurrentFile != null) - //{ - // var msg = messages.FirstOrDefault(m => m.MemberNames.Any(f => f.Equals(CurrentFile.ValidateId, StringComparison.OrdinalIgnoreCase))); - // if (msg != null) - // { - // ErrorMessage = msg.ErrorMessage; - // } - //} } else { ErrorMessage = null; IsValid = true; } + OnValidate(IsValid); } } From 22f2e2419b28c6a896c17631f2a2ffd2dfb45f49 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 17:42:36 +0800 Subject: [PATCH 086/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E9=AA=8C=E8=AF=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Locales/en-US.json | 2 +- src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 +- .../Components/Upload/AvatarUpload.razor | 4 +- .../Components/Upload/AvatarUpload.razor.cs | 47 ++++++++++++++----- .../Components/Upload/ButtonUpload.razor.cs | 2 +- .../Components/Upload/CardUpload.razor.cs | 1 - .../Components/Upload/InputUpload.razor.scss | 4 -- .../Components/Upload/UploadBase.cs | 25 ++++++---- 8 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 5252b643958..fe9b6cd330e 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3468,7 +3468,7 @@ "AvatarUploadTips7": "Verify that an example of using a picture box is used in the form", "AvatarUploadButtonText": "Submit", "AvatarUploadValidateTitle": "ValidateForm", - "AvatarUploadValidateIntro": "Place it in ValidateForm to integrate automatic data validation function. For details, please refer to ValidateForm component", + "AvatarUploadValidateIntro": "Place it in ValidateForm to integrate automatic data validation function. For details, please refer to ValidateForm component. In this example, the uploaded file extension is limited to .png, .jpg, .jpeg. An error message will be displayed when uploading other formats. The file size limit is 5M. An error message will also be displayed when it exceeds", "AvatarUploadAcceptTitle": "Accept", "AvatarUploadAcceptIntro": "The component provides Accept property for upload file filtering, in this case the circular avatar box accepts both GIF and JPEG images, sets the Accept='image/gif, image/jpeg' and can be written as: Accept='image/*' if you don't restrict the format of the image. Whether this property is not secure or should be to file format validation using the server-side authentication", "UploadsWidth": "The width of the preview box", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index eb3e954364e..0a683c7a8dd 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3468,7 +3468,7 @@ "AvatarUploadTips7": "验证表单内使用头像框示例", "AvatarUploadButtonText": "提交", "AvatarUploadValidateTitle": "ValidateForm", - "AvatarUploadValidateIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件", + "AvatarUploadValidateIntro": "放置到 ValidateForm 内集成自动数据验证功能,详情可以参考 ValidateForm 组件,本例中上传文件扩展名仅限制为 .png, .jpg, .jpeg,上传其他格式时会有错误提示,文件大小限制为 5M 超过时也会有错误提示显示", "AvatarUploadAcceptTitle": "Accept", "AvatarUploadAcceptIntro": "组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept='image/gif, image/jpeg',如果不限制图像的格式,可以写为:Accept='image/*',该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证", "UploadsWidth": "预览框宽度", diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 64bae059de7..0ddc92abd6f 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -14,7 +14,7 @@ } @foreach (var item in GetUploadFiles()) { -
+
@if (!IsDisabled) { @@ -49,7 +49,7 @@ @code { RenderFragment RenderAdd => - @
+ @
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index f426e52cd7e..ba99bd9f007 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -78,19 +78,28 @@ public partial class AvatarUpload .AddClassFromAttributes(AdditionalAttributes) .Build(); - private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", !IsDisabled && item.IsValid is true) - .AddClass("is-invalid", !IsDisabled && item.IsValid is false) - .AddClass("is-valid", !IsDisabled && item is { IsValid: null, Uploaded: true, Code: 0 }) - .AddClass("is-invalid", !IsDisabled && item is { IsValid: null, Code: not 0 }) - .Build(); - - private string? ItemClassString => CssBuilder.Default("upload-item") + private string? GetItemClassString(UploadFile? item = null) => CssBuilder.Default("upload-item") .AddClass("is-circle", IsCircle) - .AddClass("is-single", IsMultiple == false) .AddClass("disabled", IsDisabled) + .AddClass(GetValidStatus(item)) .Build(); + private string? GetValidStatus(UploadFile? item = null) + { + if (ValidateForm == null) + { + return null; + } + + if (IsDisabled) + { + return null; + } + + var state = item?.IsValid ?? IsValid; + return state is true ? "is-valid" : "is-invalid"; + } + /// /// 获得/设置 预览框 Style 属性 /// @@ -127,11 +136,11 @@ protected override void OnParametersSet() InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadInvalidStatusIcon); // 头像上传时如果用户没有设置 OnChanged 回调,需要使用内置方法将文件头像转化未 Base64 格式用于预览 - OnChange ??= new Func(async item => + OnChange ??= async item => { item.ValidateId = $"{Id}_{item.GetHashCode()}"; await item.RequestBase64ImageFileAsync(); - }); + }; } /// @@ -141,12 +150,24 @@ protected override void OnParametersSet() protected override bool CheckCanUpload() { // 允许多上传 - if (IsMultiple == true) + if (IsMultiple) { - return true; + return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; } // 只允许单个上传 return UploadFiles.Count == 0; } + + /// + /// 获得 数据验证客户端 ID + /// + /// + protected override string? RetrieveId() + { + var files = GetUploadFiles(); + return files.Count == 0 ? $"{Id}_new" : files[0].ValidateId; + } + + private string? AddId => GetUploadFiles().Count == 0 ? $"{Id}_new" : null; } diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 33e20a50b88..45a0ad2b33e 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -194,7 +194,7 @@ public partial class ButtonUpload .Build(); private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item.Uploaded && item.Code == 0) + .AddClass("is-valid", item is { Uploaded: true, Code: 0 }) .AddClass("is-invalid", item.Code != 0) .Build(); diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 24c04f4894b..b06b66862a5 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -19,7 +19,6 @@ public partial class CardUpload .AddClass("is-invalid", item.Code != 0) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") - .AddClass("is-single", IsMultiple == false) .AddClass("disabled", IsDisabled) .Build(); diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 4a3f0c03f24..9f9db7525fe 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -115,10 +115,6 @@ cursor: pointer; } -.upload .upload-body.is-avatar .upload-item.is-single { - margin: 0; -} - .upload .upload-body.is-avatar .upload-item.is-invalid { border-color: var(--bs-danger); border-style: solid; diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index ec9e0091059..187375fcea3 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -122,7 +122,7 @@ public abstract class UploadBase : ValidateBase, IUpload } /// - /// + /// User selects files callback method /// /// /// @@ -130,14 +130,19 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) { UploadFiles.Clear(); var fileCount = MaxFileCount ?? args.FileCount; - var items = args.GetMultipleFiles(fileCount).Select(f => new UploadFile() + var items = args.GetMultipleFiles(fileCount).Select(f => { - OriginFileName = f.Name, - Size = f.Size, - File = f, - FileCount = args.FileCount, - Uploaded = false, - UpdateCallback = Update + var file = new UploadFile() + { + OriginFileName = f.Name, + Size = f.Size, + File = f, + FileCount = args.FileCount, + Uploaded = false, + UpdateCallback = Update + }; + file.ValidateId = $"{Id}_{file.GetHashCode()}"; + return file; }).ToList(); foreach (var item in items) @@ -170,7 +175,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) } else if (ValueType == typeof(IBrowserFile)) { - CurrentValue = (TValue)(object)items[0].File!; + CurrentValue = (TValue)items[0].File!; } else if (ValueType == typeof(string)) { @@ -269,7 +274,7 @@ public virtual void Reset() } /// - /// 显示/隐藏验证结果方法 + /// /// /// public override void ToggleMessage(IEnumerable results) From 34a88ef6634893829dc32197e6cfbc1d371c00c6 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 17:55:43 +0800 Subject: [PATCH 087/177] =?UTF-8?q?style:=20=E6=9B=B4=E6=96=B0=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 9f9db7525fe..0933e8bc63f 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -124,7 +124,7 @@ border-radius: var(--bb-upload-item-border-radius); } -.upload .upload-body.is-avatar .upload-item:not(.is-form):hover, +.upload .upload-body.is-avatar .upload-item:not(.is-form):not(.is-valid):not(.is-invalid):hover, .upload .upload-body.is-avatar .upload-item:not(.is-form).is-valid, .upload .upload-body.is-card .upload-item.is-valid, .upload .upload-body.is-card .upload-item:not(.disabled):hover { From 44be1cb486972d6983985e9b1861220258d510a1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 17:55:55 +0800 Subject: [PATCH 088/177] =?UTF-8?q?refactor:=20=E5=BE=AE=E8=B0=83=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index ba99bd9f007..d3228b72dbb 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -97,7 +97,12 @@ public partial class AvatarUpload } var state = item?.IsValid ?? IsValid; - return state is true ? "is-valid" : "is-invalid"; + if (state == null) + { + return null; + } + + return state.Value ? "is-valid" : "is-invalid"; } /// From dcb97110fdd08ea33893a324ce2c3f26e6bd25a4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 18 May 2025 18:25:52 +0800 Subject: [PATCH 089/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadFile.cs | 2 +- test/UnitTest/Components/UploadAvatarTest.cs | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index 1d0ba2a29eb..1af91bf7274 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -73,7 +73,7 @@ public class UploadFile internal string? ValidateId { get; set; } /// - /// 获得/设置 组件是否合规 默认为 null 未检查 + /// 获得/设置 当前上传文件是否合规 默认为 null 未检查 /// internal bool? IsValid { get; set; } diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index b9b91a40a20..17807fc2aa9 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -23,6 +23,8 @@ public async Task AvatarUpload_Ok() return Task.CompletedTask; }); }); + Assert.Contains("upload-item-plus", cut.Markup); + var input = cut.FindComponent(); await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() { @@ -90,6 +92,22 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha }); } + [Fact] + public void MaxFileCount_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.MaxFileCount, 2); + pb.Add(a => a.DefaultFileList, + [ + new UploadFile { FileName = "Test-File" }, + new UploadFile { FileName = "Test-File" } + ]); + }); + Assert.DoesNotContain(".upload-item-plus", cut.Markup); + } + [Fact] public async Task AvatarUpload_ValidateForm_Ok() { @@ -131,6 +149,15 @@ await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List< form.Submit(); }); Assert.False(invalid); + + // 设置 Disabled 取消校验 + var upload = cut.FindComponent>(); + upload.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, true); + }); + + Assert.DoesNotContain("is-invalid", upload.Markup); } private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile From 0f5a6eec3609026c2e16241c16c5300da2b57098 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 19 May 2025 10:20:05 +0800 Subject: [PATCH 090/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 16 -- .../Components/Upload/CardUpload.razor | 5 +- .../Components/Upload/UploadBase.cs | 8 +- test/UnitTest/Components/UploadCardTest.cs | 214 ++++++++++++++++++ 4 files changed, 220 insertions(+), 23 deletions(-) create mode 100644 test/UnitTest/Components/UploadCardTest.cs diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index d3228b72dbb..32082802554 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -148,22 +148,6 @@ protected override void OnParametersSet() }; } - /// - /// - /// - /// - protected override bool CheckCanUpload() - { - // 允许多上传 - if (IsMultiple) - { - return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; - } - - // 只允许单个上传 - return UploadFiles.Count == 0; - } - /// /// 获得 数据验证客户端 ID /// diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index cc29ff1c309..33ceb43c917 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -86,13 +86,10 @@ @code { RenderFragment RenderAdd => @
-
- @if (!IsDisabled) - { +
- }
; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 187375fcea3..8d2c56032ac 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -239,12 +239,14 @@ protected virtual bool CheckCanUpload() return true; } - if (IsMultiple == false) + // 允许多上传 + if (IsMultiple) { - return UploadFiles.Count > 0; + return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; } - return MaxFileCount.HasValue && UploadFiles.Count > MaxFileCount.Value; + // 只允许单个上传 + return UploadFiles.Count == 0; } /// diff --git a/test/UnitTest/Components/UploadCardTest.cs b/test/UnitTest/Components/UploadCardTest.cs new file mode 100644 index 00000000000..704de4045dd --- /dev/null +++ b/test/UnitTest/Components/UploadCardTest.cs @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; + +namespace UnitTest.Components; + +public class UploadCardTest : BootstrapBlazorTestBase +{ + [Fact] + public async Task CardUpload_Ok() + { + var zoom = false; + var deleted = false; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.OnDelete, file => + { + deleted = true; + return Task.FromResult(true); + }); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File1.text" }, + new() { FileName = "Test-File2.jpg" }, + new() { PrevUrl = "Test-File3.png" }, + new() { PrevUrl = "Test-File4.bmp" }, + new() { PrevUrl = "Test-File5.jpeg" }, + new() { PrevUrl = "Test-File6.gif" }, + new() { PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANS=" }, + new() { FileName = null! } + ]); + }); + cut.Contains("bb-previewer collapse active"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IconTemplate, file => builder => + { + builder.AddContent(0, "custom-file-icon-template"); + }); + }); + cut.Contains("custom-file-icon-template"); + + // OnZoom + await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); + Assert.False(zoom); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.OnZoomAsync, file => + { + zoom = true; + return Task.CompletedTask; + }); + }); + await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); + Assert.True(zoom); + + zoom = false; + await cut.InvokeAsync(() => cut.Find(".upload-item-body-image").Click()); + Assert.True(zoom); + + // ShowDownload + var clicked = false; + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ShowDownloadButton, true); + pb.Add(a => a.OnDownload, file => + { + clicked = true; + return Task.CompletedTask; + }); + + }); + Assert.Contains("btn-download", cut.Markup); + var button = cut.Find(".btn-download"); + await cut.InvokeAsync(() => button.Click()); + Assert.True(clicked); + + // OnDelete + await cut.InvokeAsync(() => cut.Find(".btn-outline-danger").Click()); + Assert.True(deleted); + + // CanPreviewCallback + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.CanPreviewCallback, p => + { + return false; + }); + }); + await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); + + // ShowProgress + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async file => + { + await file.SaveToFileAsync("1.txt"); + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test.txt", "Image-Png") + }))); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test.png") + }))); + + // IsUploadButtonAtFirst + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsUploadButtonAtFirst, true); + pb.Add(a => a.IsMultiple, true); + }); + } + + [Fact] + public void CardUpload_ValidateForm_Ok() + { + var foo = new Foo(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>(pb => + { + pb.Add(a => a.Value, foo.Name); + pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + }); + }); + cut.Contains("form-label"); + } + + [Fact] + public async Task CardUpload_ShowProgress_Ok() + { + var cancel = false; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async file => + { + await Task.Delay(100); + await file.SaveToFileAsync("1.txt"); + }); + pb.Add(a => a.OnCancel, file => + { + cancel = true; + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(() => + { + input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + })); + var button = cut.Find(".btn-cancel"); + Assert.NotNull(button); + button.Click(); + }); + Assert.True(cancel); + } + + //[Fact] + //public async Task CardUpload_Max_Ok() + //{ + // var cut = Context.RenderComponent>(pb => + // { + // pb.Add(a => a.ShowProgress, true); + // pb.Add(a => a.Max, 1); + // }); + // var input = cut.FindComponent(); + // await cut.InvokeAsync(async () => + // { + // await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + // { + // new() + // })); + // }); + //} + + private class Person + { + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] + + public IBrowserFile? Picture { get; set; } + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} From 051c1d2bb64dfa1880e403228a3e4a1c1501ed3a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 21 May 2025 17:49:16 +0800 Subject: [PATCH 091/177] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E5=90=8E=20Add=20=E6=A1=86=E5=87=BA=E7=8E=B0=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 8d2c56032ac..0c366d69551 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -236,7 +236,7 @@ protected virtual bool CheckCanUpload() { if (IsDisabled) { - return true; + return false; } // 允许多上传 From f4d37e9266fa66be66c98a65f5d2d4fa47e7fe17 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 21 May 2025 18:20:11 +0800 Subject: [PATCH 092/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 4 ++-- src/BootstrapBlazor/Extensions/UploadFileExtensions.cs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 0c366d69551..34bf81ca945 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -128,7 +128,6 @@ public abstract class UploadBase : ValidateBase, IUpload /// protected async Task OnFileChange(InputFileChangeEventArgs args) { - UploadFiles.Clear(); var fileCount = MaxFileCount ?? args.FileCount; var items = args.GetMultipleFiles(fileCount).Select(f => { @@ -234,9 +233,10 @@ protected void Update(UploadFile file) /// protected virtual bool CheckCanUpload() { + // 如果组件禁用了 IsDisabled 允许上传但是不出现 + 按钮 if (IsDisabled) { - return false; + return true; } // 允许多上传 diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index 1bba8e08bed..af5037e5dcb 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -54,7 +54,6 @@ public static async Task RequestBase64ImageFileAsync(this UploadFile upload, str /// /// /// - [ExcludeFromCodeCoverage] public static async Task SaveToFileAsync(this UploadFile upload, string fileName, long maxAllowedSize = 512000, CancellationToken token = default) { var ret = false; @@ -130,7 +129,6 @@ public static async Task SaveToFileAsync(this UploadFile upload, string fi /// /// /// - [ExcludeFromCodeCoverage] public static async Task GetBytesAsync(this UploadFile upload, string format, int maxWidth, int maxHeight, long maxAllowedSize = 512000, CancellationToken token = default) { byte[]? ret = null; From aead0946327924d326c54fe78e70d87c8fbce6f3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 21 May 2025 18:20:34 +0800 Subject: [PATCH 093/177] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/CardUpload.razor.cs | 97 ++++++++++++++++--- 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index b06b66862a5..a344ca37b36 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -150,10 +150,80 @@ public partial class CardUpload [Parameter] public List? AllowExtensions { get; set; } + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconExcel { get; set; } + + /// + /// 获得/设置 Docx 类型文件图标 + /// + [Parameter] + public string? FileIconDocx { get; set; } + + /// + /// 获得/设置 PPT 类型文件图标 + /// + [Parameter] + public string? FileIconPPT { get; set; } + + /// + /// 获得/设置 Audio 类型文件图标 + /// + [Parameter] + public string? FileIconAudio { get; set; } + + /// + /// 获得/设置 Video 类型文件图标 + /// + [Parameter] + public string? FileIconVideo { get; set; } + + /// + /// 获得/设置 File 类型文件图标 + /// + [Parameter] + public string? FileIconCode { get; set; } + + /// + /// 获得/设置 Pdf 类型文件图标 + /// + [Parameter] + public string? FileIconPdf { get; set; } + + /// + /// 获得/设置 Zip 类型文件图标 + /// + [Parameter] + public string? FileIconZip { get; set; } + + /// + /// 获得/设置 Archive 类型文件图标 + /// + [Parameter] + public string? FileIconArchive { get; set; } + + /// + /// 获得/设置 Image 类型文件图标 + /// + [Parameter] + public string? FileIconImage { get; set; } + + /// + /// 获得/设置 File 类型文件图标 + /// + [Parameter] + public string? FileIconFile { get; set; } + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } + private string? ActionClassString => CssBuilder.Default("upload-item-actions") + .AddClass("btn-browser", IsDisabled == false) + .Build(); + /// /// /// @@ -167,22 +237,19 @@ protected override void OnParametersSet() RemoveIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadRemoveIcon); DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadDownloadIcon); ZoomIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadZoomIcon); - } - - /// - /// - /// - /// - protected override bool CheckCanUpload() - { - // 允许多上传 - if (IsMultiple) - { - return true; - } - // 只允许单个上传 - return UploadFiles.Count == 0; + CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); + FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); + FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); + FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); + FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); + FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); + FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); + FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); + FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); + FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); + FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); + FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } private async Task OnCardFileDelete(UploadFile item) From d1e1a96f319ba1a2e7d503343444ea50be27a66c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 21 May 2025 18:20:44 +0800 Subject: [PATCH 094/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor.cs | 6 +- .../Components/Samples/UploadCards.razor.cs | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index 9bd75a6eda0..a08437a3ef2 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -48,10 +48,8 @@ private async Task SaveToFile(UploadFile file) // 生成写入文件名称 if (!string.IsNullOrEmpty(WebsiteOption.CurrentValue.WebRootPath)) { - var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, - $"images{Path.DirectorySeparatorChar}uploader"); - file.FileName = - $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; + var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, "images", "uploader"); + file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; var fileName = Path.Combine(uploaderFolder, file.FileName); _token ??= new CancellationTokenSource(); diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs index 3fd49cdb8a4..92222eb24f4 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs @@ -3,12 +3,14 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Newtonsoft.Json.Linq; + namespace BootstrapBlazor.Server.Components.Samples; /// /// CardUpload sample code /// -public partial class UploadCards +public partial class UploadCards : IDisposable { private List DefaultFormatFileList { get; } = [ @@ -30,6 +32,7 @@ public partial class UploadCards ]; private static long MaxFileLength => 5 * 1024 * 1024; + private CancellationTokenSource? _token; private async Task OnCardUpload(UploadFile file) { @@ -46,12 +49,65 @@ private async Task OnCardUpload(UploadFile file) { // 模拟保存成功 await Task.Delay(100); - //await SaveToFile(file); + await SaveToFile(file); await ToastService.Success(Localizer["UploadsFileMsg"], $"{file.File!.Name} {Localizer["UploadsSuccess"]}"); } } } + private async Task SaveToFile(UploadFile file) + { + // Server Side 使用 + // Web Assembly 模式下必须使用 WebApi 方式去保存文件到服务器或者数据库中 + // 生成写入文件名称 + if (!string.IsNullOrEmpty(WebsiteOption.CurrentValue.WebRootPath)) + { + var uploaderFolder = Path.Combine(WebsiteOption.CurrentValue.WebRootPath, "images", "uploader"); + file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}"; + var fileName = Path.Combine(uploaderFolder, file.FileName); + + _token ??= new CancellationTokenSource(); + try + { + var ret = await file.SaveToFileAsync(fileName, MaxFileLength, _token.Token); + + if (ret) + { + // 保存成功 + file.PrevUrl = $"{WebsiteOption.CurrentValue.AssetRootPath}images/uploader/{file.FileName}"; + } + else + { + var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}"; + file.Code = 1; + file.Error = errorMessage; + await ToastService.Error(Localizer["UploadFile"], errorMessage); + } + } + catch (OperationCanceledException) + { + + } + } + else + { + file.Code = 1; + file.Error = Localizer["UploadsWasmError"]; + await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]); + } + } + + /// + /// + /// + public void Dispose() + { + _token?.Cancel(); + _token?.Dispose(); + _token = null; + GC.SuppressFinalize(this); + } + private List GetAttributes() => [ new() From f1494c32afc66e3e9256ba67e883d056af4d6693 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 21 May 2025 19:27:36 +0800 Subject: [PATCH 095/177] =?UTF-8?q?refactor:=20=E5=A4=8D=E5=86=99=20CheckC?= =?UTF-8?q?anUpload=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/CardUpload.razor.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index a344ca37b36..a102bc46b98 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -252,6 +252,28 @@ protected override void OnParametersSet() FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } + /// + /// + /// + /// + protected override bool CheckCanUpload() + { + // 如果组件禁用了 IsDisabled 允许上传但是不出现 + 按钮 + if (IsDisabled) + { + return true; + } + + // 允许多上传 + if (IsMultiple) + { + return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; + } + + // 只允许单个上传 + return UploadFiles.Count == 0; + } + private async Task OnCardFileDelete(UploadFile item) { await OnFileDelete(item); From 4588bdc3b9f04ff2fcf83a9039f395a0b05e5c18 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 15:40:00 +0800 Subject: [PATCH 096/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=8F=AF=E4=BB=A5=E7=BB=A7=E7=BB=AD=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 34bf81ca945..10bd57a897b 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -242,11 +242,11 @@ protected virtual bool CheckCanUpload() // 允许多上传 if (IsMultiple) { - return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; + return MaxFileCount.HasValue && GetUploadFiles().Count >= MaxFileCount; } // 只允许单个上传 - return UploadFiles.Count == 0; + return UploadFiles.Count > 0; } /// From 5ef9c6536600ba5043148b3c3338fdbeafca743e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 15:47:37 +0800 Subject: [PATCH 097/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 16 ++++++++++++++++ .../Components/Upload/CardUpload.razor.cs | 6 ------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 32082802554..d3228b72dbb 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -148,6 +148,22 @@ protected override void OnParametersSet() }; } + /// + /// + /// + /// + protected override bool CheckCanUpload() + { + // 允许多上传 + if (IsMultiple) + { + return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; + } + + // 只允许单个上传 + return UploadFiles.Count == 0; + } + /// /// 获得 数据验证客户端 ID /// diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index a102bc46b98..411fa612aa6 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -258,12 +258,6 @@ protected override void OnParametersSet() /// protected override bool CheckCanUpload() { - // 如果组件禁用了 IsDisabled 允许上传但是不出现 + 按钮 - if (IsDisabled) - { - return true; - } - // 允许多上传 if (IsMultiple) { From 8d2cd8babc0751fe15ce6c02bef40ba190ceec8c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 15:51:29 +0800 Subject: [PATCH 098/177] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E7=A6=81=E7=94=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 6 +----- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 19 +++++++++++++++-- .../Components/Upload/CardUpload.razor.cs | 6 +----- .../Components/Upload/InputUpload.razor | 2 +- .../Components/Upload/InputUpload.razor.cs | 17 +++++++++++++++ .../Components/Upload/UploadBase.cs | 21 ------------------- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index d3228b72dbb..366a44019b6 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -148,11 +148,7 @@ protected override void OnParametersSet() }; } - /// - /// - /// - /// - protected override bool CheckCanUpload() + private bool CheckCanUpload() { // 允许多上传 if (IsMultiple) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 77fd9fe1dec..10fbffcce2b 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -7,7 +7,7 @@ }
- @if (ShowUploadFileList) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 45a0ad2b33e..1b2a2d59481 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -230,8 +230,6 @@ public partial class ButtonUpload .AddClass(CancelIcon) .Build(); - private bool IsUploadButtonDisabled => CheckCanUpload(); - /// /// OnParametersSet 方法 /// @@ -261,6 +259,23 @@ protected override void OnParametersSet() CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); } + private bool CheckStatus() + { + if (IsDisabled) + { + return true; + } + + // 允许多上传 + if (IsMultiple) + { + return MaxFileCount.HasValue && GetUploadFiles().Count >= MaxFileCount; + } + + // 只允许单个上传 + return UploadFiles.Count > 0; + } + /// /// 点击下载按钮回调此方法 /// diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 411fa612aa6..8dbd918ede5 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -252,11 +252,7 @@ protected override void OnParametersSet() FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } - /// - /// - /// - /// - protected override bool CheckCanUpload() + private bool CheckCanUpload() { // 允许多上传 if (IsMultiple) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor b/src/BootstrapBlazor/Components/Upload/InputUpload.razor index 41b836ac0cf..3697b11c73e 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor @@ -16,7 +16,7 @@ Icon="@DeleteButtonIcon" Text="@DeleteButtonText" Color="Color.None" OnClick="@TriggerDeleteFile"> } -
diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 645436914e2..e01dd44ba0f 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,6 +102,23 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } + private bool CheckStatus() + { + if (IsDisabled) + { + return true; + } + + // 允许多上传 + if (IsMultiple) + { + return MaxFileCount.HasValue && GetUploadFiles().Count >= MaxFileCount; + } + + // 只允许单个上传 + return UploadFiles.Count > 0; + } + private async Task TriggerDeleteFile() { var files = GetUploadFiles(); diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 10bd57a897b..552d708eb2f 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -228,27 +228,6 @@ protected void Update(UploadFile file) } } - /// - /// 是否可以上传 - /// - protected virtual bool CheckCanUpload() - { - // 如果组件禁用了 IsDisabled 允许上传但是不出现 + 按钮 - if (IsDisabled) - { - return true; - } - - // 允许多上传 - if (IsMultiple) - { - return MaxFileCount.HasValue && GetUploadFiles().Count >= MaxFileCount; - } - - // 只允许单个上传 - return UploadFiles.Count > 0; - } - /// /// Get the files collection. /// 获得当前文件集合 From af0cdfdb3c04ce32de96a94cfdc9ceadc6c934ec Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 16:13:59 +0800 Subject: [PATCH 099/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=20CardUpload?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadCards.razor | 62 ++++++++++++++++--- .../Components/Samples/UploadCards.razor.cs | 9 +++ src/BootstrapBlazor.Server/Locales/en-US.json | 7 --- src/BootstrapBlazor.Server/Locales/zh-CN.json | 7 --- .../Components/Upload/InputUpload.razor.scss | 2 +- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index 912d71d3599..4db204bcd32 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -15,15 +15,61 @@ Introduction="@Localizer["ButtonUploadIntro"]" Name="Normal">
-
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleWasm"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleWasmSide"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleLink", WebsiteOption.CurrentValue.VideoLibUrl].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
-
@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
- + public partial class UploadCards : IDisposable { + private bool _isMultiple = true; + private bool _isDirectory = false; + private bool _isDisabled = false; + private bool _isUploadButtonAtFirst = false; + private bool _showProgress = true; + private bool _showZoomButton = true; + private bool _showDeleteButton = true; + private bool _showDownloadButton = true; + private List DefaultFormatFileList { get; } = [ new() { FileName = "Test.xls" }, diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index ece5b39af04..64acc33c788 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3537,13 +3537,6 @@ "ButtonUploadIntro": "Use DefaultFileList to set up uploaded content", "UploadPreCardStyleTitle": "Preview the card style", "UploadPreCardStyleIntro": "CardUpload components and rendered in card-style band preview mode", - "UploadPreCardStyleSSR": "SSR mode ", - "UploadPreCardStyleServerSide": "Server Side mode, you can use the IWebHostEnvironment injection service to get to the wwwroot directory and save the file to the images/uploader, which does not require a direct call the controller secondary of MVCSaveToFile method", - "UploadPreCardStyleWasm": "Wasm mode ", - "UploadPreCardStyleWasmSide": "It wasn't available in wasm mode, IWebHostEnvironment needed to save files to the server side by calling webapi interface, and so on", - "UploadPreCardStyleLink": "Interested students can view their knowledge of Upload components through the wiki in the open source repository related resources of the [The portal]", - "UploadPreCardStyleValidation": "In this example, server-side verification prompts the file for too much prompt when the file size exceeds 5MB", - "UploadPreCardStyleTips1": "In this example, the ShowProgress=true display upload progress bar", "UploadFileIconTitle": "The file icon", "UploadFileIconIntro": "Icons are displayed in different file formats", "UploadFileIconTemplateTitle": "Custom file icon", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 80fb10fc238..7efee059bfb 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3537,13 +3537,6 @@ "ButtonUploadIntro": "使用 DefaultFileList 设置已上传的内容", "UploadPreCardStyleTitle": "预览卡片式", "UploadPreCardStyleIntro": "CardUpload 组件,呈现为卡片式带预览模式", - "UploadPreCardStyleSSR": "SSR 模式", - "UploadPreCardStyleServerSide": "Server Side 模式中可以使用 IWebHostEnvironment 注入服务获取到 wwwwroot 目录,保存文件到 images\\uploader 中,此功能无需 MVC 的控制器辅助进行文件的保存,直接调用 SaveToFile 方法即可", - "UploadPreCardStyleWasm": "Wasm 模式", - "UploadPreCardStyleWasmSide": "wasm 模式中无法使用 IWebHostEnvironment 需要调用 webapi 接口等形式将文件保存到服务器端", - "UploadPreCardStyleLink": "有兴趣的同学可以通过开源仓库中的 wiki 文档中相关资源查看关于 Upload 组件的相关知识技巧 [传送门]", - "UploadPreCardStyleValidation": "本例中通过服务器端验证当文件大小超过 5MB 时,提示文件太大提示信息", - "UploadPreCardStyleTips1": "本例中设置 ShowProgress=true 显示上传进度条,通过设置 IsMultiple=\"true\" 允许一次选择多张图片上传", "UploadFileIconTitle": "文件图标", "UploadFileIconIntro": "不同文件格式显示的图标不同", "UploadFileIconTemplateTitle": "自定义文件图标", diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 0933e8bc63f..f69d4ea32fd 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -146,7 +146,7 @@ } .upload .upload-body.is-avatar .upload-item .upload-item-actions, -.upload .upload-body.is-card .upload-item .upload-item-actions.btn-browser { +.upload .upload-body.is-card .upload-item .upload-item-actions > .upload-item-plus { position: absolute; top: 0; left: 0; From 41059bea8951af1974013adc3f509a47cc5c75e3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 16:15:19 +0800 Subject: [PATCH 100/177] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadCards.razor | 2 - .../Components/Samples/UploadCards.razor.cs | 52 ------------------- src/BootstrapBlazor.Server/Locales/en-US.json | 8 +-- src/BootstrapBlazor.Server/Locales/zh-CN.json | 8 +-- 4 files changed, 2 insertions(+), 68 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index 4db204bcd32..6cfd037a69a 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -99,5 +99,3 @@ Name="Base64"> - - diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs index 9fda06c4e77..31f9dba89f6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor.cs @@ -116,56 +116,4 @@ public void Dispose() _token = null; GC.SuppressFinalize(this); } - - private List GetAttributes() => - [ - new() - { - Name = "IsDirectory", - Description = Localizer["UploadsIsDirectory"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "IsMultiple", - Description = Localizer["UploadsIsMultiple"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "ShowZoomButton", - Description = Localizer["UploadsShowZoomButton"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "true" - }, - new() - { - Name = "ShowDeletedButton", - Description = Localizer["UploadsShowDeleteButton"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "true" - }, - new() - { - Name = "ShowDownloadButton", - Description = Localizer["UploadsShowDownloadButton"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - } - ]; } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 64acc33c788..50cf614efa9 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3542,13 +3542,7 @@ "UploadFileIconTemplateTitle": "Custom file icon", "UploadFileIconTemplateIntro": "By setting the IconTemplate parameter and using the FileIcon component, you can further customize the file icon [FileIcon example]", "UploadBase64Title": "Base64 format", - "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path", - "UploadsIsDirectory": "Whether to upload the entire directory", - "UploadsIsMultiple": "Whether to allow multiple file uploads", - "UploadsShowProgress": "Whether to display the upload progress", - "UploadsShowZoomButton": "Whether to display the Zoom button", - "UploadsShowDeleteButton": "Whether to display the Delete button", - "UploadsShowDownloadButton": "Whether to display the Download button" + "UploadBase64Intro": "By setting the PrevUrl parameter value of the UploadFile instance, use the image content string in the data:image/xxx;base64,XXXXX format as the preview file path" }, "BootstrapBlazor.Server.Components.Samples.UploadDrops": { "UploadsTitle": "CardDrop", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 7efee059bfb..ec69b81344c 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3542,13 +3542,7 @@ "UploadFileIconTemplateTitle": "自定义文件图标", "UploadFileIconTemplateIntro": "通过设置 IconTemplate 参数,使用 FileIcon 组件可以对文件图标进行进一步自定义 [FileIcon 示例]", "UploadBase64Title": "Base64 格式文件", - "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径", - "UploadsIsDirectory": "是否上传整个目录", - "UploadsIsMultiple": "是否允许多文件上传", - "UploadsShowProgress": "是否显示上传进度", - "UploadsShowZoomButton": "是否显示放大按钮", - "UploadsShowDeleteButton": "是否显示删除按钮", - "UploadsShowDownloadButton": "是否显示下载按钮" + "UploadBase64Intro": "通过设置 UploadFile 实例的 PrevUrl 参数值使用 data:image/xxx;base64,XXXXX 格式图片内容字符串作为预览文件路径" }, "BootstrapBlazor.Server.Components.Samples.UploadDrops": { "UploadsTitle": "CardDrop 拖拽上传组件", From d73751e8e2b665f4eb7af2082acdc8a5878f1343 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 16:25:21 +0800 Subject: [PATCH 101/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E6=96=87=E6=A1=A3=E5=87=8F=E5=B0=91=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 56 ------------------- .../Components/Samples/UploadButtons.razor | 2 - .../Components/Samples/UploadButtons.razor.cs | 44 --------------- .../Components/Samples/UploadCards.razor | 2 +- src/BootstrapBlazor.Server/Locales/en-US.json | 18 +----- src/BootstrapBlazor.Server/Locales/zh-CN.json | 18 +----- .../Components/Upload/AvatarUpload.razor.cs | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 2 +- .../Components/Upload/CardUpload.razor.cs | 2 +- .../Components/Upload/InputUpload.razor.cs | 2 +- 10 files changed, 7 insertions(+), 141 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index 568a3364153..5a95970df4f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -114,62 +114,6 @@ private List GetAttributes() => Type = "string?", ValueList = " — ", DefaultValue = " — " - }, - new() - { - Name = "IsDirectory", - Description = Localizer["UploadsIsDirectory"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "IsMultiple", - Description = Localizer["UploadsIsMultiple"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "Accept", - Description = Localizer["UploadsAccept"], - Type = "string", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "DefaultFileList", - Description = Localizer["UploadsDefaultFileList"], - Type = "List", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnDelete", - Description = Localizer["UploadsOnDelete"], - Type = "Func>", - ValueList = " — ", - DefaultValue = " — " - }, - new() - { - Name = "OnChange", - Description = Localizer["UploadsOnChange"], - Type = "Func", - ValueList = " — ", - DefaultValue = " — " } ]; diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor index 4230691f222..d441d68baeb 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -59,5 +59,3 @@ ShowUploadFileList="@_showUploadFileList" ShowDownloadButton="@_showDownloadButton" OnChange="@OnClickToUpload" OnDownload="OnDownload"> - - diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index a08437a3ef2..9c68ed094e1 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -93,48 +93,4 @@ public void Dispose() _token = null; GC.SuppressFinalize(this); } - - private List GetAttributes() => - [ - new() - { - Name = "IsDirectory", - Description = Localizer["UploadsIsDirectory"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "IsMultiple", - Description = Localizer["UploadsIsMultiple"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "ShowProgress", - Description = Localizer["UploadsShowProgress"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "ShowUploadFileList", - Description = Localizer["UploadsShowUploadFileList"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "true" - }, - new() - { - Name = "ShowDownloadButton", - Description = Localizer["UploadsShowDeleteButton"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - } - ]; } diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index 6cfd037a69a..0077b42934b 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -97,5 +97,5 @@ - + diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 50cf614efa9..981337f74f9 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3474,13 +3474,6 @@ "UploadsWidth": "The width of the preview box", "UploadsHeight": "The height of the preview box", "UploadsIsCircle": "Whether it is circular avatar mode", - "UploadsIsDirectory": "Whether to upload the entire directory", - "UploadsIsMultiple": "Whether to allow multiple file uploads", - "UploadsShowProgress": "Whether to display the upload progress", - "UploadsDefaultFileList": "The collection of files has been uploaded", - "UploadsAccept": "Upload the received file format", - "UploadsOnDelete": "Call back this method when you click the Delete button", - "UploadsOnChange": "Call back this method when you click the Browse button", "UploadsBorderRadius": "Border radius" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { @@ -3518,16 +3511,7 @@ "UploadsSubTitle": "Upload files by clicking on them, usually used to upload file attachments", "UploadsNote": "If you edit too much content, signalR communication interruption may be triggered. Please adjust the HubOptions configuration.", "ButtonUploadTitle": "Basic usage", - "ButtonUploadIntro": "By setting ShowUploadFileList=\"true\" you can display the uploaded file list, and setting ShowDeleteButton=\"true\" you can display the Delete button", - "UploadsIsDirectory": "Whether to upload the entire directory", - "UploadsIsMultiple": "Whether to allow multiple file uploads", - "UploadsShowProgress": "Whether to display the upload progress", - "UploadsDefaultFileList": "The collection of files has been uploaded", - "UploadsShowUploadFileList": "Whether show the upload file list", - "UploadsAccept": "Upload the received file format", - "UploadsShowDeleteButton": "Whether to display the Delete button", - "UploadsOnDelete": "Call back this method when you click the Delete button", - "UploadsOnChange": "Call back this method when you click the Browse button" + "ButtonUploadIntro": "By setting ShowUploadFileList=\"true\" you can display the uploaded file list, and setting ShowDeleteButton=\"true\" you can display the Delete button" }, "BootstrapBlazor.Server.Components.Samples.UploadCards": { "UploadsTitle": "CardUpload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index ec69b81344c..8e649eed7d6 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3474,13 +3474,6 @@ "UploadsWidth": "预览框宽度", "UploadsHeight": "预览框高度", "UploadsIsCircle": "是否为圆形头像模式", - "UploadsIsDirectory": "是否上传整个目录", - "UploadsIsMultiple": "是否允许多文件上传", - "UploadsShowProgress": "是否显示上传进度", - "UploadsDefaultFileList": "已上传文件集合", - "UploadsAccept": "上传接收的文件格式", - "UploadsOnDelete": "点击删除按钮时回调此方法", - "UploadsOnChange": "点击浏览按钮时回调此方法", "UploadsBorderRadius": "预览框圆角曲率" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { @@ -3518,16 +3511,7 @@ "UploadsSubTitle": "通过点击按钮弹出选择文件框选择一个或者多个文件,通常用作上传文件附件", "UploadsNote": "如果上传文件过大,可能会触发 signalR 通讯中断问题,请自行调整 HubOptions 配置即可。", "ButtonUploadTitle": "基础用法", - "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮", - "UploadsIsDirectory": "是否上传整个目录", - "UploadsIsMultiple": "是否允许多文件上传", - "UploadsShowProgress": "是否显示上传进度", - "UploadsDefaultFileList": "已上传文件集合", - "UploadsAccept": "上传接收的文件格式", - "UploadsShowUploadFileList": "是否显示上传列表", - "UploadsShowDeleteButton": "是否显示删除按钮", - "UploadsOnDelete": "点击删除按钮时回调此方法", - "UploadsOnChange": "点击浏览按钮时回调此方法" + "ButtonUploadIntro": "通过设置 ShowUploadFileList=\"true\" 可以显示上传文件列表,设置 ShowDeleteButton=\"true\" 显示 删除 按钮" }, "BootstrapBlazor.Server.Components.Samples.UploadCards": { "UploadsTitle": "CardUpload 卡片上传组件", diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 366a44019b6..e6709fa2edb 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -157,7 +157,7 @@ private bool CheckCanUpload() } // 只允许单个上传 - return UploadFiles.Count == 0; + return GetUploadFiles().Count == 0; } /// diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 1b2a2d59481..45d29f16cb9 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -273,7 +273,7 @@ private bool CheckStatus() } // 只允许单个上传 - return UploadFiles.Count > 0; + return GetUploadFiles().Count > 0; } /// diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 8dbd918ede5..cbd8b9a28ca 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -261,7 +261,7 @@ private bool CheckCanUpload() } // 只允许单个上传 - return UploadFiles.Count == 0; + return GetUploadFiles().Count == 0; } private async Task OnCardFileDelete(UploadFile item) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index e01dd44ba0f..2201ef45866 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -116,7 +116,7 @@ private bool CheckStatus() } // 只允许单个上传 - return UploadFiles.Count > 0; + return GetUploadFiles().Count > 0; } private async Task TriggerDeleteFile() From 921b06c7612e4cc0a72643aa5d1eb3b35dd7712a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 19:15:31 +0800 Subject: [PATCH 102/177] =?UTF-8?q?refactor:=20=E7=BB=9F=E4=B8=80=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20btn-browser=20=E4=BD=9C=E4=B8=BA=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/DropUpload.razor | 2 +- src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs | 4 ++++ src/BootstrapBlazor/wwwroot/modules/upload.js | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 1b5665e8b88..ae6cc7253e6 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -6,7 +6,7 @@ }
-
+
@if (BodyTemplate != null) { @BodyTemplate diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 9a79d0c19c3..5289e0b9ee1 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -75,6 +75,10 @@ public partial class DropUpload .AddClassFromAttributes(AdditionalAttributes) .Build(); + private string? BodyClassString => CssBuilder.Default("upload-drop-body") + .AddClass("btn-browser", !IsDisabled) + .Build(); + /// /// /// diff --git a/src/BootstrapBlazor/wwwroot/modules/upload.js b/src/BootstrapBlazor/wwwroot/modules/upload.js index 006eb250a6b..97e0ddaa52b 100644 --- a/src/BootstrapBlazor/wwwroot/modules/upload.js +++ b/src/BootstrapBlazor/wwwroot/modules/upload.js @@ -15,10 +15,6 @@ export function init(id) { inputFile.click() }) - EventHandler.on(el, 'click', '.upload-drop-body', () => { - inputFile.click() - }) - EventHandler.on(document, "dragleave", preventHandler) EventHandler.on(document, 'drop', preventHandler) EventHandler.on(document, 'dragenter', preventHandler) From c44c02c29d7af33c7b8b878c125901b80623ebb6 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 22 May 2025 19:24:36 +0800 Subject: [PATCH 103/177] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/DropUpload.razor | 2 +- src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs | 5 +++++ src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index ae6cc7253e6..b8e784bc369 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -23,7 +23,7 @@ }
-
+
@if (TextTemplate != null) { @TextTemplate diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 5289e0b9ee1..d57378c4916 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -77,6 +77,11 @@ public partial class DropUpload private string? BodyClassString => CssBuilder.Default("upload-drop-body") .AddClass("btn-browser", !IsDisabled) + .AddClass("disabled", IsDisabled) + .Build(); + + private string? TextClassString => CssBuilder.Default("upload-drop-text") + .AddClass("text-muted", IsDisabled) .Build(); /// diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index f69d4ea32fd..5c1b6c934dd 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -310,6 +310,10 @@ height: var(--bb-upload-drop-height); cursor: pointer; + &.disabled { + border-color: var(--bs-border-color); + } + .upload-drop-icon > i { font-size: 3em; color: var(--bs-secondary); From 0dd8fda8668f71fee4aa175242d6a485567c4222 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 10:04:02 +0800 Subject: [PATCH 104/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E6=A0=B7=E5=BC=8F=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/DropUpload.razor.cs | 2 +- .../Components/Upload/InputUpload.razor.scss | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index d57378c4916..9cdabdd6646 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -72,12 +72,12 @@ public partial class DropUpload private IStringLocalizer>? Localizer { get; set; } private string? ClassString => CssBuilder.Default("upload is-drop") + .AddClass("disabled", IsDisabled) .AddClassFromAttributes(AdditionalAttributes) .Build(); private string? BodyClassString => CssBuilder.Default("upload-drop-body") .AddClass("btn-browser", !IsDisabled) - .AddClass("disabled", IsDisabled) .Build(); private string? TextClassString => CssBuilder.Default("upload-drop-text") diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 5c1b6c934dd..c967e39bdd0 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -300,6 +300,13 @@ } .upload.is-drop { + + &.disabled { + .upload-drop-body { + border-color: var(--bs-border-color); + } + } + .upload-drop-body { border: 1px dashed var(--bs-primary); border-radius: var(--bs-border-radius); @@ -310,10 +317,6 @@ height: var(--bb-upload-drop-height); cursor: pointer; - &.disabled { - border-color: var(--bs-border-color); - } - .upload-drop-icon > i { font-size: 3em; color: var(--bs-secondary); From 5639bd05579a261fcd0be707182a2ee30e9eaca8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 10:04:10 +0800 Subject: [PATCH 105/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 12 +++---- .../Components/Samples/UploadAvatars.razor.cs | 2 +- .../Components/Samples/UploadDrops.razor | 31 ++++++++++++++++++- .../Components/Samples/UploadDrops.razor.cs | 5 +++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index 0f753735014..dc727ad3b1e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -16,6 +16,12 @@ Name="Normal">
+
+ + + + +
@@ -40,12 +46,6 @@
-
- - - - -
_previewFileList = []; private readonly Person _foo = new(); - private bool _isMultiple = true; private bool _isUploadButtonAtFirst; private bool _isCircle; private int _radius = 49; + private bool _isMultiple = true; private bool _isDisabled = false; private string? RadiusString => $"{_radius}px"; diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor index d5cc698e15e..fc3a685b0f2 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor @@ -12,8 +12,37 @@
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+ IsDisabled="@_isDisabled" IsMultiple="@_isMultiple" + ShowProgress="@_showProgress" ShowFooter="@_showFooter">
@foreach (var file in _dropFiles) { diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs index 04ffcb6a8e1..aa12413f62f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -10,6 +10,11 @@ namespace BootstrapBlazor.Server.Components.Samples; ///
public partial class UploadDrops { + private bool _isMultiple = true; + private bool _isDisabled = false; + private bool _showProgress = true; + private bool _showFooter = true; + private readonly List _dropFiles = []; private async Task OnDropUpload(UploadFile file) From d18973cbc810281542979e3a945a2a120021deec Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 13:27:49 +0800 Subject: [PATCH 106/177] =?UTF-8?q?refactor:=20=E6=96=B0=E5=BB=BA=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E7=BB=84=E4=BB=B6=E5=87=86=E5=A4=87=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor | 52 +--- .../Components/Upload/ButtonUpload.razor.cs | 108 +------ .../Components/Upload/UploadBase.cs | 2 +- .../Components/Upload/UploadPreviewList.razor | 45 +++ .../Upload/UploadPreviewList.razor.cs | 284 ++++++++++++++++++ 5 files changed, 341 insertions(+), 150 deletions(-) create mode 100644 src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor create mode 100644 src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 10fbffcce2b..600f859bc5a 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -12,49 +12,15 @@ @if (ShowUploadFileList) { -
- @foreach (var item in GetUploadFiles()) - { -
- -
- @item.GetFileName() - (@item.Size.ToFileSizeString()) -
- @if (GetShowProgress(item)) - { - - - - } - else - { -
- @if (item.Code == 0) - { - @if (ShowDownloadButton) - { - - } - - @if (!IsDisabled) - { - - } - } - else - { - @if (!IsDisabled) - { - - - } - } -
- } -
- } -
+ }
diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 45d29f16cb9..b919b6697da 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -9,11 +9,12 @@ namespace BootstrapBlazor.Components; /// /// 按钮上传组件 +/// ButtonUpload Component /// public partial class ButtonUpload { /// - /// 获得/设置 浏览按钮图标 + /// 获得/设置 浏览按钮加载中图标 /// [Parameter] public string? LoadingIcon { get; set; } @@ -193,43 +194,10 @@ public partial class ButtonUpload .AddClassFromAttributes(AdditionalAttributes) .Build(); - private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) - .AddClass("is-valid", item is { Uploaded: true, Code: 0 }) - .AddClass("is-invalid", item.Code != 0) - .Build(); - - private string? ItemClassString => CssBuilder.Default("upload-item") - .AddClass("disabled", IsDisabled) - .Build(); - private string? BrowserButtonClassString => CssBuilder.Default("btn-browser") .AddClass(BrowserButtonClass, !string.IsNullOrEmpty(BrowserButtonClass)) .Build(); - private string? LoadingIconString => CssBuilder.Default("loading-icon") - .AddClass(LoadingIcon) - .Build(); - - private string? DeleteIconString => CssBuilder.Default("delete-icon") - .AddClass(DeleteIcon) - .Build(); - - private string? ValidStatusIconString => CssBuilder.Default("valid-icon") - .AddClass(ValidStatusIcon) - .Build(); - - private string? InvalidStatusIconString => CssBuilder.Default("invalid-icon") - .AddClass(InvalidStatusIcon) - .Build(); - - private string? DownloadIconString => CssBuilder.Default("download-icon") - .AddClass(DownloadIcon) - .Build(); - - private string? CancelIconString => CssBuilder.Default("cancel-icon") - .AddClass(CancelIcon) - .Build(); - /// /// OnParametersSet 方法 /// @@ -239,24 +207,6 @@ protected override void OnParametersSet() BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadBrowserButtonIcon); - LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadLoadingIcon); - InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadInvalidStatusIcon); - ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadValidStatusIcon); - DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDownloadIcon); - DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDeleteIcon); - - FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); - FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); - FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); - FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); - FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); - FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); - FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); - FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); - FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); - FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); - FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); - CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); } private bool CheckStatus() @@ -275,58 +225,4 @@ private bool CheckStatus() // 只允许单个上传 return GetUploadFiles().Count > 0; } - - /// - /// 点击下载按钮回调此方法 - /// - /// - /// - private async Task OnClickDownload(UploadFile item) - { - if (OnDownload != null) - { - await OnDownload(item); - } - } - - /// - /// 点击取消按钮回调此方法 - /// - /// - /// - private async Task OnClickCancel(UploadFile item) - { - if (OnCancel != null) - { - await OnCancel(item); - } - } - - private string? GetFileFormatClassString(UploadFile item) - { - var builder = CssBuilder.Default("file-icon"); - var fileExtension = Path.GetExtension(item.OriginFileName ?? item.FileName); - if (!string.IsNullOrEmpty(fileExtension)) - { - fileExtension = fileExtension.ToLowerInvariant(); - } - var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(fileExtension); - builder.AddClass(icon); - return builder.Build(); - } - - private string? GetFileExtensions(string? fileExtension) => fileExtension switch - { - ".csv" or ".xls" or ".xlsx" => FileIconExcel, - ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, - ".ppt" or ".pptx" => FileIconPPT, - ".wav" or ".mp3" => FileIconAudio, - ".mp4" or ".mov" or ".mkv" => FileIconVideo, - ".cs" or ".html" or ".vb" => FileIconCode, - ".pdf" => FileIconPdf, - ".zip" or ".rar" or ".iso" => FileIconZip, - ".txt" or ".log" => FileIconArchive, - ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, - _ => FileIconFile - }; } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 552d708eb2f..e62a656e0d8 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -205,8 +205,8 @@ protected virtual async Task OnFileDelete(UploadFile item) UploadFiles.Remove(item); DefaultFileList?.Remove(item); } + StateHasChanged(); return ret; - } /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor new file mode 100644 index 00000000000..7a6ac0e5a9e --- /dev/null +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor @@ -0,0 +1,45 @@ +@namespace BootstrapBlazor.Components + +
+ @foreach (var item in Items) + { +
+ +
+ @item.GetFileName() + (@item.Size.ToFileSizeString()) +
+ @if (GetShowProgress(item)) + { + + + + } + else + { +
+ @if (item.Code == 0) + { + @if (ShowDownloadButton) + { + + } + + @if (!IsDisabled) + { + + } + } + else + { + @if (!IsDisabled) + { + + + } + } +
+ } +
+ } +
diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs new file mode 100644 index 00000000000..b289000fdd7 --- /dev/null +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs @@ -0,0 +1,284 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// UploadPreviewList component +/// +public partial class UploadPreviewList +{ + /// + /// Gets or sets the collection of files to be uploaded. + /// + [Parameter] + [NotNull] + public List? Items { get; set; } + + /// + /// Gets or sets the disable status of the upload list. + /// + [Parameter] + public bool IsDisabled { get; set; } + + /// + /// Gets or sets a value indicating whether progress should be displayed during the operation. + /// + [Parameter] + public bool ShowProgress { get; set; } + + /// + /// Gets or sets the upload file format callback method. + /// + [Parameter] + public Func? OnGetFileFormat { get; set; } + + /// + /// Gets or sets the callback method for the cancel button click event. Default is null + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + + /// + /// 获得/设置 浏览按钮图标 + /// + [Parameter] + public string? LoadingIcon { get; set; } + + /// + /// 获得/设置 下载按钮图标 + /// + [Parameter] + public string? DownloadIcon { get; set; } + + /// + /// 获得/设置 上传失败状态图标 + /// + [Parameter] + public string? InvalidStatusIcon { get; set; } + + /// + /// 获得/设置 上传成功状态图标 + /// + [Parameter] + public string? ValidStatusIcon { get; set; } + + /// + /// 获得/设置 删除按钮图标 + /// + [Parameter] + public string? DeleteIcon { get; set; } + + /// + /// 获得/设置 是否显示下载按钮 默认 false + /// + [Parameter] + public bool ShowDownloadButton { get; set; } + + /// + /// 获得/设置 点击下载按钮回调方法 默认 null + /// + [Parameter] + public Func? OnDownload { get; set; } + + /// + /// 获得/设置 点击删除按钮时回调此方法 默认 null + /// + [Parameter] + public Func>? OnDelete { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconExcel { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconDocx { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPPT { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconAudio { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconVideo { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconCode { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPdf { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconZip { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconArchive { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconImage { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconFile { get; set; } + + [Inject] + [NotNull] + private IIconTheme? IconTheme { get; set; } + + private string? ItemClassString => CssBuilder.Default("upload-item") + .AddClass("disabled", IsDisabled) + .Build(); + + private string? GetItemClassString(UploadFile item) => CssBuilder.Default(ItemClassString) + .AddClass("is-valid", item is { Uploaded: true, Code: 0 }) + .AddClass("is-invalid", item.Code != 0) + .Build(); + + private string? LoadingIconString => CssBuilder.Default("loading-icon") + .AddClass(LoadingIcon) + .Build(); + + private string? CancelIconString => CssBuilder.Default("cancel-icon") + .AddClass(CancelIcon) + .Build(); + + private string? DownloadIconString => CssBuilder.Default("download-icon") + .AddClass(DownloadIcon) + .Build(); + + private string? DeleteIconString => CssBuilder.Default("delete-icon") + .AddClass(DeleteIcon) + .Build(); + + private string? ValidStatusIconString => CssBuilder.Default("valid-icon") + .AddClass(ValidStatusIcon) + .Build(); + + private string? InvalidStatusIconString => CssBuilder.Default("invalid-icon") + .AddClass(InvalidStatusIcon) + .Build(); + + /// + /// + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + Items ??= []; + + LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadLoadingIcon); + InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadInvalidStatusIcon); + ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadValidStatusIcon); + DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDownloadIcon); + CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); + DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDeleteIcon); + + FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); + FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); + FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); + FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); + FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); + FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); + FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); + FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); + FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); + FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); + FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); + } + + private async Task OnClickDownload(UploadFile item) + { + if (OnDownload != null) + { + await OnDownload(item); + } + } + + private async Task OnFileDelete(UploadFile item) + { + if (OnDelete != null) + { + await OnDelete(item); + } + } + + private bool GetShowProgress(UploadFile item) => ShowProgress && !item.Uploaded; + + private async Task OnClickCancel(UploadFile item) + { + if (OnCancel != null) + { + await OnCancel(item); + } + } + + private string? GetFileFormatClassString(UploadFile item) + { + var builder = CssBuilder.Default("file-icon"); + var fileExtension = Path.GetExtension(item.OriginFileName ?? item.FileName); + if (!string.IsNullOrEmpty(fileExtension)) + { + fileExtension = fileExtension.ToLowerInvariant(); + } + var icon = OnGetFileFormat?.Invoke(fileExtension) ?? GetFileExtensions(fileExtension); + builder.AddClass(icon); + return builder.Build(); + } + + private string? GetFileExtensions(string? fileExtension) => fileExtension switch + { + ".csv" or ".xls" or ".xlsx" => FileIconExcel, + ".doc" or ".docx" or ".dot" or ".dotx" => FileIconDocx, + ".ppt" or ".pptx" => FileIconPPT, + ".wav" or ".mp3" => FileIconAudio, + ".mp4" or ".mov" or ".mkv" => FileIconVideo, + ".cs" or ".html" or ".vb" => FileIconCode, + ".pdf" => FileIconPdf, + ".zip" or ".rar" or ".iso" => FileIconZip, + ".txt" or ".log" => FileIconArchive, + ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" => FileIconImage, + _ => FileIconFile + }; +} From fc8cb32baeb43874d3bcbe3ecf4f60f85f8f6290 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 13:28:04 +0800 Subject: [PATCH 107/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadButtons.razor | 2 +- .../Components/Samples/UploadButtons.razor.cs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor index d441d68baeb..78cad6f9254 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor @@ -57,5 +57,5 @@ + OnChange="@OnClickToUpload" OnDownload="OnDownload" OnDelete="OnDelete"> diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs index 9c68ed094e1..6e96250e7b6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadButtons.razor.cs @@ -41,6 +41,12 @@ private async Task OnDownload(UploadFile item) await ToastService.Success("文件下载", $"下载 {item.FileName} 成功"); } + private async Task OnDelete(UploadFile item) + { + await ToastService.Success("文件操作", $"删除文件 {item.FileName} 成功"); + return true; + } + private async Task SaveToFile(UploadFile file) { // Server Side 使用 From 2d0d195c25fc743a89450e1a6f498c20b2eb7126 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 13:28:13 +0800 Subject: [PATCH 108/177] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E5=AD=97?= =?UTF-8?q?=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exclusion.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/exclusion.dic b/exclusion.dic index 4820a3c3e44..a3d2a0b1822 100644 --- a/exclusion.dic +++ b/exclusion.dic @@ -117,3 +117,4 @@ Hotp univer rdkit webkitdirectory +dotx From 88a2bd995cc0ab99a5208f2e72918fb2eaab7f2d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 14:32:39 +0800 Subject: [PATCH 109/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor.cs | 16 +-- .../Components/Upload/DropUpload.razor | 12 ++ .../Components/Upload/DropUpload.razor.cs | 132 ++++++++++++++++++ 3 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index b919b6697da..0cbfd228007 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -86,14 +86,6 @@ public partial class ButtonUpload [Parameter] public RenderFragment? ChildContent { get; set; } - [Inject] - [NotNull] - private IStringLocalizer>? Localizer { get; set; } - - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - /// /// 获得/设置 设置文件格式图标回调委托 /// @@ -190,6 +182,14 @@ public partial class ButtonUpload [Parameter] public Func? OnCancel { get; set; } + [Inject] + [NotNull] + private IStringLocalizer>? Localizer { get; set; } + + [Inject] + [NotNull] + private IIconTheme? IconTheme { get; set; } + private string? ClassString => CssBuilder.Default("upload") .AddClassFromAttributes(AdditionalAttributes) .Build(); diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index b8e784bc369..9b857bb684c 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -48,5 +48,17 @@ }
} + @if (ShowUploadFileList) + { + + }
diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 9cdabdd6646..5eaf3e4c767 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -63,6 +63,138 @@ public partial class DropUpload [NotNull] public string? FooterText { get; set; } + /// + /// 获得/设置 是否显示上传列表 默认 true + /// + [Parameter] + public bool ShowUploadFileList { get; set; } = true; + + /// + /// 获得/设置 设置文件格式图标回调委托 + /// + [Parameter] + public Func? OnGetFileFormat { get; set; } + + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + + /// + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + + /// + /// 获得/设置 是否显示下载按钮 默认 false + /// + [Parameter] + public bool ShowDownloadButton { get; set; } + + /// + /// 获得/设置 点击下载按钮回调方法 默认 null + /// + [Parameter] + public Func? OnDownload { get; set; } + + /// + /// 获得/设置 下载按钮图标 + /// + [Parameter] + public string? DownloadIcon { get; set; } + + /// + /// 获得/设置 加载中图标 + /// + [Parameter] + public string? LoadingIcon { get; set; } + + /// + /// 获得/设置 上传失败状态图标 + /// + [Parameter] + public string? InvalidStatusIcon { get; set; } + + /// + /// 获得/设置 上传成功状态图标 + /// + [Parameter] + public string? ValidStatusIcon { get; set; } + + /// + /// 获得/设置 删除按钮图标 + /// + [Parameter] + public string? DeleteIcon { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconExcel { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconDocx { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPPT { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconAudio { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconVideo { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconCode { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPdf { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconZip { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconArchive { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconImage { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconFile { get; set; } + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } From 32218eba08ead78b5a190319949393401c240f06 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 14:57:19 +0800 Subject: [PATCH 110/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadDrops.razor | 18 ++++++++++++------ .../Components/Samples/UploadDrops.razor.cs | 12 ++++-------- .../Components/Upload/DropUpload.razor | 3 ++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor index fc3a685b0f2..c6d7c0a1a03 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor @@ -26,6 +26,18 @@
+
+ + + + +
+
+ + + + +
@@ -43,12 +55,6 @@ -
- @foreach (var file in _dropFiles) - { -
@file.GetFileName()
- } -
diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs index aa12413f62f..0cc56c2b423 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -14,17 +14,13 @@ public partial class UploadDrops private bool _isDisabled = false; private bool _showProgress = true; private bool _showFooter = true; + private bool _showUploadFileList = true; + private bool _showDownloadButton = true; - private readonly List _dropFiles = []; - - private async Task OnDropUpload(UploadFile file) + private Task OnDropUpload(UploadFile file) { // 模拟保存文件等处理 - await Task.Delay(1000); - - // 添加文件到集合中,用于 UI 呈现上传列表 - _dropFiles.Add(file); - StateHasChanged(); + return Task.Delay(1000); } private List GetAttributes() => diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 9b857bb684c..71a623d8db4 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -58,7 +58,8 @@ FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" - FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + }
From 7e719edbe0e3d52be2ea3cee1e40b4d5a5c533af Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 15:12:03 +0800 Subject: [PATCH 111/177] =?UTF-8?q?doc:=20=E7=B2=BE=E7=AE=80=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8C=96=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadDrops.razor.cs | 16 ---------------- src/BootstrapBlazor.Server/Locales/en-US.json | 2 -- src/BootstrapBlazor.Server/Locales/zh-CN.json | 2 -- 3 files changed, 20 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs index 0cc56c2b423..800b30870e9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -25,22 +25,6 @@ private Task OnDropUpload(UploadFile file) private List GetAttributes() => [ - new() - { - Name = "IsDirectory", - Description = Localizer["UploadsIsDirectory"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, - new() - { - Name = "IsMultiple", - Description = Localizer["UploadsIsMultiple"], - Type = "bool", - ValueList = "true|false", - DefaultValue = "false" - }, new() { Name = "BodyTemplate", diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 981337f74f9..cacaf6bcbf0 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3535,8 +3535,6 @@ "DropUploadTitle": "Basic usage", "DropUploadIntro": "Handle all uploaded files via the OnChange callback", "DropUploadFooterText": "File size should not exceed 5Mb", - "UploadsIsDirectory": "Whether to upload the entire directory", - "UploadsIsMultiple": "Whether to allow multiple file uploads", "UploadsBodyTemplate": "Body Template", "UploadsIconTemplate": "Icon Template", "UploadsTextTemplate": "Text Template", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 8e649eed7d6..8862323cdc1 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3535,8 +3535,6 @@ "DropUploadTitle": "基础用法", "DropUploadIntro": "通过 OnChange 回调处理所有上传文件", "DropUploadFooterText": "文件大小不超过 5Mb", - "UploadsIsDirectory": "是否上传整个目录", - "UploadsIsMultiple": "是否允许多文件上传", "UploadsBodyTemplate": "Body 模板", "UploadsIconTemplate": "图标模板", "UploadsTextTemplate": "文字模板", From 11a2d76da54a6175f0e10dcafa6b3a6d9b9eadac Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 23 May 2025 19:19:42 +0800 Subject: [PATCH 112/177] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8=20Files?= =?UTF-8?q?=20=E5=B1=9E=E6=80=A7=E6=8F=90=E9=AB=98=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 2 +- .../Components/Upload/AvatarUpload.razor.cs | 9 ++++----- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 4 ++-- .../Components/Upload/CardUpload.razor | 2 +- .../Components/Upload/CardUpload.razor.cs | 8 ++++---- .../Components/Upload/DropUpload.razor | 2 +- .../Components/Upload/InputUpload.razor.cs | 9 ++++----- .../Components/Upload/UploadBase.cs | 19 ++++++++++++++----- 9 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 0ddc92abd6f..55daadcb422 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -12,7 +12,7 @@ { @RenderAdd } - @foreach (var item in GetUploadFiles()) + @foreach (var item in Files) {
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index e6709fa2edb..3a600a54870 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -153,11 +153,11 @@ private bool CheckCanUpload() // 允许多上传 if (IsMultiple) { - return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; + return !MaxFileCount.HasValue || Files.Count < MaxFileCount; } // 只允许单个上传 - return GetUploadFiles().Count == 0; + return Files.Count == 0; } /// @@ -166,9 +166,8 @@ private bool CheckCanUpload() /// protected override string? RetrieveId() { - var files = GetUploadFiles(); - return files.Count == 0 ? $"{Id}_new" : files[0].ValidateId; + return Files.Count == 0 ? $"{Id}_new" : Files[0].ValidateId; } - private string? AddId => GetUploadFiles().Count == 0 ? $"{Id}_new" : null; + private string? AddId => Files.Count == 0 ? $"{Id}_new" : null; } diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 600f859bc5a..94ab50dbd87 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -12,7 +12,7 @@ @if (ShowUploadFileList) { - = MaxFileCount; + return MaxFileCount.HasValue && Files.Count >= MaxFileCount; } // 只允许单个上传 - return GetUploadFiles().Count > 0; + return Files.Count > 0; } } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 33ceb43c917..95b95f787ee 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -12,7 +12,7 @@ { @RenderAdd } - @foreach (var item in GetUploadFiles()) + @foreach (var item in Files) {
diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index cbd8b9a28ca..2975e670679 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -28,9 +28,9 @@ public partial class CardUpload private string? GetDisabledString(UploadFile item) => (!IsDisabled && item is { Uploaded: true, Code: 0 }) ? null : "disabled"; - private bool ShowPreviewList => GetUploadFiles().Count != 0; + private bool ShowPreviewList => Files.Count != 0; - private List PreviewList => GetUploadFiles().Select(i => i.PrevUrl).ToList(); + private List PreviewList => Files.Select(i => i.PrevUrl).ToList(); private string? GetDeleteButtonDisabledString(UploadFile item) => (!IsDisabled && item.Uploaded) ? null : "disabled"; @@ -257,11 +257,11 @@ private bool CheckCanUpload() // 允许多上传 if (IsMultiple) { - return !MaxFileCount.HasValue || GetUploadFiles().Count < MaxFileCount; + return !MaxFileCount.HasValue || Files.Count < MaxFileCount; } // 只允许单个上传 - return GetUploadFiles().Count == 0; + return Files.Count == 0; } private async Task OnCardFileDelete(UploadFile item) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 71a623d8db4..e6cc5a0a8b2 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -50,7 +50,7 @@ } @if (ShowUploadFileList) { - = MaxFileCount; + return MaxFileCount.HasValue && Files.Count >= MaxFileCount; } // 只允许单个上传 - return GetUploadFiles().Count > 0; + return Files.Count > 0; } private async Task TriggerDeleteFile() { - var files = GetUploadFiles(); - for (var index = files.Count; index > 0; index--) + for (var index = Files.Count; index > 0; index--) { - var item = files[index - 1]; + var item = Files[index - 1]; await OnFileDelete(item); } CurrentValue = default; diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index e62a656e0d8..6443f924b0d 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -94,6 +94,11 @@ public abstract class UploadBase : ValidateBase, IUpload ///
public List UploadFiles { get; } = []; + /// + /// Gets the collection of files to be uploaded. + /// + protected List Files => GetUploadFiles(); + /// /// /// @@ -228,6 +233,7 @@ protected void Update(UploadFile file) } } + private List? _filesCache; /// /// Get the files collection. /// 获得当前文件集合 @@ -235,13 +241,16 @@ protected void Update(UploadFile file) /// protected List GetUploadFiles() { - var ret = new List(); - if (DefaultFileList != null) + if (_filesCache == null) { - ret.AddRange(DefaultFileList); + _filesCache = []; + if (DefaultFileList != null) + { + _filesCache.AddRange(DefaultFileList); + } + _filesCache.AddRange(UploadFiles); } - ret.AddRange(UploadFiles); - return ret; + return _filesCache; } /// From 0aaa1305e42dcda5fe3ec383508e51c22781e499 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 09:52:24 +0800 Subject: [PATCH 113/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor index c6d7c0a1a03..1b2949baba6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor @@ -54,7 +54,7 @@ + ShowProgress="@_showProgress" ShowUploadFileList="@_showUploadFileList" ShowFooter="@_showFooter"> From 37a21688f425c46c11c0dca4ad95b24b4417a078 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 10:25:20 +0800 Subject: [PATCH 114/177] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E5=B7=B2?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=88=97=E8=A1=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 12 ------- .../Components/Upload/CardUpload.razor.cs | 14 +-------- .../Components/Upload/DropUpload.razor.cs | 6 ++-- .../Components/Upload/UploadBase.cs | 31 ++++++++++++++++--- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 3a600a54870..73af19d56ef 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -148,18 +148,6 @@ protected override void OnParametersSet() }; } - private bool CheckCanUpload() - { - // 允许多上传 - if (IsMultiple) - { - return !MaxFileCount.HasValue || Files.Count < MaxFileCount; - } - - // 只允许单个上传 - return Files.Count == 0; - } - /// /// 获得 数据验证客户端 ID /// diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 2975e670679..7f80cd89174 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -19,7 +19,7 @@ public partial class CardUpload .AddClass("is-invalid", item.Code != 0) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") - .AddClass("disabled", IsDisabled) + .AddClass("disabled", CheckCanUpload() == false) .Build(); private string? BodyClassString => CssBuilder.Default("upload-body is-card") @@ -252,18 +252,6 @@ protected override void OnParametersSet() FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } - private bool CheckCanUpload() - { - // 允许多上传 - if (IsMultiple) - { - return !MaxFileCount.HasValue || Files.Count < MaxFileCount; - } - - // 只允许单个上传 - return Files.Count == 0; - } - private async Task OnCardFileDelete(UploadFile item) { await OnFileDelete(item); diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 5eaf3e4c767..bfb6fe8f389 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -204,16 +204,16 @@ public partial class DropUpload private IStringLocalizer>? Localizer { get; set; } private string? ClassString => CssBuilder.Default("upload is-drop") - .AddClass("disabled", IsDisabled) + .AddClass("disabled", CheckCanUpload() == false) .AddClassFromAttributes(AdditionalAttributes) .Build(); private string? BodyClassString => CssBuilder.Default("upload-drop-body") - .AddClass("btn-browser", !IsDisabled) + .AddClass("btn-browser", CheckCanUpload()) .Build(); private string? TextClassString => CssBuilder.Default("upload-drop-text") - .AddClass("text-muted", IsDisabled) + .AddClass("text-muted", CheckCanUpload() == false) .Build(); /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 6443f924b0d..94d8c7f85f8 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -151,6 +151,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) foreach (var item in items) { + _filesCache = null; UploadFiles.Add(item); // trigger OnChange event callback @@ -209,6 +210,7 @@ protected virtual async Task OnFileDelete(UploadFile item) } UploadFiles.Remove(item); DefaultFileList?.Remove(item); + _filesCache = null; } StateHasChanged(); return ret; @@ -235,8 +237,8 @@ protected void Update(UploadFile file) private List? _filesCache; /// - /// Get the files collection. /// 获得当前文件集合 + /// Get the files collection. /// /// protected List GetUploadFiles() @@ -253,8 +255,31 @@ protected List GetUploadFiles() return _filesCache; } + /// + /// 检查是否可以继续上传文件 + /// Check whether can upload file. + /// + /// + protected bool CheckCanUpload() + { + if(IsDisabled) + { + return false; + } + + // 允许多上传 + if (IsMultiple) + { + return !MaxFileCount.HasValue || Files.Count < MaxFileCount; + } + + // 只允许单个上传 + return Files.Count == 0; + } + /// /// 清空上传列表方法 + /// Clear the upload files collection. /// public virtual void Reset() { @@ -274,9 +299,7 @@ public override void ToggleMessage(IEnumerable results) var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.Value.FieldName)).ToList(); if (messages.Count == 0) { - messages = results.Where(item => item.MemberNames.Any(m => - UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false))) - .ToList(); + messages = [.. results.Where(item => item.MemberNames.Any(m => UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false)))]; } if (messages.Count > 0) { From b4828953332100c2ada082d7fe0d49221ef09ab4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 10:59:54 +0800 Subject: [PATCH 115/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20ButtonUplo?= =?UTF-8?q?ad=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 41 ++++++------------ .../Components/Upload/UploadBase.cs | 2 +- test/UnitTest/Components/UploadButtonTest.cs | 43 ++++++++++++++----- 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 94ab50dbd87..c17dbb3fdd5 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -7,7 +7,7 @@ }
- @if (ShowUploadFileList) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index f1cbe98af46..31676e1ba30 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -104,6 +104,18 @@ public partial class ButtonUpload [Parameter] public Func? OnDownload { get; set; } + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + + /// + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + /// /// 获得/设置 Excel 类型文件图标 /// @@ -170,18 +182,6 @@ public partial class ButtonUpload [Parameter] public string? FileIconFile { get; set; } - /// - /// 获得/设置 取消图标 - /// - [Parameter] - public string? CancelIcon { get; set; } - - /// - /// 获得/设置 点击取消按钮回调此方法 默认 null - /// - [Parameter] - public Func? OnCancel { get; set; } - [Inject] [NotNull] private IStringLocalizer>? Localizer { get; set; } @@ -208,21 +208,4 @@ protected override void OnParametersSet() BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadBrowserButtonIcon); } - - private bool CheckStatus() - { - if (IsDisabled) - { - return true; - } - - // 允许多上传 - if (IsMultiple) - { - return MaxFileCount.HasValue && Files.Count >= MaxFileCount; - } - - // 只允许单个上传 - return Files.Count > 0; - } } diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 94d8c7f85f8..46f688f8fac 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -262,7 +262,7 @@ protected List GetUploadFiles() /// protected bool CheckCanUpload() { - if(IsDisabled) + if (IsDisabled) { return false; } diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index ed553b25c4c..077d267e994 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -156,6 +156,7 @@ public async Task ButtonUpload_Validate_Ok() pb.Add(a => a.Accept, "Image"); pb.Add(a => a.Value, foo.Name); pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + pb.Add(a => a.ShowUploadFileList, true); }); pb.Add(a => a.OnValidSubmit, context => { @@ -311,6 +312,24 @@ public void ButtonUpload_OnGetFileFormat_Ok() { var cut = Context.RenderComponent>(pb => { + pb.Add(a => a.LoadingIcon, "fa-loading"); + pb.Add(a => a.DeleteIcon, "fa-delte"); + pb.Add(a => a.CancelIcon, "fa-cancel"); + pb.Add(a => a.DownloadIcon, "fa-download"); + pb.Add(a => a.InvalidStatusIcon, "fa-invalid"); + pb.Add(a => a.ValidStatusIcon, "fa-valid"); + + pb.Add(a => a.FileIconArchive, "fa-file-text"); + pb.Add(a => a.FileIconExcel, "fa-file-excel"); + pb.Add(a => a.FileIconFile, "fa-file"); + pb.Add(a => a.FileIconDocx, "fa-file-word"); + pb.Add(a => a.FileIconPPT, "fa-file-powerpoint"); + pb.Add(a => a.FileIconAudio, "fa-file-audio"); + pb.Add(a => a.FileIconVideo, "fa-file-video"); + pb.Add(a => a.FileIconCode, "fa-file-code"); + pb.Add(a => a.FileIconPdf, "fa-file-pdf"); + pb.Add(a => a.FileIconImage, "fa-file-image"); + pb.Add(a => a.FileIconZip, "fa-file-archive"); pb.Add(a => a.DefaultFileList, [ new() { FileName = "1.csv" }, @@ -343,18 +362,20 @@ public void ButtonUpload_OnGetFileFormat_Ok() new() { FileName = "1.test" }, new() { FileName = "1" } ]); + }); - cut.Contains("fa-regular fa-file-excel"); - cut.Contains("fa-regular fa-file-word"); - cut.Contains("fa-regular fa-file-powerpoint"); - cut.Contains("fa-regular fa-file-audio"); - cut.Contains("fa-regular fa-file-video"); - cut.Contains("fa-regular fa-file-code"); - cut.Contains("fa-regular fa-file-pdf"); - cut.Contains("fa-regular fa-file-archive"); - cut.Contains("fa-regular fa-file-text"); - cut.Contains("fa-regular fa-file-image"); - cut.Contains("fa-regular fa-file"); + cut.Contains("fa-file-excel"); + cut.Contains("fa-file-word"); + cut.Contains("fa-file-powerpoint"); + cut.Contains("fa-file-audio"); + cut.Contains("fa-file-video"); + cut.Contains("fa-file-code"); + cut.Contains("fa-file-pdf"); + cut.Contains("fa-file-archive"); + cut.Contains("fa-file-text"); + cut.Contains("fa-file-image"); + cut.Contains("fa-file-archive"); + cut.Contains("fa-file"); cut.SetParametersAndRender(pb => { From 1d713bcb0d35c002abfe7a33f5f63492d0a4b2f3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 15:18:58 +0800 Subject: [PATCH 116/177] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86=20ShowAd?= =?UTF-8?q?dButton=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 4 ++-- .../Components/Upload/AvatarUpload.razor.cs | 7 ++++++- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/ButtonUpload.razor.cs | 2 ++ .../Components/Upload/CardUpload.razor | 4 ++-- .../Components/Upload/CardUpload.razor.cs | 2 +- .../Components/Upload/DropUpload.razor.cs | 6 +++--- .../Components/Upload/UploadBase.cs | 21 +++++++++++++------ test/UnitTest/Components/UploadAvatarTest.cs | 1 - 9 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 55daadcb422..883902bbb07 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -8,7 +8,7 @@ }
- @if (IsUploadButtonAtFirst && CheckCanUpload()) + @if (IsUploadButtonAtFirst && ShowAddButton()) { @RenderAdd } @@ -39,7 +39,7 @@ }
} - @if (!IsUploadButtonAtFirst && CheckCanUpload()) + @if (!IsUploadButtonAtFirst && ShowAddButton()) { @RenderAdd } diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 73af19d56ef..ee0fb7fe1a7 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -96,7 +96,12 @@ public partial class AvatarUpload return null; } - var state = item?.IsValid ?? IsValid; + if(item == null) + { + return null; + } + + var state = item.IsValid ?? IsValid; if (state == null) { return null; diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index c17dbb3fdd5..94ab50dbd87 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -7,7 +7,7 @@ }
- @if (ShowUploadFileList) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index 31676e1ba30..a25d393cacf 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -208,4 +208,6 @@ protected override void OnParametersSet() BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadBrowserButtonIcon); } + + private bool CheckStatus() => IsDisabled || CanUpload() == false; } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 95b95f787ee..194dae8f0b3 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -8,7 +8,7 @@ }
- @if (IsUploadButtonAtFirst && CheckCanUpload()) + @if (IsUploadButtonAtFirst && ShowAddButton()) { @RenderAdd } @@ -70,7 +70,7 @@
} - @if (!IsUploadButtonAtFirst && CheckCanUpload()) + @if (!IsUploadButtonAtFirst && ShowAddButton()) { @RenderAdd } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 7f80cd89174..527e6e7af54 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -19,7 +19,7 @@ public partial class CardUpload .AddClass("is-invalid", item.Code != 0) .Build(); private string? ItemClassString => CssBuilder.Default("upload-item") - .AddClass("disabled", CheckCanUpload() == false) + .AddClass("disabled", CanUpload() == false) .Build(); private string? BodyClassString => CssBuilder.Default("upload-body is-card") diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index bfb6fe8f389..dedc0fb4307 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -204,16 +204,16 @@ public partial class DropUpload private IStringLocalizer>? Localizer { get; set; } private string? ClassString => CssBuilder.Default("upload is-drop") - .AddClass("disabled", CheckCanUpload() == false) + .AddClass("disabled", CanUpload() == false) .AddClassFromAttributes(AdditionalAttributes) .Build(); private string? BodyClassString => CssBuilder.Default("upload-drop-body") - .AddClass("btn-browser", CheckCanUpload()) + .AddClass("btn-browser", CanUpload()) .Build(); private string? TextClassString => CssBuilder.Default("upload-drop-text") - .AddClass("text-muted", CheckCanUpload() == false) + .AddClass("text-muted", CanUpload() == false) .Build(); /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 46f688f8fac..2a849e884cc 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -260,13 +260,8 @@ protected List GetUploadFiles() /// Check whether can upload file. /// /// - protected bool CheckCanUpload() + protected bool CanUpload() { - if (IsDisabled) - { - return false; - } - // 允许多上传 if (IsMultiple) { @@ -277,6 +272,20 @@ protected bool CheckCanUpload() return Files.Count == 0; } + /// + /// 判断是否显示新建按钮 + /// + /// + protected bool ShowAddButton() + { + if (IsDisabled) + { + return Files.Count == 0; + } + + return CanUpload(); + } + /// /// 清空上传列表方法 /// Clear the upload files collection. diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 17807fc2aa9..062af68da7d 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -4,7 +4,6 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using Microsoft.AspNetCore.Components.Forms; -using System.ComponentModel.DataAnnotations; namespace UnitTest.Components; From f4c38e8aefd834d2dcf675a5b93950df97f25fad Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 15:26:46 +0800 Subject: [PATCH 117/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 2 +- src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs | 1 + test/UnitTest/Components/UploadAvatarTest.cs | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index dc727ad3b1e..696abf997b9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -43,7 +43,7 @@
- +
diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index ee0fb7fe1a7..e4febe51d14 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -7,6 +7,7 @@ namespace BootstrapBlazor.Components; /// /// 头像上传组件 +/// AvatarUpload Component /// public partial class AvatarUpload { diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 062af68da7d..5f2ffae439f 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -82,12 +82,14 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha { pb.Add(a => a.IsDisabled, true); }); - cut.Contains("upload-item-actions"); + cut.DoesNotContain("upload-item-actions"); // IsUploadButtonAtFirst cut.SetParametersAndRender(pb => { pb.Add(a => a.IsUploadButtonAtFirst, true); + pb.Add(a => a.IsDisabled, false); + pb.Add(a => a.IsMultiple, true); }); } From 128cfcdb93e4da65ebe9e61177c54bfd525b68fc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 18:32:13 +0800 Subject: [PATCH 118/177] =?UTF-8?q?refactor:=20=E5=A4=8D=E7=94=A8=20CanUpl?= =?UTF-8?q?oad=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 8dbaf7f3885..d4a7aada353 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -109,14 +109,7 @@ private bool CheckStatus() return true; } - // 允许多上传 - if (IsMultiple) - { - return MaxFileCount.HasValue && Files.Count >= MaxFileCount; - } - - // 只允许单个上传 - return Files.Count > 0; + return CanUpload(); } private async Task TriggerDeleteFile() From 22c413e22d76745dddedfa7870f0adda08a79f77 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 18:40:13 +0800 Subject: [PATCH 119/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/CardUpload.razor | 3 +- .../Components/Upload/CardUpload.razor.cs | 8 +++++ test/UnitTest/Components/UploadCardTest.cs | 35 +++++-------------- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 194dae8f0b3..9d5a924986e 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -75,12 +75,11 @@ @RenderAdd }
- - @if (ShowPreviewList) { } +
@code { diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 527e6e7af54..67d31809d2d 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -106,8 +106,16 @@ public partial class CardUpload /// 获得/设置 是否显示删除按钮 默认 true 显示 ///
[Parameter] + [Obsolete("已弃用,请使用 ShowDeleteButton 参数。Deprecated, please use the ShowDeleteButton parameter")] + [ExcludeFromCodeCoverage] public bool ShowDeletedButton { get; set; } = true; + /// + /// 获得/设置 是否显示删除按钮 默认 true 显示 + /// + [Parameter] + public bool ShowDeleteButton { get; set; } = true; + /// /// 获得/设置 继续上传按钮是否在列表前 默认 false /// diff --git a/test/UnitTest/Components/UploadCardTest.cs b/test/UnitTest/Components/UploadCardTest.cs index 704de4045dd..e80c530fdbe 100644 --- a/test/UnitTest/Components/UploadCardTest.cs +++ b/test/UnitTest/Components/UploadCardTest.cs @@ -4,7 +4,6 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using Microsoft.AspNetCore.Components.Forms; -using System.ComponentModel.DataAnnotations; namespace UnitTest.Components; @@ -17,6 +16,8 @@ public async Task CardUpload_Ok() var deleted = false; var cut = Context.RenderComponent>(pb => { + pb.Add(a => a.ShowZoomButton, true); + pb.Add(a => a.ShowDeleteButton, true); pb.Add(a => a.OnDelete, file => { deleted = true; @@ -35,6 +36,8 @@ public async Task CardUpload_Ok() ]); }); cut.Contains("bb-previewer collapse active"); + cut.Contains("aria-label=\"zoom\""); + cut.Contains("aria-label=\"delete\""); cut.SetParametersAndRender(pb => { @@ -119,7 +122,11 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha { pb.Add(a => a.IsUploadButtonAtFirst, true); pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.ShowZoomButton, false); + pb.Add(a => a.ShowDeleteButton, false); }); + cut.DoesNotContain("aria-label=\"zoom\""); + cut.DoesNotContain("aria-label=\"delete\""); } [Fact] @@ -170,32 +177,6 @@ await cut.InvokeAsync(() => Assert.True(cancel); } - //[Fact] - //public async Task CardUpload_Max_Ok() - //{ - // var cut = Context.RenderComponent>(pb => - // { - // pb.Add(a => a.ShowProgress, true); - // pb.Add(a => a.Max, 1); - // }); - // var input = cut.FindComponent(); - // await cut.InvokeAsync(async () => - // { - // await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - // { - // new() - // })); - // }); - //} - - private class Person - { - [Required] - [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] - - public IBrowserFile? Picture { get; set; } - } - private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; From 276ca59229b8fe78b3b3cd61f44a23ae07fd4904 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 19:27:32 +0800 Subject: [PATCH 120/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadCards.razor | 4 +- .../Components/Upload/CardUpload.razor | 2 +- .../Extensions/UploadFileExtensions.cs | 5 +- test/UnitTest/Components/UploadAvatarTest.cs | 20 + test/UnitTest/Components/UploadDropTest.cs | 201 +++ test/UnitTest/Components/UploadFileTest.cs | 37 + test/UnitTest/Components/UploadTest.cs | 1126 ----------------- 7 files changed, 265 insertions(+), 1130 deletions(-) create mode 100644 test/UnitTest/Components/UploadDropTest.cs create mode 100644 test/UnitTest/Components/UploadFileTest.cs delete mode 100644 test/UnitTest/Components/UploadTest.cs diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor index 0077b42934b..841d13409e4 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadCards.razor @@ -68,7 +68,7 @@ @@ -97,5 +97,5 @@ - + diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 9d5a924986e..33eec8ecd47 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -51,7 +51,7 @@ }
- @if (ShowDeletedButton) + @if (ShowDeleteButton) { /// /// + [ExcludeFromCodeCoverage] public static async Task RequestBase64ImageFileAsync(this UploadFile upload, string? format = null, int maxWidth = 320, int maxHeight = 240, long? maxAllowedSize = null, CancellationToken token = default) { if (upload.File != null) { try { - format ??= upload.File.ContentType; + format ??= upload.File.ContentType; var imageFile = await upload.File.RequestImageFileAsync(format, maxWidth, maxHeight); maxAllowedSize ??= upload.File.Size; @@ -54,6 +55,7 @@ public static async Task RequestBase64ImageFileAsync(this UploadFile upload, str /// /// /// + [ExcludeFromCodeCoverage] public static async Task SaveToFileAsync(this UploadFile upload, string fileName, long maxAllowedSize = 512000, CancellationToken token = default) { var ret = false; @@ -129,6 +131,7 @@ public static async Task SaveToFileAsync(this UploadFile upload, string fi /// /// /// + [ExcludeFromCodeCoverage] public static async Task GetBytesAsync(this UploadFile upload, string format, int maxWidth, int maxHeight, long maxAllowedSize = 512000, CancellationToken token = default) { byte[]? ret = null; diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 5f2ffae439f..95e8bcd8a2c 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -4,6 +4,7 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using Microsoft.AspNetCore.Components.Forms; +using System.Runtime.CompilerServices; namespace UnitTest.Components; @@ -161,6 +162,22 @@ await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List< Assert.DoesNotContain("is-invalid", upload.Markup); } + [Fact] + public void AvatarUpload_ShowProgress_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async file => + { + await Task.Delay(100); + await file.SaveToFileAsync("1.txt"); + SetUploaded(file, false); + }); + }); + var input = cut.FindComponent(); + } + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; @@ -176,4 +193,7 @@ public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken can return new MemoryStream([0x01, 0x02]); } } + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Uploaded")] + static extern void SetUploaded(UploadFile @this, bool v); } diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs new file mode 100644 index 00000000000..ac84703384c --- /dev/null +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -0,0 +1,201 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; + +namespace UnitTest.Components; + +public class UploadDropTest : BootstrapBlazorTestBase +{ + [Fact] + public void DropUpload_BodyTemplate_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.BodyTemplate, b => b.AddContent(0, "drop-upload-body-template")); + }); + cut.MarkupMatches("
drop-upload-body-template
    "); + } + + [Fact] + public void DropUpload_IconTemplate_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.IconTemplate, b => b.AddContent(0, "drop-upload-icon-template")); + }); + cut.Contains("
    drop-upload-icon-template
    "); + } + + [Fact] + public void DropUpload_TextTemplate_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.TextTemplate, b => b.AddContent(0, "drop-upload-text-template")); + }); + cut.Contains("
    drop-upload-text-template
    "); + } + + [Fact] + public void DropUpload_Footer_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.ShowFooter, true); + }); + cut.Contains("
    "); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.FooterTemplate, b => b.AddContent(0, "drop-upload-footer-text")); + }); + cut.Contains("
    drop-upload-footer-text
    "); + } + + [Fact] + public async Task DropUpload_OnChanged_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.ShowLabel, true); + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async files => + { + await files.SaveToFileAsync("1.text"); + }); + }); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + }))); + } + + [Fact] + public async Task ShowUploadList_Ok() + { + UploadFile? file = null; + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.ShowUploadFileList, true); + pb.Add(a => a.ShowDownloadButton, true); + pb.Add(a => a.OnDownload, f => + { + file = f; + return Task.CompletedTask; + }); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "Test-File1.text" }, + new() { FileName = "Test-File2.jpg" }, + ]); + }); + cut.Contains("upload-body is-list"); + + var button = cut.Find(".download-icon"); + await cut.InvokeAsync(() => button.Click()); + Assert.NotNull(file); + } + + [Fact] + public void ButtonUpload_OnGetFileFormat_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.LoadingIcon, "fa-loading"); + pb.Add(a => a.DeleteIcon, "fa-delte"); + pb.Add(a => a.CancelIcon, "fa-cancel"); + pb.Add(a => a.DownloadIcon, "fa-download"); + pb.Add(a => a.InvalidStatusIcon, "fa-invalid"); + pb.Add(a => a.ValidStatusIcon, "fa-valid"); + + pb.Add(a => a.FileIconArchive, "fa-file-text"); + pb.Add(a => a.FileIconExcel, "fa-file-excel"); + pb.Add(a => a.FileIconFile, "fa-file"); + pb.Add(a => a.FileIconDocx, "fa-file-word"); + pb.Add(a => a.FileIconPPT, "fa-file-powerpoint"); + pb.Add(a => a.FileIconAudio, "fa-file-audio"); + pb.Add(a => a.FileIconVideo, "fa-file-video"); + pb.Add(a => a.FileIconCode, "fa-file-code"); + pb.Add(a => a.FileIconPdf, "fa-file-pdf"); + pb.Add(a => a.FileIconImage, "fa-file-image"); + pb.Add(a => a.FileIconZip, "fa-file-archive"); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "1.csv" }, + new() { FileName = "1.xls" }, + new() { FileName = "1.xlsx" }, + new() { FileName = "1.doc" }, + new() { FileName = "1.docx" }, + new() { FileName = "1.dot" }, + new() { FileName = "1.ppt" }, + new() { FileName = "1.pptx" }, + new() { FileName = "1.wav" }, + new() { FileName = "1.mp3" }, + new() { FileName = "1.mp4" }, + new() { FileName = "1.mov" }, + new() { FileName = "1.mkv" }, + new() { FileName = "1.cs" }, + new() { FileName = "1.html" }, + new() { FileName = "1.vb" }, + new() { FileName = "1.pdf" }, + new() { FileName = "1.zip" }, + new() { FileName = "1.rar" }, + new() { FileName = "1.iso" }, + new() { FileName = "1.txt" }, + new() { FileName = "1.log" }, + new() { FileName = "1.jpg" }, + new() { FileName = "1.jpeg" }, + new() { FileName = "1.png" }, + new() { FileName = "1.bmp" }, + new() { FileName = "1.gif" }, + new() { FileName = "1.test" }, + new() { FileName = "1" } + ]); + + }); + cut.Contains("fa-file-excel"); + cut.Contains("fa-file-word"); + cut.Contains("fa-file-powerpoint"); + cut.Contains("fa-file-audio"); + cut.Contains("fa-file-video"); + cut.Contains("fa-file-code"); + cut.Contains("fa-file-pdf"); + cut.Contains("fa-file-archive"); + cut.Contains("fa-file-text"); + cut.Contains("fa-file-image"); + cut.Contains("fa-file-archive"); + cut.Contains("fa-file"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.OnGetFileFormat, extensions => + { + return "fa-format-test"; + }); + }); + cut.Contains("fa-format-test"); + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} diff --git a/test/UnitTest/Components/UploadFileTest.cs b/test/UnitTest/Components/UploadFileTest.cs new file mode 100644 index 00000000000..efdf2b12e8d --- /dev/null +++ b/test/UnitTest/Components/UploadFileTest.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; + +namespace UnitTest.Components; + +public class UploadFileTest +{ + [Fact] + public async Task RequestBase64ImageFileAsync_Ok() + { + UploadFile uploadFile = new() + { + File = new MockBrowserFile("UploadTestFile", "image/png") + }; + await uploadFile.RequestBase64ImageFileAsync(format: "image/png", maxWidth: 320, maxHeight: 240, maxAllowedSize: 512000, token: default); + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} diff --git a/test/UnitTest/Components/UploadTest.cs b/test/UnitTest/Components/UploadTest.cs deleted file mode 100644 index cbe006eb510..00000000000 --- a/test/UnitTest/Components/UploadTest.cs +++ /dev/null @@ -1,1126 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.AspNetCore.Components.Forms; -using System.ComponentModel.DataAnnotations; - -namespace UnitTest.Components; - -public class UploadTest : BootstrapBlazorTestBase -{ - [Fact] - public async Task InputUpload_Ok() - { - UploadFile? uploadFile = null; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.PlaceHolder, "TestPlaceHolder"); - pb.Add(a => a.OnChange, file => - { - uploadFile = file; - return Task.CompletedTask; - }); - pb.Add(a => a.Value, "test.jpg"); - }); - cut.Contains("value=\"test.jpg\""); - - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - Assert.Equal("UploadTestFile", uploadFile!.OriginFileName); - cut.Contains("fa-regular fa-folder-open"); - cut.Contains("btn-primary"); - cut.Contains("TestPlaceHolder"); - - // 参数 - cut.SetParametersAndRender(pb => pb.Add(a => a.BrowserButtonIcon, "fa-solid fa-chrome")); - cut.Contains("fa-solid fa-chrome"); - - cut.SetParametersAndRender(pb => pb.Add(a => a.BrowserButtonClass, "btn btn-browser")); - cut.Contains("btn btn-browser"); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowDeleteButton, true); - pb.Add(a => a.DeleteButtonText, "Delete-Test"); - pb.Add(a => a.DeleteButtonIcon, "fa-solid fa-trash"); - }); - cut.WaitForAssertion(() => cut.Contains("fa-solid fa-trash")); - cut.Contains("btn-danger"); - - // 删除逻辑 - var deleted = false; - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.DeleteButtonClass, "btn btn-delete"); - pb.Add(a => a.OnDelete, file => - { - deleted = true; - return Task.FromResult(true); - }); - }); - cut.WaitForAssertion(() => cut.Contains("btn btn-delete")); - - var button = cut.Find(".input-group button"); - await cut.InvokeAsync(() => button.Click()); - Assert.True(deleted); - - // IsDisable - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsDisabled, true); - }); - cut.WaitForAssertion(() => cut.Contains("btn btn-delete")); - } - - [Fact] - public async Task InputUpload_ValidateForm_Ok() - { - var invalid = false; - var foo = new Foo(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - pb.Add(a => a.OnValidSubmit, context => - { - invalid = false; - return Task.CompletedTask; - }); - pb.Add(a => a.OnInvalidSubmit, context => - { - invalid = true; - return Task.CompletedTask; - }); - }); - - // 提交表单 - var form = cut.Find("form"); - await cut.InvokeAsync(() => form.Submit()); - Assert.True(invalid); - - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - await cut.InvokeAsync(() => form.Submit()); - Assert.False(invalid); - } - - [Fact] - public void InputUpload_FileValidate_OK() - { - var foo = new Person(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Value, foo.Picture); - pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, nameof(Person.Picture), typeof(IBrowserFile))); - }); - }); - - var input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - - // 提交表单 - var form = cut.Find("form"); - cut.InvokeAsync(() => form.Submit()); - } - - [Fact] - public void AvatarUpload_Ok() - { - UploadFile? uploadFile = null; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsSingle, true); - pb.Add(a => a.OnChange, file => - { - uploadFile = file; - return Task.CompletedTask; - }); - }); - var input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - - // Height/Width - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.Height, 40); - pb.Add(a => a.Width, 50); - }); - cut.WaitForAssertion(() => cut.Contains("width: 50px;")); - cut.WaitForAssertion(() => cut.Contains("height: 40px;")); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsCircle, true); - }); - cut.WaitForAssertion(() => cut.Contains("height: 50px;")); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.Height, 0); - }); - cut.WaitForAssertion(() => cut.Contains("height: 50px;")); - - // DefaultFileList - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.OnChange, null); - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File" } - ]); - }); - input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - - // upload-item-delete - var button = cut.Find(".upload-item-delete"); - cut.InvokeAsync(() => button.Click()); - - // isdisable - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsDisabled, true); - }); - - // IsUploadButtonAtFirst - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsUploadButtonAtFirst, true); - }); - } - - [Fact] - public void AvatarUpload_Value_Ok() - { - var cut = Context.RenderComponent>(pb => pb.Add(a => a.IsSingle, true)); - var input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - cut.WaitForAssertion(() => Assert.Equal("UploadTestFile", cut.Instance.Value!.Name)); - } - - [Fact] - public async Task AvatarUpload_ListValue_Ok() - { - var cut = Context.RenderComponent>>(); - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - Assert.Single(cut.Instance.Value); - } - - [Fact] - public async Task AvatarUpload_ValidateForm_Ok() - { - var invalid = false; - var foo = new Foo(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Accept, "Image"); - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - pb.Add(a => a.OnValidSubmit, context => - { - invalid = false; - return Task.CompletedTask; - }); - pb.Add(a => a.OnInvalidSubmit, context => - { - invalid = true; - return Task.CompletedTask; - }); - }); - - // 提交表单 - var form = cut.Find("form"); - await cut.InvokeAsync(() => form.Submit()); - Assert.True(invalid); - - var input = cut.FindComponent(); - await cut.InvokeAsync(async () => - { - await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - })); - form.Submit(); - }); - Assert.False(invalid); - } - - [Fact] - public async Task AvatarUpload_Validate_Ok() - { - var invalid = true; - var foo = new Foo - { - Name = "abc" - }; - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Accept, "Image"); - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - pb.Add(a => a.OnValidSubmit, context => - { - invalid = false; - return Task.CompletedTask; - }); - }); - - // 由于设置了属性 Name 值 Validate 方法通过 - var form = cut.Find("form"); - await cut.InvokeAsync(() => form.Submit()); - Assert.False(invalid); - } - - [Fact] - public void AvatarUpload_FileValidate_Ok() - { - var foo = new Person(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Value, foo.Picture); - pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, nameof(Person.Picture), typeof(IBrowserFile))); - }); - }); - - var input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - - // 提交表单 - var form = cut.Find("form"); - cut.InvokeAsync(() => form.Submit()); - } - - [Fact] - public async Task ButtonUpload_Ok() - { - UploadFile? uploadFile = null; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsSingle, true); - pb.Add(a => a.BrowserButtonClass, "browser-class"); - pb.Add(a => a.BrowserButtonIcon, "fa-solid fa-chrome"); - pb.Add(a => a.BrowserButtonColor, Color.Success); - }); - cut.Contains("fa-solid fa-chrome"); - cut.Contains("browser-class"); - cut.Contains("btn btn-success"); - cut.DoesNotContain("form-label"); - - // DefaultFileList - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.OnChange, file => - { - uploadFile = file; - return Task.CompletedTask; - }); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - cut.DoesNotContain("cancel-icon"); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.Size, Size.ExtraSmall); - }); - cut.Contains("btn-xs"); - } - - [Fact] - public void ButtonUpload_ChildContent() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ChildContent, builder => builder.AddContent(0, new MarkupString("
    test-child-content
    "))); - }); - cut.Contains("
    test-child-content
    "); - } - - [Fact] - public void ButtonUpload_IsDisabled_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsDisabled, true); - }); - var button = cut.Find(".btn-browser"); - Assert.Contains("disabled=\"disabled\"", button.ToMarkup()); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsDisabled, false); - pb.Add(a => a.IsSingle, false); - }); - Assert.DoesNotContain("disabled=\"disabled\"", button.ToMarkup()); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsDisabled, false); - pb.Add(a => a.IsSingle, true); - }); - Assert.DoesNotContain("disabled=\"disabled\"", button.ToMarkup()); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsDisabled, false); - pb.Add(a => a.IsSingle, true); - }); - var input = cut.FindComponent(); - cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - } - - private static readonly string[] memberNames = ["bb_validate_123"]; - - [Fact] - public void ButtonUpload_ValidateForm_Ok() - { - var foo = new Foo(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - }); - cut.Contains("form-label"); - - // ValidateId 为空情况 - var uploader = cut.FindComponent>(); - var pi = typeof(ButtonUpload).GetProperty("UploadFiles", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - Assert.NotNull(pi); - var filesValue = pi.GetValue(uploader.Instance); - - if (filesValue is List fs) - { - fs.Add(new UploadFile()); - } - var results = new List() - { - new("test", memberNames) - }; - uploader.Instance.ToggleMessage(results); - } - - [Fact] - public async Task ButtonUpload_ShowDownload() - { - var clicked = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowDownloadButton, true); - pb.Add(a => a.OnDownload, file => - { - clicked = true; - return Task.CompletedTask; - }); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File1.text" } - ]); - }); - - var button = cut.Find(".fa-download"); - await cut.InvokeAsync(() => button.Click()); - Assert.True(clicked); - } - - [Fact] - public async Task ButtonUpload_Validate_Ok() - { - var invalid = true; - var foo = new Foo - { - Name = "abc" - }; - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Accept, "Image"); - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - pb.Add(a => a.OnValidSubmit, context => - { - invalid = false; - return Task.CompletedTask; - }); - }); - - // 由于设置了属性 Name 值 Validate 方法通过 - var form = cut.Find("form"); - await cut.InvokeAsync(() => form.Submit()); - Assert.False(invalid); - } - - [Fact] - public void ShowUploadList_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.Accept, "Image"); - }); - - cut.Contains("upload-body is-list"); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowUploadFileList, false); - }); - cut.WaitForState(() => !cut.Markup.Contains("upload-body is-list")); - cut.DoesNotContain("upload-body is-list"); - } - - [Fact] - public async Task ButtonUpload_OnDeleteFile_Ok() - { - UploadFile? deleteFile = null; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsSingle, false); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File" } - ]); - pb.Add(a => a.OnDelete, file => - { - deleteFile = file; - return Task.FromResult(true); - }); - }); - await cut.InvokeAsync(() => cut.Find(".delete-icon").Click()); - Assert.NotNull(deleteFile); - Assert.Null(deleteFile!.Error); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.DefaultFileList, null); - }); - // 增加代码覆盖率 - var ins = cut.Instance; - var pi = ins.GetType().GetMethod("OnFileDelete", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; - pi.Invoke(ins, [new UploadFile()]); - - deleteFile = null; - // 上传失败测试 - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File2", Code = 1001 } - ]); - }); - await cut.InvokeAsync(() => cut.Find(".delete-icon").Click()); - Assert.NotNull(deleteFile); - } - - [Fact] - public async Task ButtonUpload_ShowProgress_Ok() - { - var cancel = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.OnChange, async file => - { - await Task.Delay(100); - await file.SaveToFileAsync("1.txt"); - }); - pb.Add(a => a.OnCancel, file => - { - cancel = true; - return Task.CompletedTask; - }); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(async () => - { - _ = input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - })); - - var button = cut.Find(".cancel-icon"); - Assert.NotNull(button); - await cut.InvokeAsync(() => button.Click()); - Assert.True(cancel); - }); - } - - [Fact] - public async Task ButtonUpload_IsDirectory_Ok() - { - var fileCount = 0; - var fileNames = new List(); - List fileList = []; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsDirectory, true); - pb.Add(a => a.OnChange, file => - { - fileCount = file.FileCount; - fileNames.Add(file.OriginFileName!); - return Task.CompletedTask; - }); - pb.Add(a => a.OnAllFileUploaded, files => - { - fileList.AddRange(files); - return Task.CompletedTask; - }); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new(), - new("UploadTestFile2") - }))); - Assert.Equal(2, fileCount); - Assert.Equal(2, fileNames.Count); - Assert.Equal(2, fileList.Count); - } - - [Fact] - public void ButtonUpload_Accept_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.Accept, ".jpg"); - }); - cut.Contains("accept=\".jpg\""); - } - - [Fact] - public void ButtonUpload_OnGetFileFormat_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "1.csv" }, - new() { FileName = "1.xls" }, - new() { FileName = "1.xlsx" }, - new() { FileName = "1.doc" }, - new() { FileName = "1.docx" }, - new() { FileName = "1.dot" }, - new() { FileName = "1.ppt" }, - new() { FileName = "1.pptx" }, - new() { FileName = "1.wav" }, - new() { FileName = "1.mp3" }, - new() { FileName = "1.mp4" }, - new() { FileName = "1.mov" }, - new() { FileName = "1.mkv" }, - new() { FileName = "1.cs" }, - new() { FileName = "1.html" }, - new() { FileName = "1.vb" }, - new() { FileName = "1.pdf" }, - new() { FileName = "1.zip" }, - new() { FileName = "1.rar" }, - new() { FileName = "1.iso" }, - new() { FileName = "1.txt" }, - new() { FileName = "1.log" }, - new() { FileName = "1.jpg" }, - new() { FileName = "1.jpeg" }, - new() { FileName = "1.png" }, - new() { FileName = "1.bmp" }, - new() { FileName = "1.gif" }, - new() { FileName = "1.test" }, - new() { FileName = "1" } - ]); - }); - cut.Contains("fa-regular fa-file-excel"); - cut.Contains("fa-regular fa-file-word"); - cut.Contains("fa-regular fa-file-powerpoint"); - cut.Contains("fa-regular fa-file-audio"); - cut.Contains("fa-regular fa-file-video"); - cut.Contains("fa-regular fa-file-code"); - cut.Contains("fa-regular fa-file-pdf"); - cut.Contains("fa-regular fa-file-archive"); - cut.Contains("fa-regular fa-file-text"); - cut.Contains("fa-regular fa-file-image"); - cut.Contains("fa-regular fa-file"); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.OnGetFileFormat, extensions => - { - return "fa-format-test"; - }); - }); - cut.Contains("fa-format-test"); - } - - [Fact] - public async Task CardUpload_Ok() - { - var zoom = false; - var deleted = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.OnDelete, file => - { - deleted = true; - return Task.FromResult(true); - }); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File1.text" }, - new() { FileName = "Test-File2.jpg" }, - new() { PrevUrl = "Test-File3.png" }, - new() { PrevUrl = "Test-File4.bmp" }, - new() { PrevUrl = "Test-File5.jpeg" }, - new() { PrevUrl = "Test-File6.gif" }, - new() { PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANS=" }, - new() { FileName = null! } - ]); - }); - cut.Contains("bb-previewer collapse active"); - - // OnZoom - await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); - Assert.False(zoom); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.OnZoomAsync, file => - { - zoom = true; - return Task.CompletedTask; - }); - }); - await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); - Assert.True(zoom); - - zoom = false; - await cut.InvokeAsync(() => cut.Find(".upload-item-body-image").Click()); - Assert.True(zoom); - - // OnDelete - await cut.InvokeAsync(() => cut.Find(".btn-outline-danger").Click()); - Assert.True(deleted); - - // CanPreviewCallback - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.CanPreviewCallback, p => - { - return false; - }); - }); - await cut.InvokeAsync(() => cut.Find(".btn-zoom").Click()); - - // ShowProgress - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.OnChange, async file => - { - await file.SaveToFileAsync("1.txt"); - }); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new("test.txt", "Image-Png") - }))); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new("test.png") - }))); - - // IsUploadButtonAtFirst - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.IsUploadButtonAtFirst, true); - }); - } - - [Fact] - public async Task CardUpload_Reset() - { - var cut = Context.RenderComponent>(); - await cut.InvokeAsync(() => cut.Instance.Reset()); - Assert.Null(cut.Instance.DefaultFileList); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.DefaultFileList, - [ - new UploadFile() { FileName = "Test-File1.text" } - ]); - }); - await cut.InvokeAsync(() => cut.Instance.Reset()); - Assert.NotNull(cut.Instance.DefaultFileList); - Assert.Empty(cut.Instance.DefaultFileList); - } - - [Fact] - public async Task CardUpload_ShowDownload() - { - var clicked = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowDownloadButton, true); - pb.Add(a => a.OnDownload, file => - { - clicked = true; - return Task.CompletedTask; - }); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File1.text" } - ]); - }); - - var button = cut.Find(".btn-download"); - await cut.InvokeAsync(() => button.Click()); - Assert.True(clicked); - } - - [Fact] - public void CardUpload_ShowZoom() - { - var clicked = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowZoomButton, true); - pb.Add(a => a.OnZoomAsync, file => - { - clicked = true; - return Task.CompletedTask; - }); - pb.Add(a => a.DefaultFileList, - [ - new UploadFile() { FileName = "Test-File1.text" } - ]); - }); - - var button = cut.Find(".btn-zoom"); - button.Click(); - cut.WaitForState(() => clicked); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowZoomButton, false); - }); - cut.WaitForAssertion(() => cut.DoesNotContain("btn-zoom")); - } - - [Fact] - public void ShowDeletedButton_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowDeletedButton, true); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File1.text" } - ]); - }); - cut.Contains("aria-label=\"delete\""); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.ShowDeletedButton, false); - }); - cut.WaitForAssertion(() => cut.DoesNotContain("aria-label=\"delete\"")); - } - - [Fact] - public void CardUpload_ValidateForm_Ok() - { - var foo = new Foo(); - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.Model, foo); - pb.AddChildContent>(pb => - { - pb.Add(a => a.Value, foo.Name); - pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); - }); - }); - cut.Contains("form-label"); - } - - [Fact] - public void CardUpload_IconTemplate_Ok() - { - var foo = new Foo(); - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "Test-File1.text" } - ]); - pb.Add(a => a.IconTemplate, file => builder => - { - builder.AddContent(0, "custom-file-icon-template"); - }); - }); - cut.Contains("custom-file-icon-template"); - } - - [Fact] - public async Task CardUpload_ShowProgress_Ok() - { - var cancel = false; - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.OnChange, async file => - { - await Task.Delay(100); - await file.SaveToFileAsync("1.txt"); - }); - pb.Add(a => a.OnCancel, file => - { - cancel = true; - return Task.CompletedTask; - }); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(() => - { - input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - })); - var button = cut.Find(".btn-cancel"); - Assert.NotNull(button); - button.Click(); - }); - Assert.True(cancel); - } - - [Fact] - public async Task CardUpload_Max_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.Max, 1); - }); - var input = cut.FindComponent(); - await cut.InvokeAsync(async () => - { - await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - })); - }); - } - - [Fact] - public void FileSize_Ok() - { - var validator = new FileValidationAttribute() - { - FileSize = 5 - }; - var p = new Person() - { - Picture = new MockBrowserFile("test.log") - }; - var result = validator.GetValidationResult(p.Picture, new ValidationContext(p)); - Assert.NotEqual(ValidationResult.Success, result); - } - - [Fact] - public void FileExtensions_Ok() - { - var validator = new FileValidationAttribute() - { - Extensions = ["jpg"] - }; - var p = new Person() - { - Picture = new MockBrowserFile("test.log") - }; - var result = validator.GetValidationResult(p.Picture, new ValidationContext(p)); - Assert.NotEqual(ValidationResult.Success, result); - } - - [Fact] - public void IsValid_Ok() - { - var validator = new FileValidationAttribute() - { - Extensions = ["jpg"] - }; - var p = new Person() - { - Picture = new MockBrowserFile("test.log") - }; - Assert.False(validator.IsValid(p.Picture)); - } - - [Fact] - public void Validate_Ok() - { - var validator = new FileValidationAttribute() - { - Extensions = ["jpg"] - }; - var p = new Person() - { - Picture = new MockBrowserFile("test.log") - }; - Assert.Throws(() => validator.Validate(p.Picture, "Picture")); - Assert.Throws(() => validator.Validate(p.Picture, new ValidationContext(p))); - } - - [Fact] - public void Capture_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.Capture, "camera"); - }); - cut.Contains("capture=\"camera\""); - } - - [Fact] - public void DropUpload_BodyTemplate_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.BodyTemplate, b => b.AddContent(0, "drop-upload-body-template")); - }); - cut.MarkupMatches("
    drop-upload-body-template
      "); - } - - [Fact] - public void DropUpload_IconTemplate_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.IconTemplate, b => b.AddContent(0, "drop-upload-icon-template")); - }); - cut.Contains("
      drop-upload-icon-template
      "); - } - - [Fact] - public void DropUpload_TextTemplate_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.TextTemplate, b => b.AddContent(0, "drop-upload-text-template")); - }); - cut.Contains("
      drop-upload-text-template
      "); - } - - [Fact] - public void DropUpload_Footer_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.ShowFooter, true); - }); - cut.Contains("
      "); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.FooterTemplate, b => b.AddContent(0, "drop-upload-footer-text")); - }); - cut.Contains("
      drop-upload-footer-text
      "); - } - - [Fact] - public async Task DropUpload_OnChanged_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.ShowLabel, true); - pb.Add(a => a.ShowProgress, true); - pb.Add(a => a.OnChange, async files => - { - await files.SaveToFileAsync("1.text"); - }); - }); - - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new() - }))); - } - - private class Person - { - [Required] - [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] - - public IBrowserFile? Picture { get; set; } - } - - private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile - { - public string Name { get; } = name; - - public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; - - public long Size { get; } = 10; - - public string ContentType { get; } = contentType; - - public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) - { - return new MemoryStream([0x01, 0x02]); - } - } -} From d0ebb002d66bc5eb94fd0307696616ee808da832 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 24 May 2025 20:46:24 +0800 Subject: [PATCH 121/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadFileTest.cs | 37 --------------------- test/UnitTest/Components/UploadInputTest.cs | 30 +++++++++++++++++ 2 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 test/UnitTest/Components/UploadFileTest.cs diff --git a/test/UnitTest/Components/UploadFileTest.cs b/test/UnitTest/Components/UploadFileTest.cs deleted file mode 100644 index efdf2b12e8d..00000000000 --- a/test/UnitTest/Components/UploadFileTest.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.AspNetCore.Components.Forms; - -namespace UnitTest.Components; - -public class UploadFileTest -{ - [Fact] - public async Task RequestBase64ImageFileAsync_Ok() - { - UploadFile uploadFile = new() - { - File = new MockBrowserFile("UploadTestFile", "image/png") - }; - await uploadFile.RequestBase64ImageFileAsync(format: "image/png", maxWidth: 320, maxHeight: 240, maxAllowedSize: 512000, token: default); - } - - private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile - { - public string Name { get; } = name; - - public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; - - public long Size { get; } = 10; - - public string ContentType { get; } = contentType; - - public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) - { - return new MemoryStream([0x01, 0x02]); - } - } -} diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index 24272fce41f..cea06d27f1e 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -16,6 +16,7 @@ public async Task InputUpload_Ok() UploadFile? uploadFile = null; var cut = Context.RenderComponent>(pb => { + pb.Add(a => a.Capture, "capture"); pb.Add(a => a.PlaceHolder, "TestPlaceHolder"); pb.Add(a => a.OnChange, file => { @@ -25,6 +26,7 @@ public async Task InputUpload_Ok() pb.Add(a => a.Value, "test.jpg"); }); cut.Contains("value=\"test.jpg\""); + cut.Contains("capture=\"capture\""); var input = cut.FindComponent(); await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() @@ -141,6 +143,34 @@ public void InputUpload_FileValidate_OK() cut.InvokeAsync(() => form.Submit()); } + [Fact] + public void InputUpload_Value() + { + var cut = Context.RenderComponent>>(pb => + { + pb.Add(a => a.Value, + [ + "test1.png", + "test2.png" + ]); + }); + Assert.Contains("test1.png;test2.png", cut.Markup); + } + + [Fact] + public void InputUpload_Files() + { + var cut = Context.RenderComponent>>(pb => + { + pb.Add(a => a.Value, + [ + new MockBrowserFile("test1.png"), + new MockBrowserFile("test2.png") + ]); + }); + Assert.Contains("test1.png;test2.png", cut.Markup); + } + private class Person { [Required] From b8fe562cdf2ce63b9e7236d8996a152337808948 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 14:20:38 +0800 Subject: [PATCH 122/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20InputU?= =?UTF-8?q?pload=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor.cs | 2 +- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index d4a7aada353..2e32521c543 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -109,7 +109,7 @@ private bool CheckStatus() return true; } - return CanUpload(); + return !CanUpload(); } private async Task TriggerDeleteFile() diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 2a849e884cc..4d7d110d0c8 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -99,6 +99,16 @@ public abstract class UploadBase : ValidateBase, IUpload ///
      protected List Files => GetUploadFiles(); + /// + /// + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + _filesCache = null; + } + /// /// /// From 7f97d7aa4f1dc8237cbceca69120dc963b519c66 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 14:25:20 +0800 Subject: [PATCH 123/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadInputTest.cs | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index cea06d27f1e..1ef34045ecb 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using AngleSharp.Dom; using Microsoft.AspNetCore.Components.Forms; using System.ComponentModel.DataAnnotations; @@ -171,6 +172,41 @@ public void InputUpload_Files() Assert.Contains("test1.png;test2.png", cut.Markup); } + [Fact] + public void InputUpload_IsMultiple() + { + var cut = Context.RenderComponent>>(pb => + { + pb.Add(a => a.IsMultiple, false); + }); + + // 禁用多选功能 + cut.DoesNotContain("multiple=\"multiple\""); + + // 给定已上传文件后上传按钮应该被禁用 + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new UploadFile() { FileName = "test1.png" }, + new UploadFile() { FileName = "test2.png" } + ]); + }); + var button = cut.Find(".btn-browser"); + Assert.True(button.IsDisabled()); + + // 开启多选功能 + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsMultiple, true); + }); + cut.Contains("multiple=\"multiple\""); + + // 给定已上传文件后上传按钮不应该被禁用 + button = cut.Find(".btn-browser"); + Assert.False(button.IsDisabled()); + } + private class Person { [Required] From 431cc1bc6e1a0efd14db9c207f2ccbb0793c12fc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 14:31:35 +0800 Subject: [PATCH 124/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor.cs | 2 +- .../Components/Upload/InputUpload.razor.cs | 10 +----- test/UnitTest/Components/UploadButtonTest.cs | 36 +++++++++++++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index a25d393cacf..bf6711578e2 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -209,5 +209,5 @@ protected override void OnParametersSet() BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadBrowserButtonIcon); } - private bool CheckStatus() => IsDisabled || CanUpload() == false; + private bool CheckStatus() => IsDisabled || !CanUpload(); } diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index 2e32521c543..d4f93f7b31c 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,15 +102,7 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } - private bool CheckStatus() - { - if (IsDisabled) - { - return true; - } - - return !CanUpload(); - } + private bool CheckStatus() => IsDisabled || !CanUpload(); private async Task TriggerDeleteFile() { diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 077d267e994..3fb044166c1 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using AngleSharp.Dom; using Microsoft.AspNetCore.Components.Forms; using System.ComponentModel.DataAnnotations; @@ -84,6 +85,41 @@ public void ButtonUpload_IsDisabled_Ok() Assert.DoesNotContain("disabled=\"disabled\"", button.ToMarkup()); } + [Fact] + public void InputUpload_IsMultiple() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsMultiple, false); + }); + + // 禁用多选功能 + cut.DoesNotContain("multiple=\"multiple\""); + + // 给定已上传文件后上传按钮应该被禁用 + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new UploadFile() { FileName = "test1.png" }, + new UploadFile() { FileName = "test2.png" } + ]); + }); + var button = cut.Find(".btn-browser"); + Assert.True(button.IsDisabled()); + + // 开启多选功能 + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.IsMultiple, true); + }); + cut.Contains("multiple=\"multiple\""); + + // 给定已上传文件后上传按钮不应该被禁用 + button = cut.Find(".btn-browser"); + Assert.False(button.IsDisabled()); + } + [Fact] public void ButtonUpload_ValidateForm_Ok() { From 4b0ff0e5f911f9a1dac7b05de3f56c1bb1e42829 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 14:35:20 +0800 Subject: [PATCH 125/177] =?UTF-8?q?test:=20UploadDrop=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20OnCancel=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadDropTest.cs | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index ac84703384c..54d554b58ef 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -103,6 +103,39 @@ public async Task ShowUploadList_Ok() Assert.NotNull(file); } + [Fact] + public async Task DropUpload_ShowProgress_Ok() + { + var cancel = false; + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.ShowProgress, true); + pb.Add(a => a.OnChange, async file => + { + await Task.Delay(100); + await file.SaveToFileAsync("1.txt"); + }); + pb.Add(a => a.OnCancel, file => + { + cancel = true; + return Task.CompletedTask; + }); + }); + var input = cut.FindComponent(); + await cut.InvokeAsync(async () => + { + _ = input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + })); + + var button = cut.Find(".cancel-icon"); + Assert.NotNull(button); + await cut.InvokeAsync(() => button.Click()); + Assert.True(cancel); + }); + } + [Fact] public void ButtonUpload_OnGetFileFormat_Ok() { From 6b47ea90a1b587b257b5ad3f07e71cd144a1fb46 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 15:57:59 +0800 Subject: [PATCH 126/177] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=A2=9E=E5=8A=A0=E5=9F=BA=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor | 7 +- .../Components/Upload/ButtonUpload.razor.cs | 110 +------------ .../Components/Upload/CardUpload.razor | 2 +- .../Components/Upload/CardUpload.razor.cs | 131 +-------------- .../Components/Upload/DropUpload.razor | 4 +- .../Components/Upload/DropUpload.razor.cs | 106 ------------ .../Components/Upload/FileListUploadBase.cs | 152 ++++++++++++++++++ .../Components/Upload/InputUpload.razor.cs | 2 - .../Components/Upload/InputUpload.razor.scss | 7 - .../Components/Upload/UploadBase.cs | 6 + .../Components/Upload/UploadPreviewList.razor | 22 +-- .../Upload/UploadPreviewList.razor.cs | 20 ++- src/BootstrapBlazor/Enums/ComponentIcons.cs | 56 +++---- src/BootstrapBlazor/Icons/BootstrapIcons.cs | 12 +- src/BootstrapBlazor/Icons/FontAwesomeIcons.cs | 12 +- .../Icons/MaterialDesignIcons.cs | 12 +- 16 files changed, 223 insertions(+), 438 deletions(-) create mode 100644 src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 94ab50dbd87..ca0fe5c18f6 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @typeparam TValue -@inherits UploadBase +@inherits FileListUploadBase @if (IsShowLabel) { @@ -16,11 +16,12 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" + ShowDeleteButton="@ShowDeleteButton" DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" - FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + }
      diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs index bf6711578e2..701efe23ff3 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor.cs @@ -19,12 +19,6 @@ public partial class ButtonUpload [Parameter] public string? LoadingIcon { get; set; } - /// - /// 获得/设置 下载按钮图标 - /// - [Parameter] - public string? DownloadIcon { get; set; } - /// /// 获得/设置 上传失败状态图标 /// @@ -37,12 +31,6 @@ public partial class ButtonUpload [Parameter] public string? ValidStatusIcon { get; set; } - /// - /// 获得/设置 删除按钮图标 - /// - [Parameter] - public string? DeleteIcon { get; set; } - /// /// 获得/设置 浏览按钮图标 /// @@ -92,104 +80,10 @@ public partial class ButtonUpload [Parameter] public Func? OnGetFileFormat { get; set; } - /// - /// 获得/设置 是否显示下载按钮 默认 false - /// - [Parameter] - public bool ShowDownloadButton { get; set; } - - /// - /// 获得/设置 点击下载按钮回调方法 默认 null - /// - [Parameter] - public Func? OnDownload { get; set; } - - /// - /// 获得/设置 取消图标 - /// - [Parameter] - public string? CancelIcon { get; set; } - - /// - /// 获得/设置 点击取消按钮回调此方法 默认 null - /// - [Parameter] - public Func? OnCancel { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconExcel { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconDocx { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPPT { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconAudio { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconVideo { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconCode { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPdf { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconZip { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconArchive { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconImage { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconFile { get; set; } - [Inject] [NotNull] private IStringLocalizer>? Localizer { get; set; } - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - private string? ClassString => CssBuilder.Default("upload") .AddClassFromAttributes(AdditionalAttributes) .Build(); @@ -199,7 +93,7 @@ public partial class ButtonUpload .Build(); /// - /// OnParametersSet 方法 + /// /// protected override void OnParametersSet() { @@ -208,6 +102,4 @@ protected override void OnParametersSet() BrowserButtonText ??= Localizer[nameof(BrowserButtonText)]; BrowserButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadBrowserButtonIcon); } - - private bool CheckStatus() => IsDisabled || !CanUpload(); } diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor b/src/BootstrapBlazor/Components/Upload/CardUpload.razor index 33eec8ecd47..3f0cbef8246 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor @@ -1,6 +1,6 @@ @namespace BootstrapBlazor.Components @typeparam TValue -@inherits UploadBase +@inherits FileListUploadBase @if (IsShowLabel) { diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 67d31809d2d..989082efb76 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -30,7 +30,7 @@ public partial class CardUpload private bool ShowPreviewList => Files.Count != 0; - private List PreviewList => Files.Select(i => i.PrevUrl).ToList(); + private List PreviewList => [.. Files.Select(i => i.PrevUrl)]; private string? GetDeleteButtonDisabledString(UploadFile item) => (!IsDisabled && item.Uploaded) ? null : "disabled"; @@ -72,24 +72,12 @@ public partial class CardUpload [Parameter] public string? StatusIcon { get; set; } - /// - /// 获得/设置 删除图标 - /// - [Parameter] - public string? DeleteIcon { get; set; } - /// /// 获得/设置 移除图标 /// [Parameter] public string? RemoveIcon { get; set; } - /// - /// 获得/设置 下载图标 - /// - [Parameter] - public string? DownloadIcon { get; set; } - /// /// 获得/设置 放大图标 /// @@ -110,124 +98,24 @@ public partial class CardUpload [ExcludeFromCodeCoverage] public bool ShowDeletedButton { get; set; } = true; - /// - /// 获得/设置 是否显示删除按钮 默认 true 显示 - /// - [Parameter] - public bool ShowDeleteButton { get; set; } = true; - /// /// 获得/设置 继续上传按钮是否在列表前 默认 false /// [Parameter] public bool IsUploadButtonAtFirst { get; set; } - /// - /// 获得/设置 是否显示下载按钮 默认 false - /// - [Parameter] - public bool ShowDownloadButton { get; set; } - - /// - /// 获得/设置 点击下载按钮回调方法 默认 null - /// - [Parameter] - public Func? OnDownload { get; set; } - - /// - /// 获得/设置 点击取消按钮回调此方法 默认 null - /// - [Parameter] - public Func? OnCancel { get; set; } - /// /// 获得/设置 点击 Zoom 图标回调方法 /// [Parameter] public Func? OnZoomAsync { get; set; } - /// - /// 获得/设置 取消图标 - /// - [Parameter] - public string? CancelIcon { get; set; } - /// /// 获得/设置 图标文件扩展名集合 ".png" /// [Parameter] public List? AllowExtensions { get; set; } - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconExcel { get; set; } - - /// - /// 获得/设置 Docx 类型文件图标 - /// - [Parameter] - public string? FileIconDocx { get; set; } - - /// - /// 获得/设置 PPT 类型文件图标 - /// - [Parameter] - public string? FileIconPPT { get; set; } - - /// - /// 获得/设置 Audio 类型文件图标 - /// - [Parameter] - public string? FileIconAudio { get; set; } - - /// - /// 获得/设置 Video 类型文件图标 - /// - [Parameter] - public string? FileIconVideo { get; set; } - - /// - /// 获得/设置 File 类型文件图标 - /// - [Parameter] - public string? FileIconCode { get; set; } - - /// - /// 获得/设置 Pdf 类型文件图标 - /// - [Parameter] - public string? FileIconPdf { get; set; } - - /// - /// 获得/设置 Zip 类型文件图标 - /// - [Parameter] - public string? FileIconZip { get; set; } - - /// - /// 获得/设置 Archive 类型文件图标 - /// - [Parameter] - public string? FileIconArchive { get; set; } - - /// - /// 获得/设置 Image 类型文件图标 - /// - [Parameter] - public string? FileIconImage { get; set; } - - /// - /// 获得/设置 File 类型文件图标 - /// - [Parameter] - public string? FileIconFile { get; set; } - - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - private string? ActionClassString => CssBuilder.Default("upload-item-actions") .AddClass("btn-browser", IsDisabled == false) .Build(); @@ -241,23 +129,8 @@ protected override void OnParametersSet() AddIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadAddIcon); StatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadStatusIcon); - DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadDeleteIcon); - RemoveIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadRemoveIcon); - DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadDownloadIcon); ZoomIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadZoomIcon); - - CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); - FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); - FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); - FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); - FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); - FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); - FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); - FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); - FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); - FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); - FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); - FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); + RemoveIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadRemoveIcon); } private async Task OnCardFileDelete(UploadFile item) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index e6cc5a0a8b2..4ad70cbf3fd 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -1,5 +1,5 @@ @namespace BootstrapBlazor.Components -@inherits UploadBase +@inherits FileListUploadBase @if (IsShowLabel) { @@ -54,7 +54,7 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" + ShowDeleteButton="@ShowDeleteButton" DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index dedc0fb4307..6469be9b33d 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -75,36 +75,6 @@ public partial class DropUpload [Parameter] public Func? OnGetFileFormat { get; set; } - /// - /// 获得/设置 取消图标 - /// - [Parameter] - public string? CancelIcon { get; set; } - - /// - /// 获得/设置 点击取消按钮回调此方法 默认 null - /// - [Parameter] - public Func? OnCancel { get; set; } - - /// - /// 获得/设置 是否显示下载按钮 默认 false - /// - [Parameter] - public bool ShowDownloadButton { get; set; } - - /// - /// 获得/设置 点击下载按钮回调方法 默认 null - /// - [Parameter] - public Func? OnDownload { get; set; } - - /// - /// 获得/设置 下载按钮图标 - /// - [Parameter] - public string? DownloadIcon { get; set; } - /// /// 获得/设置 加载中图标 /// @@ -123,82 +93,6 @@ public partial class DropUpload [Parameter] public string? ValidStatusIcon { get; set; } - /// - /// 获得/设置 删除按钮图标 - /// - [Parameter] - public string? DeleteIcon { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconExcel { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconDocx { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPPT { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconAudio { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconVideo { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconCode { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPdf { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconZip { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconArchive { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconImage { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconFile { get; set; } - - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - [Inject] [NotNull] private IStringLocalizer>? Localizer { get; set; } diff --git a/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs b/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs new file mode 100644 index 00000000000..b48d87e5452 --- /dev/null +++ b/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs @@ -0,0 +1,152 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// PreviewListUploadBase 基类 +/// +/// +public class FileListUploadBase : UploadBase +{ + /// + /// 获得/设置 是否显示删除按钮 默认 false + /// + [Parameter] + public bool ShowDeleteButton { get; set; } + + /// + /// 获得/设置 删除按钮图标 + /// + [Parameter] + public string? DeleteIcon { get; set; } + + /// + /// 获得/设置 是否显示下载按钮 默认 false + /// + [Parameter] + public bool ShowDownloadButton { get; set; } + + /// + /// 获得/设置 下载按钮图标 + /// + [Parameter] + public string? DownloadIcon { get; set; } + + /// + /// 获得/设置 点击下载按钮回调方法 默认 null + /// + [Parameter] + public Func? OnDownload { get; set; } + + /// + /// 获得/设置 取消图标 + /// + [Parameter] + public string? CancelIcon { get; set; } + + /// + /// 获得/设置 点击取消按钮回调此方法 默认 null + /// + [Parameter] + public Func? OnCancel { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconExcel { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconDocx { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPPT { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconAudio { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconVideo { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconCode { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconPdf { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconZip { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconArchive { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconImage { get; set; } + + /// + /// 获得/设置 Excel 类型文件图标 + /// + [Parameter] + public string? FileIconFile { get; set; } + + /// + /// 服务实例 + /// + [Inject] + [NotNull] + protected IIconTheme? IconTheme { get; set; } + + /// + /// + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDeleteIcon); + DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDownloadIcon); + CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); + + FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); + FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); + FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); + FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); + FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); + FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); + FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); + FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); + FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); + FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); + FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); + } +} diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs index d4f93f7b31c..9a3f43de1a1 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.cs @@ -102,8 +102,6 @@ protected override void OnParametersSet() DeleteButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.InputUploadDeleteButtonIcon); } - private bool CheckStatus() => IsDisabled || !CanUpload(); - private async Task TriggerDeleteFile() { for (var index = Files.Count; index > 0; index--) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index c967e39bdd0..88c7ec179e2 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -43,10 +43,6 @@ background-color: var(--bs-secondary-bg); } -.upload .upload-body.is-list .upload-item:hover .fa-trash-can { - display: inline-block; -} - .upload .upload-body.is-list .upload-item .upload-item-body { flex: 1; padding: var(--bb-upload-body-list-item-body-padding); @@ -63,9 +59,6 @@ padding-right: 0.25rem; } -.upload .upload-body.is-list .upload-item .fa-trash-can, -.upload .upload-body.is-list .upload-item:not(.disabled):hover .fa-circle-check, -.upload .upload-body.is-list .upload-item:hover .fa-xmark-circle, .upload .upload-body.is-avatar .upload-item .upload-item-delete, .upload .upload-body.is-avatar .upload-item.is-invalid .upload-item-spin, .upload .upload-body.is-avatar .upload-item.is-valid .upload-item-spin, diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 4d7d110d0c8..b28c64b0ba2 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -282,6 +282,12 @@ protected bool CanUpload() return Files.Count == 0; } + /// + /// 检查上传按钮是否可用方法 不可用时返回 true + /// + /// + protected bool CheckStatus() => IsDisabled || !CanUpload(); + /// /// 判断是否显示新建按钮 /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor index 7a6ac0e5a9e..5b4deb87be9 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor @@ -18,26 +18,12 @@ else {
      - @if (item.Code == 0) + @if (item.Code == 0 && ShowDownloadButton) { - @if (ShowDownloadButton) - { - - } - - @if (!IsDisabled) - { - - } - } - else - { - @if (!IsDisabled) - { - - - } + } + +
      }
      diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs index b289000fdd7..501b213c9b0 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs @@ -72,6 +72,12 @@ public partial class UploadPreviewList [Parameter] public string? ValidStatusIcon { get; set; } + /// + /// 获得/设置 是否显示删除按钮 默认 false + /// + [Parameter] + public bool ShowDeleteButton { get; set; } + /// /// 获得/设置 删除按钮图标 /// @@ -188,8 +194,8 @@ public partial class UploadPreviewList .Build(); private string? DeleteIconString => CssBuilder.Default("delete-icon") - .AddClass(DeleteIcon) - .Build(); + .AddClass(DeleteIcon) + .Build(); private string? ValidStatusIconString => CssBuilder.Default("valid-icon") .AddClass(ValidStatusIcon) @@ -208,12 +214,12 @@ protected override void OnParametersSet() Items ??= []; - LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadLoadingIcon); - InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadInvalidStatusIcon); - ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadValidStatusIcon); - DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDownloadIcon); + LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadLoadingIcon); + InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadInvalidStatusIcon); + ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadValidStatusIcon); + DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDownloadIcon); CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); - DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.ButtonUploadDeleteIcon); + DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDeleteIcon); FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); diff --git a/src/BootstrapBlazor/Enums/ComponentIcons.cs b/src/BootstrapBlazor/Enums/ComponentIcons.cs index a401bf07393..4a465fbdd47 100644 --- a/src/BootstrapBlazor/Enums/ComponentIcons.cs +++ b/src/BootstrapBlazor/Enums/ComponentIcons.cs @@ -55,31 +55,6 @@ public enum ComponentIcons /// AutoFillIcon, - /// - /// ButtonUpload 组件 LoadingIcon 属性图标 - /// - ButtonUploadLoadingIcon, - - /// - /// ButtonUpload 组件 FailedInvalidIcon 属性图标 - /// - ButtonUploadInvalidStatusIcon, - - /// - /// ButtonUpload 组件 FailedValidIcon 属性图标 - /// - ButtonUploadValidStatusIcon, - - /// - /// ButtonUpload 组件 DownloadIcon 属性图标 - /// - ButtonUploadDownloadIcon, - - /// - /// ButtonUpload 组件 DeleteIcon 属性图标 - /// - ButtonUploadDeleteIcon, - /// /// ButtonUpload 组件 BrowserButtonIcon 属性图标 /// @@ -116,30 +91,45 @@ public enum ComponentIcons CardUploadStatusIcon, /// - /// CardUpload 组件 DeleteIcon 图标 + /// CardUpload 组件 RemoveIcon 图标 + /// + CardUploadRemoveIcon, + + /// + /// CardUpload 组件 ZoomIcon 图标 /// - CardUploadDeleteIcon, + CardUploadZoomIcon, /// - /// CardUpload 组件 RemoveIcon 图标 + /// ButtonUpload 组件 LoadingIcon 属性图标 /// - CardUploadRemoveIcon, + UploadLoadingIcon, /// - /// CardUpload 组件 DownloadIcon 图标 + /// ButtonUpload 组件 FailedInvalidIcon 属性图标 /// - CardUploadDownloadIcon, + UploadInvalidStatusIcon, /// - /// CardUpload 组件 ZoomIcon 图标 + /// ButtonUpload 组件 FailedValidIcon 属性图标 /// - CardUploadZoomIcon, + UploadValidStatusIcon, /// /// Upload 组件 CancelIcon 图标 /// UploadCancelIcon, + /// + /// CardUpload 组件 DeleteIcon 图标 + /// + UploadDeleteIcon, + + /// + /// CardUpload 组件 DownloadIcon 图标 + /// + UploadDownloadIcon, + /// /// Upload 组件 UploadIcon 图标 /// diff --git a/src/BootstrapBlazor/Icons/BootstrapIcons.cs b/src/BootstrapBlazor/Icons/BootstrapIcons.cs index 641d0182b37..62b89e20f24 100644 --- a/src/BootstrapBlazor/Icons/BootstrapIcons.cs +++ b/src/BootstrapBlazor/Icons/BootstrapIcons.cs @@ -194,23 +194,21 @@ internal static class BootstrapIcons { ComponentIcons.AvatarUploadInvalidStatusIcon, "bi bi-x bi-rotate-315" }, { ComponentIcons.ButtonUploadBrowserButtonIcon, "bi bi-folder2-open" }, - { ComponentIcons.ButtonUploadLoadingIcon, "bi bi-arrow-clockwise bi-spin" }, - { ComponentIcons.ButtonUploadInvalidStatusIcon, "bi bi-x-circle" }, - { ComponentIcons.ButtonUploadValidStatusIcon, "bi bi-check-circle" }, - { ComponentIcons.ButtonUploadDeleteIcon, "bi bi-trash3" }, - { ComponentIcons.ButtonUploadDownloadIcon, "bi bi-cloud-download" }, { ComponentIcons.InputUploadBrowserButtonIcon, "bi bi-folder-open" }, { ComponentIcons.InputUploadDeleteButtonIcon, "bi bi-trash3" }, { ComponentIcons.CardUploadAddIcon, "bi bi-plus" }, { ComponentIcons.CardUploadStatusIcon, "bi bi-check bi-rotate-315" }, - { ComponentIcons.CardUploadDeleteIcon, "bi bi-x bi-rotate-315" }, { ComponentIcons.CardUploadRemoveIcon, "bi bi-trash3" }, - { ComponentIcons.CardUploadDownloadIcon, "bi bi-cloud-download" }, { ComponentIcons.CardUploadZoomIcon, "bi bi-search" }, { ComponentIcons.UploadCancelIcon, "bi bi-cancel" }, { ComponentIcons.DropUploadIcon, "bi bi-cloud-arrow-up-fill" }, + { ComponentIcons.UploadLoadingIcon, "bi bi-arrow-clockwise bi-spin" }, + { ComponentIcons.UploadInvalidStatusIcon, "bi bi-x-circle" }, + { ComponentIcons.UploadValidStatusIcon, "bi bi-check-circle" }, + { ComponentIcons.UploadDownloadIcon, "bi bi-cloud-download" }, + { ComponentIcons.UploadDeleteIcon, "bi bi-x bi-rotate-315" }, { ComponentIcons.FileIconExcel, "bi bi-filetype-xlsx" }, { ComponentIcons.FileIconDocx, "bi bi-filetype-docx" }, diff --git a/src/BootstrapBlazor/Icons/FontAwesomeIcons.cs b/src/BootstrapBlazor/Icons/FontAwesomeIcons.cs index 893d038e89a..8e17be0655d 100644 --- a/src/BootstrapBlazor/Icons/FontAwesomeIcons.cs +++ b/src/BootstrapBlazor/Icons/FontAwesomeIcons.cs @@ -194,23 +194,21 @@ internal static class FontAwesomeIcons { ComponentIcons.AvatarUploadInvalidStatusIcon, "fa-solid fa-xmark" }, { ComponentIcons.ButtonUploadBrowserButtonIcon, "fa-regular fa-folder-open" }, - { ComponentIcons.ButtonUploadLoadingIcon, "fa-solid fa-spinner fa-spin" }, - { ComponentIcons.ButtonUploadInvalidStatusIcon, "fa-regular fa-circle-xmark" }, - { ComponentIcons.ButtonUploadValidStatusIcon, "fa-regular fa-circle-check" }, - { ComponentIcons.ButtonUploadDeleteIcon, "fa-regular fa-trash-can" }, - { ComponentIcons.ButtonUploadDownloadIcon, "fa-solid fa-download" }, { ComponentIcons.InputUploadBrowserButtonIcon, "fa-regular fa-folder-open" }, { ComponentIcons.InputUploadDeleteButtonIcon, "fa-regular fa-trash-can" }, { ComponentIcons.CardUploadAddIcon, "fa-solid fa-plus" }, { ComponentIcons.CardUploadStatusIcon, "fa-solid fa-check" }, - { ComponentIcons.CardUploadDeleteIcon, "fa-solid fa-xmark" }, { ComponentIcons.CardUploadRemoveIcon, "fa-regular fa-trash-can" }, - { ComponentIcons.CardUploadDownloadIcon, "fa-solid fa-download" }, { ComponentIcons.CardUploadZoomIcon, "fa-solid fa-magnifying-glass-plus" }, { ComponentIcons.UploadCancelIcon, "fa-solid fa-ban" }, { ComponentIcons.DropUploadIcon, "fa-solid fa-cloud-arrow-up" }, + { ComponentIcons.UploadLoadingIcon, "fa-solid fa-spinner fa-spin" }, + { ComponentIcons.UploadInvalidStatusIcon, "fa-regular fa-circle-xmark" }, + { ComponentIcons.UploadValidStatusIcon, "fa-regular fa-circle-check" }, + { ComponentIcons.UploadDownloadIcon, "fa-solid fa-download" }, + { ComponentIcons.UploadDeleteIcon, "fa-solid fa-xmark" }, { ComponentIcons.FileIconExcel, "fa-regular fa-file-excel" }, { ComponentIcons.FileIconDocx, "fa-regular fa-file-word" }, diff --git a/src/BootstrapBlazor/Icons/MaterialDesignIcons.cs b/src/BootstrapBlazor/Icons/MaterialDesignIcons.cs index a75eb1597ea..7ac9631d0db 100644 --- a/src/BootstrapBlazor/Icons/MaterialDesignIcons.cs +++ b/src/BootstrapBlazor/Icons/MaterialDesignIcons.cs @@ -194,23 +194,21 @@ internal static class MaterialDesignIcons { ComponentIcons.AvatarUploadInvalidStatusIcon, "mdi mdi-close mdi-rotate-315" }, { ComponentIcons.ButtonUploadBrowserButtonIcon, "mdi mdi-folder-open" }, - { ComponentIcons.ButtonUploadLoadingIcon, "mdi mdi-loading mdi-spin" }, - { ComponentIcons.ButtonUploadInvalidStatusIcon, "mdi mdi-close-circle-outline" }, - { ComponentIcons.ButtonUploadValidStatusIcon, "mdi mdi-check-circle-outline" }, - { ComponentIcons.ButtonUploadDeleteIcon, "mdi mdi-trash-can-outline" }, - { ComponentIcons.ButtonUploadDownloadIcon, "mdi mdi-cloud-download-outline" }, { ComponentIcons.InputUploadBrowserButtonIcon, "mdi mdi-folder-open" }, { ComponentIcons.InputUploadDeleteButtonIcon, "mdi mdi-trash-can-outline" }, { ComponentIcons.CardUploadAddIcon, "mdi mdi-plus" }, { ComponentIcons.CardUploadStatusIcon, "mdi mdi-check mdi-rotate-315" }, - { ComponentIcons.CardUploadDeleteIcon, "mdi mdi-close mdi-rotate-315" }, { ComponentIcons.CardUploadRemoveIcon, "mdi mdi-trash-can-outline" }, - { ComponentIcons.CardUploadDownloadIcon, "mdi mdi-cloud-download-outline" }, { ComponentIcons.CardUploadZoomIcon, "mdi mdi-magnify-plus-outline" }, { ComponentIcons.UploadCancelIcon, "mdi mdi-cancel" }, { ComponentIcons.DropUploadIcon, "mdi mdi-cloud-upload" }, + { ComponentIcons.UploadLoadingIcon, "mdi mdi-loading mdi-spin" }, + { ComponentIcons.UploadInvalidStatusIcon, "mdi mdi-close-circle-outline" }, + { ComponentIcons.UploadValidStatusIcon, "mdi mdi-check-circle-outline" }, + { ComponentIcons.UploadDeleteIcon, "mdi mdi-close mdi-rotate-315" }, + { ComponentIcons.UploadDownloadIcon, "mdi mdi-cloud-download-outline" }, { ComponentIcons.FileIconExcel, "mdi mdi-file-excel-outline" }, { ComponentIcons.FileIconDocx, "mdi mdi-file-word-outline" }, From 2f6cfe6654554939dc2069f725956e129777ec16 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:02:13 +0800 Subject: [PATCH 127/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadPreviewList.razor | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor index 5b4deb87be9..d6002ea5ffa 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor @@ -18,11 +18,18 @@ else {
      - @if (item.Code == 0 && ShowDownloadButton) + @if (item.Code == 0) { - + @if (ShowDownloadButton) + { + + } + + } + else + { + } -
      } From 97716a7d1d488d3701cec7d9e73776f1011c5d11 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:06:46 +0800 Subject: [PATCH 128/177] =?UTF-8?q?refactor:=20=E7=B2=BE=E7=AE=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadPreviewList.razor.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs index 501b213c9b0..b5a09158153 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs @@ -217,21 +217,6 @@ protected override void OnParametersSet() LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadLoadingIcon); InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadInvalidStatusIcon); ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadValidStatusIcon); - DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDownloadIcon); - CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); - DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDeleteIcon); - - FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); - FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); - FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); - FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); - FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); - FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); - FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); - FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); - FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); - FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); - FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } private async Task OnClickDownload(UploadFile item) From f7f2a4a06c0434803663068bf72b0625fdbdf021 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:10:38 +0800 Subject: [PATCH 129/177] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20ShowDe?= =?UTF-8?q?leteButton=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor | 2 +- .../Components/Upload/DropUpload.razor | 2 +- .../Upload/UploadPreviewList.razor.cs | 6 -- test/UnitTest/Components/UploadDropTest.cs | 80 ------------------- 4 files changed, 2 insertions(+), 88 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index ca0fe5c18f6..0360652f16d 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -16,7 +16,7 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - ShowDeleteButton="@ShowDeleteButton" DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" + DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 4ad70cbf3fd..ead46f5ee70 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -54,7 +54,7 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - ShowDeleteButton="@ShowDeleteButton" DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" + DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs index b5a09158153..daaa7e9227a 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs @@ -72,12 +72,6 @@ public partial class UploadPreviewList [Parameter] public string? ValidStatusIcon { get; set; } - /// - /// 获得/设置 是否显示删除按钮 默认 false - /// - [Parameter] - public bool ShowDeleteButton { get; set; } - /// /// 获得/设置 删除按钮图标 /// diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index 54d554b58ef..6fe0157e5df 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -136,86 +136,6 @@ await cut.InvokeAsync(async () => }); } - [Fact] - public void ButtonUpload_OnGetFileFormat_Ok() - { - var cut = Context.RenderComponent(pb => - { - pb.Add(a => a.LoadingIcon, "fa-loading"); - pb.Add(a => a.DeleteIcon, "fa-delte"); - pb.Add(a => a.CancelIcon, "fa-cancel"); - pb.Add(a => a.DownloadIcon, "fa-download"); - pb.Add(a => a.InvalidStatusIcon, "fa-invalid"); - pb.Add(a => a.ValidStatusIcon, "fa-valid"); - - pb.Add(a => a.FileIconArchive, "fa-file-text"); - pb.Add(a => a.FileIconExcel, "fa-file-excel"); - pb.Add(a => a.FileIconFile, "fa-file"); - pb.Add(a => a.FileIconDocx, "fa-file-word"); - pb.Add(a => a.FileIconPPT, "fa-file-powerpoint"); - pb.Add(a => a.FileIconAudio, "fa-file-audio"); - pb.Add(a => a.FileIconVideo, "fa-file-video"); - pb.Add(a => a.FileIconCode, "fa-file-code"); - pb.Add(a => a.FileIconPdf, "fa-file-pdf"); - pb.Add(a => a.FileIconImage, "fa-file-image"); - pb.Add(a => a.FileIconZip, "fa-file-archive"); - pb.Add(a => a.DefaultFileList, - [ - new() { FileName = "1.csv" }, - new() { FileName = "1.xls" }, - new() { FileName = "1.xlsx" }, - new() { FileName = "1.doc" }, - new() { FileName = "1.docx" }, - new() { FileName = "1.dot" }, - new() { FileName = "1.ppt" }, - new() { FileName = "1.pptx" }, - new() { FileName = "1.wav" }, - new() { FileName = "1.mp3" }, - new() { FileName = "1.mp4" }, - new() { FileName = "1.mov" }, - new() { FileName = "1.mkv" }, - new() { FileName = "1.cs" }, - new() { FileName = "1.html" }, - new() { FileName = "1.vb" }, - new() { FileName = "1.pdf" }, - new() { FileName = "1.zip" }, - new() { FileName = "1.rar" }, - new() { FileName = "1.iso" }, - new() { FileName = "1.txt" }, - new() { FileName = "1.log" }, - new() { FileName = "1.jpg" }, - new() { FileName = "1.jpeg" }, - new() { FileName = "1.png" }, - new() { FileName = "1.bmp" }, - new() { FileName = "1.gif" }, - new() { FileName = "1.test" }, - new() { FileName = "1" } - ]); - - }); - cut.Contains("fa-file-excel"); - cut.Contains("fa-file-word"); - cut.Contains("fa-file-powerpoint"); - cut.Contains("fa-file-audio"); - cut.Contains("fa-file-video"); - cut.Contains("fa-file-code"); - cut.Contains("fa-file-pdf"); - cut.Contains("fa-file-archive"); - cut.Contains("fa-file-text"); - cut.Contains("fa-file-image"); - cut.Contains("fa-file-archive"); - cut.Contains("fa-file"); - - cut.SetParametersAndRender(pb => - { - pb.Add(a => a.OnGetFileFormat, extensions => - { - return "fa-format-test"; - }); - }); - cut.Contains("fa-format-test"); - } - private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; From 7ee88fbffe459125c254f1c7088f947e13c9cc18 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:23:23 +0800 Subject: [PATCH 130/177] =?UTF-8?q?refactor:=20=E5=87=8F=E5=B0=91=E5=86=97?= =?UTF-8?q?=E4=BD=99=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/ButtonUpload.razor | 6 +- .../Components/Upload/DropUpload.razor | 6 +- .../Components/Upload/FileListUploadBase.cs | 78 ------------------- .../Components/Upload/UploadPreviewList.razor | 71 +++++++++-------- .../Upload/UploadPreviewList.razor.cs | 14 +++- test/UnitTest/Components/UploadButtonTest.cs | 18 ++--- 6 files changed, 57 insertions(+), 136 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor index 0360652f16d..66815687591 100644 --- a/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/ButtonUpload.razor @@ -16,11 +16,7 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" - FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" - FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" - FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" - FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete"> } diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index ead46f5ee70..3a70a75aba5 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -54,11 +54,7 @@ OnGetFileFormat="@OnGetFileFormat" OnCancel="OnCancel" CancelIcon="@CancelIcon" LoadingIcon="@LoadingIcon" InvalidStatusIcon="@InvalidStatusIcon" ValidStatusIcon="@ValidStatusIcon" ShowDownloadButton="@ShowDownloadButton" DownloadIcon="@DownloadIcon" OnDownload="@OnDownload" - DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete" - FileIconExcel="@FileIconExcel" FileIconDocx="@FileIconDocx" FileIconPPT="@FileIconPPT" - FileIconAudio="@FileIconAudio" FileIconVideo="@FileIconVideo" - FileIconCode="@FileIconCode" FileIconPdf="@FileIconPdf" FileIconZip="@FileIconZip" - FileIconArchive="@FileIconArchive" FileIconImage="@FileIconImage" FileIconFile="@FileIconFile"> + DeleteIcon="@DeleteIcon" OnDelete="@OnFileDelete"> } diff --git a/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs b/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs index b48d87e5452..8a29dda16c0 100644 --- a/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/FileListUploadBase.cs @@ -53,72 +53,6 @@ public class FileListUploadBase : UploadBase [Parameter] public Func? OnCancel { get; set; } - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconExcel { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconDocx { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPPT { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconAudio { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconVideo { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconCode { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconPdf { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconZip { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconArchive { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconImage { get; set; } - - /// - /// 获得/设置 Excel 类型文件图标 - /// - [Parameter] - public string? FileIconFile { get; set; } - /// /// 服务实例 /// @@ -136,17 +70,5 @@ protected override void OnParametersSet() DeleteIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDeleteIcon); DownloadIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadDownloadIcon); CancelIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadCancelIcon); - - FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); - FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); - FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); - FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); - FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); - FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); - FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); - FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); - FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); - FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); - FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } } diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor index d6002ea5ffa..371845f3008 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor @@ -1,38 +1,41 @@ @namespace BootstrapBlazor.Components -
      - @foreach (var item in Items) - { -
      - -
      - @item.GetFileName() - (@item.Size.ToFileSizeString()) -
      - @if (GetShowProgress(item)) - { - - - - } - else - { -
      - @if (item.Code == 0) - { - @if (ShowDownloadButton) +@if (Items != null) +{ +
      + @foreach (var item in Items) + { +
      + +
      + @item.GetFileName() + (@item.Size.ToFileSizeString()) +
      + @if (GetShowProgress(item)) + { + + + + } + else + { +
      + @if (item.Code == 0) { - + @if (ShowDownloadButton) + { + + } + } - - } - else - { - - } - -
      - } -
      - } -
      + else + { + + } + +
      + } +
      + } +
      +} diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs index daaa7e9227a..05806121dce 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor.cs @@ -206,11 +206,21 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= []; - LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadLoadingIcon); InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadInvalidStatusIcon); ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.UploadValidStatusIcon); + + FileIconExcel ??= IconTheme.GetIconByKey(ComponentIcons.FileIconExcel); + FileIconDocx ??= IconTheme.GetIconByKey(ComponentIcons.FileIconDocx); + FileIconPPT ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPPT); + FileIconAudio ??= IconTheme.GetIconByKey(ComponentIcons.FileIconAudio); + FileIconVideo ??= IconTheme.GetIconByKey(ComponentIcons.FileIconVideo); + FileIconCode ??= IconTheme.GetIconByKey(ComponentIcons.FileIconCode); + FileIconPdf ??= IconTheme.GetIconByKey(ComponentIcons.FileIconPdf); + FileIconZip ??= IconTheme.GetIconByKey(ComponentIcons.FileIconZip); + FileIconArchive ??= IconTheme.GetIconByKey(ComponentIcons.FileIconArchive); + FileIconImage ??= IconTheme.GetIconByKey(ComponentIcons.FileIconImage); + FileIconFile ??= IconTheme.GetIconByKey(ComponentIcons.FileIconFile); } private async Task OnClickDownload(UploadFile item) diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 3fb044166c1..474931115a1 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -354,18 +354,6 @@ public void ButtonUpload_OnGetFileFormat_Ok() pb.Add(a => a.DownloadIcon, "fa-download"); pb.Add(a => a.InvalidStatusIcon, "fa-invalid"); pb.Add(a => a.ValidStatusIcon, "fa-valid"); - - pb.Add(a => a.FileIconArchive, "fa-file-text"); - pb.Add(a => a.FileIconExcel, "fa-file-excel"); - pb.Add(a => a.FileIconFile, "fa-file"); - pb.Add(a => a.FileIconDocx, "fa-file-word"); - pb.Add(a => a.FileIconPPT, "fa-file-powerpoint"); - pb.Add(a => a.FileIconAudio, "fa-file-audio"); - pb.Add(a => a.FileIconVideo, "fa-file-video"); - pb.Add(a => a.FileIconCode, "fa-file-code"); - pb.Add(a => a.FileIconPdf, "fa-file-pdf"); - pb.Add(a => a.FileIconImage, "fa-file-image"); - pb.Add(a => a.FileIconZip, "fa-file-archive"); pb.Add(a => a.DefaultFileList, [ new() { FileName = "1.csv" }, @@ -421,6 +409,12 @@ public void ButtonUpload_OnGetFileFormat_Ok() }); }); cut.Contains("fa-format-test"); + + // Empty Items + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, null); + }); } private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile From 4c9f1aa04a8047d3b67496dd4ce5481ea9140824 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:23:47 +0800 Subject: [PATCH 131/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=20AllowExten?= =?UTF-8?q?sions=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadCardTest.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/UnitTest/Components/UploadCardTest.cs b/test/UnitTest/Components/UploadCardTest.cs index e80c530fdbe..e6d830b6b5b 100644 --- a/test/UnitTest/Components/UploadCardTest.cs +++ b/test/UnitTest/Components/UploadCardTest.cs @@ -145,6 +145,21 @@ public void CardUpload_ValidateForm_Ok() cut.Contains("form-label"); } + [Fact] + public void AllowExtensions_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.AllowExtensions, [".dba"]); + pb.Add(a => a.DefaultFileList, new List() + { + new() { FileName = "test.dba" } + }); + }); + + cut.Contains("test.dba (0 B)"); + } + [Fact] public async Task CardUpload_ShowProgress_Ok() { From 1703c2fcf7cba6559bd4acb2672ca2ddb69cde62 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 16:36:05 +0800 Subject: [PATCH 132/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=20IsImage=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadFile.cs | 2 +- test/UnitTest/Components/UploadCardTest.cs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index 1af91bf7274..1649d9ed892 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -81,7 +81,7 @@ public class UploadFile /// 获得 UploadFile 文件名 /// /// - public string? GetFileName() => FileName ?? OriginFileName; + public string? GetFileName() => FileName ?? OriginFileName ?? File?.Name; /// /// 获得 UploadFile 文件扩展名 diff --git a/test/UnitTest/Components/UploadCardTest.cs b/test/UnitTest/Components/UploadCardTest.cs index e6d830b6b5b..77e61bdb567 100644 --- a/test/UnitTest/Components/UploadCardTest.cs +++ b/test/UnitTest/Components/UploadCardTest.cs @@ -151,13 +151,21 @@ public void AllowExtensions_Ok() var cut = Context.RenderComponent>(pb => { pb.Add(a => a.AllowExtensions, [".dba"]); - pb.Add(a => a.DefaultFileList, new List() - { + pb.Add(a => a.DefaultFileList, + [ new() { FileName = "test.dba" } - }); + ]); }); - cut.Contains("test.dba (0 B)"); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new() { File = new MockBrowserFile("demo.dba") } + ]); + }); + cut.Contains("demo.dba (0 B)"); } [Fact] From bd806a14da436d793aff24eecc81ac809808d4a7 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 25 May 2025 20:35:47 +0800 Subject: [PATCH 133/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 23 ++++++++--------- test/UnitTest/Components/UploadAvatarTest.cs | 10 ++++++-- test/UnitTest/Components/UploadButtonTest.cs | 1 - test/UnitTest/Components/UploadDropTest.cs | 25 +++++++++++++++++++ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index 883902bbb07..f26406c9d78 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -16,20 +16,17 @@ {
      - @if (!IsDisabled) - { -
      - - +
      + + + + @if (GetShowProgress(item)) + { + + - @if (GetShowProgress(item)) - { - - - - } -
      - } + } +
      @if (!IsCircle) { diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 95e8bcd8a2c..6def5e6454e 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -163,7 +163,7 @@ await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List< } [Fact] - public void AvatarUpload_ShowProgress_Ok() + public async Task DropUpload_ShowProgress_Ok() { var cut = Context.RenderComponent>(pb => { @@ -172,10 +172,16 @@ public void AvatarUpload_ShowProgress_Ok() { await Task.Delay(100); await file.SaveToFileAsync("1.txt"); - SetUploaded(file, false); }); }); var input = cut.FindComponent(); + await cut.InvokeAsync(() => + { + _ = input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new() + })); + }); } private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 474931115a1..215c97acfab 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -386,7 +386,6 @@ public void ButtonUpload_OnGetFileFormat_Ok() new() { FileName = "1.test" }, new() { FileName = "1" } ]); - }); cut.Contains("fa-file-excel"); cut.Contains("fa-file-word"); diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index 6fe0157e5df..36eb6015a60 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -136,6 +136,31 @@ await cut.InvokeAsync(async () => }); } + + [Fact] + public void OnGetFileFormat_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.LoadingIcon, "fa-loading"); + pb.Add(a => a.DeleteIcon, "fa-delte"); + pb.Add(a => a.CancelIcon, "fa-cancel"); + pb.Add(a => a.DownloadIcon, "fa-download"); + pb.Add(a => a.InvalidStatusIcon, "fa-invalid"); + pb.Add(a => a.ValidStatusIcon, "fa-valid"); + pb.Add(a => a.ShowUploadFileList, true); + pb.Add(a => a.OnGetFileFormat, extensions => + { + return "fa-format-test"; + }); + pb.Add(a => a.DefaultFileList, + [ + new() { FileName = "1.csv" } + ]); + }); + cut.Contains("fa-format-test"); + } + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; From a63da1a993da38b355570d681d291830ec6c5d49 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 26 May 2025 09:35:51 +0800 Subject: [PATCH 134/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadAvatarTest.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 6def5e6454e..7ea5ce0e194 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -83,7 +83,7 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha { pb.Add(a => a.IsDisabled, true); }); - cut.DoesNotContain("upload-item-actions"); + cut.Contains("upload-item-actions"); // IsUploadButtonAtFirst cut.SetParametersAndRender(pb => @@ -184,6 +184,19 @@ await cut.InvokeAsync(() => }); } + [Fact] + public void IsImage_Ok() + { + var file = new UploadFile + { + File = new MockBrowserFile("test.text") + }; + Assert.True(file.IsImage([".text"])); + + file.File = new MockBrowserFile("test.jpg", "image/jpeg"); + Assert.True(file.IsImage()); + } + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; From 18f273de83a3cf8d3e16192c42f4ff94e4e2ac21 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 27 May 2025 09:47:26 +0800 Subject: [PATCH 135/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20Reset?= =?UTF-8?q?=20=E6=96=B9=E6=B3=95=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadBase.cs | 4 +++- test/UnitTest/Components/UploadInputTest.cs | 24 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index b28c64b0ba2..8776a56b690 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -186,7 +186,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) } else if (ValueType.IsAssignableTo(typeof(IEnumerable))) { - CurrentValue = (TValue)(object)string.Join(";", items.Select(f => f.OriginFileName)).ToList(); + CurrentValue = (TValue)(object)items.Select(f => f.OriginFileName).ToList(); } else if (ValueType == typeof(IBrowserFile)) { @@ -310,6 +310,8 @@ public virtual void Reset() { DefaultFileList?.Clear(); UploadFiles.Clear(); + _filesCache = null; + CurrentValue = default; StateHasChanged(); } diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index 1ef34045ecb..f1d77b9d4e1 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -145,7 +145,7 @@ public void InputUpload_FileValidate_OK() } [Fact] - public void InputUpload_Value() + public async Task InputUpload_Value() { var cut = Context.RenderComponent>>(pb => { @@ -156,10 +156,18 @@ public void InputUpload_Value() ]); }); Assert.Contains("test1.png;test2.png", cut.Markup); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test3.png"), + new("test4.png") + }))); + Assert.Contains("test3.png;test4.png", cut.Markup); } [Fact] - public void InputUpload_Files() + public async Task InputUpload_Files() { var cut = Context.RenderComponent>>(pb => { @@ -170,6 +178,18 @@ public void InputUpload_Files() ]); }); Assert.Contains("test1.png;test2.png", cut.Markup); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test3.png"), + new("test4.png") + }))); + Assert.Contains("test3.png;test4.png", cut.Markup); + + // 重置后不应该包含新上传的文件 + await cut.InvokeAsync(() => cut.Instance.Reset()); + Assert.DoesNotContain("test3.png;test4.png", cut.Markup); } [Fact] From 8c7060a3876e382e8d5c3ca6e53e93ad8b2c4ee1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 27 May 2025 10:35:56 +0800 Subject: [PATCH 136/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20MaxFil?= =?UTF-8?q?eCount=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 23 ++++--------------- .../Components/Upload/UploadBase.cs | 5 ++-- test/UnitTest/Components/UploadAvatarTest.cs | 17 +------------- test/UnitTest/Components/UploadInputTest.cs | 18 +++++++++++++++ 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index e4febe51d14..66930f3d387 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -87,28 +87,15 @@ public partial class AvatarUpload private string? GetValidStatus(UploadFile? item = null) { - if (ValidateForm == null) + if(item == null || IsDisabled || ValidateForm == null) { return null; } - if (IsDisabled) - { - return null; - } - - if(item == null) - { - return null; - } - - var state = item.IsValid ?? IsValid; - if (state == null) - { - return null; - } - - return state.Value ? "is-valid" : "is-invalid"; + var state = item.IsValid; + return state.HasValue + ? state.Value ? "is-valid" : "is-invalid" + : null; } /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 8776a56b690..2d2a565b9f4 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -143,8 +143,9 @@ protected override void OnParametersSet() /// protected async Task OnFileChange(InputFileChangeEventArgs args) { - var fileCount = MaxFileCount ?? args.FileCount; - var items = args.GetMultipleFiles(fileCount).Select(f => + var fileCount = MaxFileCount ?? 0; + fileCount = Math.Max(fileCount, args.FileCount); + var items = args.GetMultipleFiles(args.FileCount).Take(fileCount).Select(f => { var file = new UploadFile() { diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 7ea5ce0e194..f5799cc04bd 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Components.Forms; using System.Runtime.CompilerServices; +using System.Threading.Tasks; namespace UnitTest.Components; @@ -94,22 +95,6 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha }); } - [Fact] - public void MaxFileCount_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsMultiple, true); - pb.Add(a => a.MaxFileCount, 2); - pb.Add(a => a.DefaultFileList, - [ - new UploadFile { FileName = "Test-File" }, - new UploadFile { FileName = "Test-File" } - ]); - }); - Assert.DoesNotContain(".upload-item-plus", cut.Markup); - } - [Fact] public async Task AvatarUpload_ValidateForm_Ok() { diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index f1d77b9d4e1..144729ce7ca 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -227,6 +227,24 @@ public void InputUpload_IsMultiple() Assert.False(button.IsDisabled()); } + [Fact] + public async Task MaxFileCount_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.MaxFileCount, 4); + }); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test1.png"), new("test2.png"), new("test3.png") + }))); + cut.Contains("test1.png;test2.png"); + cut.DoesNotContain("test3.png"); + } + private class Person { [Required] From 80e65eaff02efb1d98424179283e9f80d26f3596 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 27 May 2025 11:27:50 +0800 Subject: [PATCH 137/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20MaxFil?= =?UTF-8?q?eCount=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadBase.cs | 16 ++++++++++++++-- test/UnitTest/Components/UploadInputTest.cs | 19 ++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 2d2a565b9f4..9028b88ce7f 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -143,8 +143,20 @@ protected override void OnParametersSet() /// protected async Task OnFileChange(InputFileChangeEventArgs args) { - var fileCount = MaxFileCount ?? 0; - fileCount = Math.Max(fileCount, args.FileCount); + var fileCount = args.FileCount; + if (MaxFileCount.HasValue) + { + fileCount = MaxFileCount.Value; + } + + // 计算剩余可上传数量 + fileCount = fileCount - Files.Count; + if (fileCount <= 0) + { + // 如果剩余可上传数量小于等于 0 则不允许继续上传 + return; + } + var items = args.GetMultipleFiles(args.FileCount).Take(fileCount).Select(f => { var file = new UploadFile() diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index 144729ce7ca..c2762c2cd48 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -190,6 +190,23 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha // 重置后不应该包含新上传的文件 await cut.InvokeAsync(() => cut.Instance.Reset()); Assert.DoesNotContain("test3.png;test4.png", cut.Markup); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.DefaultFileList, + [ + new UploadFile() { FileName = "test5.png" }, + new UploadFile() { FileName = "test6.png" } + ]); + pb.Add(a => a.Value, + [ + new MockBrowserFile("test5.png"), + new MockBrowserFile("test6.png") + ]); + }); + Assert.Contains("test5.png;test6.png", cut.Markup); + await cut.InvokeAsync(() => cut.Instance.Reset()); + Assert.DoesNotContain("test5.png;test6.png", cut.Markup); } [Fact] @@ -233,7 +250,7 @@ public async Task MaxFileCount_Ok() var cut = Context.RenderComponent>(pb => { pb.Add(a => a.IsMultiple, true); - pb.Add(a => a.MaxFileCount, 4); + pb.Add(a => a.MaxFileCount, 2); }); var input = cut.FindComponent(); From 9bc11e0a559c2a23ea886d11b930dd59c5a9c367 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 27 May 2025 12:13:34 +0800 Subject: [PATCH 138/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8C=89=E9=92=AE=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadCardTest.cs | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/test/UnitTest/Components/UploadCardTest.cs b/test/UnitTest/Components/UploadCardTest.cs index 77e61bdb567..5cf60a2142c 100644 --- a/test/UnitTest/Components/UploadCardTest.cs +++ b/test/UnitTest/Components/UploadCardTest.cs @@ -200,7 +200,26 @@ await cut.InvokeAsync(() => Assert.True(cancel); } - private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + [Fact] + public async Task ShowDeleteButton_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowDeleteButton, true); + pb.Add(a => a.IsDisabled, true); + }); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test3.png", delay: TimeSpan.FromMilliseconds(300)), + }))); + + var btn = cut.Find(".btn-outline-danger"); + btn.InnerHtml.Contains("disabled=\"disabled\""); + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text", TimeSpan? delay = null) : IBrowserFile { public string Name { get; } = name; @@ -212,6 +231,10 @@ private class MockBrowserFile(string name = "UploadTestFile", string contentType public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) { + if (delay != null) + { + Thread.Sleep(delay.Value.Milliseconds); + } return new MemoryStream([0x01, 0x02]); } } From 02f559907d037be602ce54a4e89e8fad387ee5d9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 27 May 2025 12:54:39 +0800 Subject: [PATCH 139/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=20FileValida?= =?UTF-8?q?tionAttribute=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Attributes/FileValidationAttribute.cs | 7 +- .../Attributes/FileValidationAttributeTest.cs | 98 +++++++++++++++++++ 2 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 test/UnitTest/Attributes/FileValidationAttributeTest.cs diff --git a/src/BootstrapBlazor/Attributes/FileValidationAttribute.cs b/src/BootstrapBlazor/Attributes/FileValidationAttribute.cs index acfed7bec48..3e3d601027c 100644 --- a/src/BootstrapBlazor/Attributes/FileValidationAttribute.cs +++ b/src/BootstrapBlazor/Attributes/FileValidationAttribute.cs @@ -56,10 +56,5 @@ public class FileValidationAttribute : ValidationAttribute return ret; } - private static IEnumerable? GetMemberNames(ValidationContext validationContext) - { - return validationContext == null ? [] : GetMemberNames(); - - IEnumerable GetMemberNames() => string.IsNullOrEmpty(validationContext.MemberName) ? [] : [validationContext.MemberName]; - } + private static IEnumerable? GetMemberNames(ValidationContext validationContext) => validationContext == null || string.IsNullOrEmpty(validationContext.MemberName) ? [] : [validationContext.MemberName]; } diff --git a/test/UnitTest/Attributes/FileValidationAttributeTest.cs b/test/UnitTest/Attributes/FileValidationAttributeTest.cs new file mode 100644 index 00000000000..4be0f49a5cf --- /dev/null +++ b/test/UnitTest/Attributes/FileValidationAttributeTest.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; + +namespace UnitTest.Attributes; + +public class FileValidationAttributeTest : BootstrapBlazorTestBase +{ + [Fact] + public void FileSize_Ok() + { + var validator = new FileValidationAttribute() + { + FileSize = 5 + }; + var p = new Person() + { + Picture = new MockBrowserFile("test.log") + }; + var result = validator.GetValidationResult(p.Picture, new ValidationContext(p)); + Assert.NotEqual(ValidationResult.Success, result); + } + + [Fact] + public void FileExtensions_Ok() + { + var validator = new FileValidationAttribute() + { + Extensions = ["jpg"] + }; + var p = new Person() + { + Picture = new MockBrowserFile("test.log") + }; + var result = validator.GetValidationResult(p.Picture, new ValidationContext(p)); + Assert.NotEqual(ValidationResult.Success, result); + + result = validator.GetValidationResult(p.Picture, new ValidationContext(p) { MemberName = "Pic" }); + Assert.NotEqual(ValidationResult.Success, result); + } + + [Fact] + public void IsValid_Ok() + { + var validator = new FileValidationAttribute() + { + Extensions = ["jpg"] + }; + var p = new Person() + { + Picture = new MockBrowserFile("test.log") + }; + Assert.False(validator.IsValid(p.Picture)); + } + + [Fact] + public void Validate_Ok() + { + var validator = new FileValidationAttribute() + { + Extensions = ["jpg"] + }; + var p = new Person() + { + Picture = new MockBrowserFile("test.log") + }; + Assert.Throws(() => validator.Validate(p.Picture, "Picture")); + Assert.Throws(() => validator.Validate(p.Picture, new ValidationContext(p))); + } + + private class Person + { + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] + + public IBrowserFile? Picture { get; set; } + } + + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile + { + public string Name { get; } = name; + + public DateTimeOffset LastModified { get; } = DateTimeOffset.Now; + + public long Size { get; } = 10; + + public string ContentType { get; } = contentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + return new MemoryStream([0x01, 0x02]); + } + } +} From 01ce5c987668abc46d6b0fd2f070be126e6efd52 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 09:29:47 +0800 Subject: [PATCH 140/177] =?UTF-8?q?refactor:=20=E7=B2=BE=E7=AE=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 66930f3d387..285962a1efd 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -85,19 +85,6 @@ public partial class AvatarUpload .AddClass(GetValidStatus(item)) .Build(); - private string? GetValidStatus(UploadFile? item = null) - { - if(item == null || IsDisabled || ValidateForm == null) - { - return null; - } - - var state = item.IsValid; - return state.HasValue - ? state.Value ? "is-valid" : "is-invalid" - : null; - } - /// /// 获得/设置 预览框 Style 属性 /// @@ -136,7 +123,6 @@ protected override void OnParametersSet() // 头像上传时如果用户没有设置 OnChanged 回调,需要使用内置方法将文件头像转化未 Base64 格式用于预览 OnChange ??= async item => { - item.ValidateId = $"{Id}_{item.GetHashCode()}"; await item.RequestBase64ImageFileAsync(); }; } @@ -151,4 +137,17 @@ protected override void OnParametersSet() } private string? AddId => Files.Count == 0 ? $"{Id}_new" : null; + + private string? GetValidStatus(UploadFile? item = null) + { + if (item == null || IsDisabled || ValidateForm == null) + { + return null; + } + + var state = item.IsValid; + return state.HasValue + ? state.Value ? "is-valid" : "is-invalid" + : null; + } } From 1d07fe3b94be166a5014d697ac8c5262c98177c1 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 10:23:40 +0800 Subject: [PATCH 141/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8C=96=E6=8F=8F=E8=BF=B0=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Locales/zh.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Locales/zh.json b/src/BootstrapBlazor/Locales/zh.json index 2997ab392b7..d86af6090e7 100644 --- a/src/BootstrapBlazor/Locales/zh.json +++ b/src/BootstrapBlazor/Locales/zh.json @@ -323,7 +323,7 @@ "BrowserButtonText": "浏览", "FileExtensions": "文件扩展名必须为以下几种格式: {0}", "FileSizeValidation": "文件太大,文件限制大小为 {0}", - "DropUploadText": "拖拽文件到此处上传", + "DropUploadText": "拖拽文件到此处或者点击上传", "DropFooterText": "" }, "BootstrapBlazor.Components.Handwritten": { From 50a93067098a01cc93a8ce6c501ddb05472339b0 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 10:23:52 +0800 Subject: [PATCH 142/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=20Footer?= =?UTF-8?q?=20=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/DropUpload.razor | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor b/src/BootstrapBlazor/Components/Upload/DropUpload.razor index 3a70a75aba5..166cd4d6788 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor @@ -33,21 +33,21 @@ @(new MarkupString(UploadText)) }
      - } -
      - @if (ShowFooter) - { - - } + } +
      @if (ShowUploadFileList) { Date: Wed, 28 May 2025 10:33:34 +0800 Subject: [PATCH 143/177] =?UTF-8?q?refactor(Tooltip):=20=E7=B2=BE=E7=AE=80?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/validate.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/BootstrapBlazor/wwwroot/modules/validate.js b/src/BootstrapBlazor/wwwroot/modules/validate.js index 15f5fd1e0c4..f06138ae67a 100644 --- a/src/BootstrapBlazor/wwwroot/modules/validate.js +++ b/src/BootstrapBlazor/wwwroot/modules/validate.js @@ -33,12 +33,7 @@ export function dispose(id) { if (el) { const tip = bootstrap.Tooltip.getInstance(el) if (tip) { - const handler = setTimeout(() => { - clearTimeout(handler) - if (tip && tip._element) { - tip.dispose() - } - }, 100); + tip.dispose() } } } From 9e44f70da80b0f7c73d4aadef53c9bb64dce9b1d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 11:02:04 +0800 Subject: [PATCH 144/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20MaxFil?= =?UTF-8?q?eCount=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/UploadBase.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 9028b88ce7f..6018098da93 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -147,14 +147,14 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) if (MaxFileCount.HasValue) { fileCount = MaxFileCount.Value; - } - // 计算剩余可上传数量 - fileCount = fileCount - Files.Count; - if (fileCount <= 0) - { - // 如果剩余可上传数量小于等于 0 则不允许继续上传 - return; + // 计算剩余可上传数量 + fileCount = fileCount - Files.Count; + if (fileCount <= 0) + { + // 如果剩余可上传数量小于等于 0 则不允许继续上传 + return; + } } var items = args.GetMultipleFiles(args.FileCount).Take(fileCount).Select(f => From 35f8b1d416dfc44f8c4ae61574de52e4a043c736 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:03:50 +0800 Subject: [PATCH 145/177] =?UTF-8?q?style:=20=E5=A2=9E=E5=8A=A0=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/InputUpload.razor.scss | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 88c7ec179e2..9092142062e 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -294,6 +294,22 @@ .upload.is-drop { + &.dropping { + .upload-drop-body { + border-color: var(--bs-success); + + * { + pointer-events: none; + } + } + + &.disabled { + .upload-drop-body { + border-color: var(--bs-danger); + } + } + } + &.disabled { .upload-drop-body { border-color: var(--bs-border-color); From 25586637ffac0307d4387df06c4e14e8ad5de6e4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:04:40 +0800 Subject: [PATCH 146/177] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=8B=96?= =?UTF-8?q?=E5=8A=A8=E4=B8=8A=E4=BC=A0=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/upload.js | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor/wwwroot/modules/upload.js b/src/BootstrapBlazor/wwwroot/modules/upload.js index 97e0ddaa52b..28334a53267 100644 --- a/src/BootstrapBlazor/wwwroot/modules/upload.js +++ b/src/BootstrapBlazor/wwwroot/modules/upload.js @@ -7,7 +7,8 @@ export function init(id) { return } const preventHandler = e => e.preventDefault() - const upload = { el, preventHandler } + const body = el.querySelector('.upload-drop-body'); + const upload = { el, body, preventHandler } Data.set(id, upload) const inputFile = el.querySelector('[type="file"]') @@ -20,7 +21,20 @@ export function init(id) { EventHandler.on(document, 'dragenter', preventHandler) EventHandler.on(document, 'dragover', preventHandler) - EventHandler.on(el, 'drop', e => { + EventHandler.on(body, 'dragenter', e => { + el.classList.add('dropping'); + }) + + EventHandler.on(body, 'dragleave', e => { + el.classList.remove('dropping'); + }); + + EventHandler.on(body, 'drop', e => { + el.classList.remove('dropping'); + + if (el.classList.contains('disabled')) { + return; + } try { const fileList = e.dataTransfer.files if (fileList.length === 0) { @@ -36,6 +50,10 @@ export function init(id) { }) EventHandler.on(el, 'paste', e => { + if (el.classList.contains('disabled')) { + return; + } + inputFile.files = e.clipboardData.files const event = new Event('change', { bubbles: true }) inputFile.dispatchEvent(event) @@ -66,14 +84,18 @@ export function dispose(id) { Data.remove(id) if (upload) { - const { el, preventHandler } = upload; + const { el, body, preventHandler } = upload; - EventHandler.off(el, 'click') - EventHandler.off(el, 'drop') - EventHandler.off(el, 'paste') EventHandler.off(document, 'dragleave', preventHandler) EventHandler.off(document, 'drop', preventHandler) EventHandler.off(document, 'dragenter', preventHandler) EventHandler.off(document, 'dragover', preventHandler) + + EventHandler.off(el, 'click') + EventHandler.off(el, 'drop') + EventHandler.off(el, 'paste') + EventHandler.off(body, 'dragleave') + EventHandler.off(body, 'drop') + EventHandler.off(body, 'dragenter') } } From d5af109375cabe6e28b1255e92cef5ab65434a8c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:05:08 +0800 Subject: [PATCH 147/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E7=8A=B6=E6=80=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index 6469be9b33d..e9cf8a3a20d 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -98,16 +98,16 @@ public partial class DropUpload private IStringLocalizer>? Localizer { get; set; } private string? ClassString => CssBuilder.Default("upload is-drop") - .AddClass("disabled", CanUpload() == false) + .AddClass("disabled", CheckStatus()) .AddClassFromAttributes(AdditionalAttributes) .Build(); private string? BodyClassString => CssBuilder.Default("upload-drop-body") - .AddClass("btn-browser", CanUpload()) + .AddClass("btn-browser", CheckStatus() == false) .Build(); private string? TextClassString => CssBuilder.Default("upload-drop-text") - .AddClass("text-muted", CanUpload() == false) + .AddClass("text-muted", CheckStatus()) .Build(); /// From 2f97d1082f338a722cf61ab71e3b6b21fb21998e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:19:47 +0800 Subject: [PATCH 148/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=AD=A3=E5=90=88?= =?UTF-8?q?=E6=B3=95=E7=8A=B6=E6=80=81=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor index 371845f3008..6678f3f64f3 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor +++ b/src/BootstrapBlazor/Components/Upload/UploadPreviewList.razor @@ -26,11 +26,11 @@ { } - + } else { - + }
      From 3c2763673439bcc670572b0de414ebbe27e4defd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:29:49 +0800 Subject: [PATCH 149/177] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20DropFo?= =?UTF-8?q?oterText=20=E6=9C=AC=E5=9C=B0=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs | 1 - src/BootstrapBlazor/Locales/en.json | 3 +-- src/BootstrapBlazor/Locales/zh.json | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs index e9cf8a3a20d..90ce8b9c0dc 100644 --- a/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/DropUpload.razor.cs @@ -119,6 +119,5 @@ protected override void OnParametersSet() UploadIcon ??= IconTheme.GetIconByKey(ComponentIcons.DropUploadIcon); UploadText ??= Localizer["DropUploadText"]; - FooterText ??= Localizer["DropFooterText"]; } } diff --git a/src/BootstrapBlazor/Locales/en.json b/src/BootstrapBlazor/Locales/en.json index 70420663e99..4ac10f71911 100644 --- a/src/BootstrapBlazor/Locales/en.json +++ b/src/BootstrapBlazor/Locales/en.json @@ -323,8 +323,7 @@ "BrowserButtonText": "Browser", "FileExtensions": "File must have one of the following extensions: {0}", "FileSizeValidation": "File size must less than {0}", - "DropUploadText": "Drop files here or click to upload", - "DropFooterText": "" + "DropUploadText": "Drop files here or click to upload" }, "BootstrapBlazor.Components.Handwritten": { "SaveButtonText": "Save", diff --git a/src/BootstrapBlazor/Locales/zh.json b/src/BootstrapBlazor/Locales/zh.json index d86af6090e7..84ba7dc3a27 100644 --- a/src/BootstrapBlazor/Locales/zh.json +++ b/src/BootstrapBlazor/Locales/zh.json @@ -323,8 +323,7 @@ "BrowserButtonText": "浏览", "FileExtensions": "文件扩展名必须为以下几种格式: {0}", "FileSizeValidation": "文件太大,文件限制大小为 {0}", - "DropUploadText": "拖拽文件到此处或者点击上传", - "DropFooterText": "" + "DropUploadText": "拖拽文件到此处或者点击上传" }, "BootstrapBlazor.Components.Handwritten": { "SaveButtonText": "保存", From bb99f8e844df279d1bf9638927b18313f53faba8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:30:06 +0800 Subject: [PATCH 150/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20MaxFileCou?= =?UTF-8?q?nt=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadDropTest.cs | 27 ++++++++++++++++++++- test/UnitTest/Components/UploadInputTest.cs | 18 -------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index 36eb6015a60..f65499c7edf 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -48,7 +48,7 @@ public void DropUpload_Footer_Ok() { pb.Add(a => a.ShowFooter, true); }); - cut.Contains("
      "); + cut.Contains("
      "); cut.SetParametersAndRender(pb => { @@ -57,6 +57,31 @@ public void DropUpload_Footer_Ok() cut.Contains("
      drop-upload-footer-text
      "); } + [Fact] + public async Task MaxFileCount_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.MaxFileCount, 2); + }); + + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test1.png") + }))); + cut.Contains("test1.png"); + + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test2.png"), + new("test3.png") + }))); + cut.Contains("test2.png"); + cut.DoesNotContain("test3.png"); + } + [Fact] public async Task DropUpload_OnChanged_Ok() { diff --git a/test/UnitTest/Components/UploadInputTest.cs b/test/UnitTest/Components/UploadInputTest.cs index c2762c2cd48..0d1e83d1f54 100644 --- a/test/UnitTest/Components/UploadInputTest.cs +++ b/test/UnitTest/Components/UploadInputTest.cs @@ -244,24 +244,6 @@ public void InputUpload_IsMultiple() Assert.False(button.IsDisabled()); } - [Fact] - public async Task MaxFileCount_Ok() - { - var cut = Context.RenderComponent>(pb => - { - pb.Add(a => a.IsMultiple, true); - pb.Add(a => a.MaxFileCount, 2); - }); - - var input = cut.FindComponent(); - await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() - { - new("test1.png"), new("test2.png"), new("test3.png") - }))); - cut.Contains("test1.png;test2.png"); - cut.DoesNotContain("test3.png"); - } - private class Person { [Required] From 854013cdecd64753a2d1d7707e222baa6739e72a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:33:30 +0800 Subject: [PATCH 151/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20FooterText?= =?UTF-8?q?=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadDropTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index f65499c7edf..72c346060a8 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -47,8 +47,9 @@ public void DropUpload_Footer_Ok() var cut = Context.RenderComponent(pb => { pb.Add(a => a.ShowFooter, true); + pb.Add(a => a.FooterText, "drop-upload-footer-text1"); }); - cut.Contains("
      "); + cut.Contains("
      drop-upload-footer-text1
      "); cut.SetParametersAndRender(pb => { From 352da6b9e4fbd87c4cb3be93f67994035aed29d8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 12:39:53 +0800 Subject: [PATCH 152/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20MaxFileCou?= =?UTF-8?q?nt=20=E6=BA=A2=E5=87=BA=E9=80=BB=E8=BE=91=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadDropTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/UnitTest/Components/UploadDropTest.cs b/test/UnitTest/Components/UploadDropTest.cs index 72c346060a8..bd06fb28ce7 100644 --- a/test/UnitTest/Components/UploadDropTest.cs +++ b/test/UnitTest/Components/UploadDropTest.cs @@ -70,16 +70,16 @@ public async Task MaxFileCount_Ok() var input = cut.FindComponent(); await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() { - new("test1.png") + new("test1.png"), + new("test2.png") }))); cut.Contains("test1.png"); + cut.Contains("test2.png"); await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() { - new("test2.png"), new("test3.png") }))); - cut.Contains("test2.png"); cut.DoesNotContain("test3.png"); } From 844230e9433c8027ac4efea706886e10ef4bf718 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 13:02:21 +0800 Subject: [PATCH 153/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20avatar?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E9=AA=8C=E8=AF=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 285962a1efd..fff68ffcfd3 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -140,12 +140,12 @@ protected override void OnParametersSet() private string? GetValidStatus(UploadFile? item = null) { - if (item == null || IsDisabled || ValidateForm == null) + if (IsDisabled || ValidateForm == null) { return null; } - var state = item.IsValid; + var state = item?.IsValid ?? IsValid; return state.HasValue ? state.Value ? "is-valid" : "is-invalid" : null; From 78382e09008e9edc5595f9bd770ca995bf2d4159 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 13:02:31 +0800 Subject: [PATCH 154/177] =?UTF-8?q?style:=20=E8=B0=83=E6=95=B4=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss index 9092142062e..89294fbba09 100644 --- a/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss +++ b/src/BootstrapBlazor/Components/Upload/InputUpload.razor.scss @@ -78,10 +78,6 @@ color: var(--bs-danger); } -.upload .upload-body.is-list .upload-item:hover .invalid-icon { - display: none; -} - .upload .upload-body.is-list .download-icon { color: var(--bs-primary); } From 50b20cfc7ec539ba5d126e05dfcc27d1287197d2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 13:02:46 +0800 Subject: [PATCH 155/177] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E7=BB=84=E4=BB=B6=E6=95=B0=E6=8D=AE=E5=90=88=E8=A7=84?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 315a1cb9d58..46fc03b698d 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -503,6 +503,9 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext { // 优先检查 File 流,不需要检查 FileName ValidateDataAnnotations(file.File, context, messages, pi, file.ValidateId); + + // 如果 message 不为空表示验证失败 + file.IsValid = messages.Count == 0; }); } else From ecaf0bfe70d736515caed7a0c6de2c9e25c298a2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 15:28:16 +0800 Subject: [PATCH 156/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=88=E8=A7=84=E6=A3=80=E6=9F=A5=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E9=9B=86=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Validate/IValidateComponent.cs | 2 +- .../Components/Validate/ValidateBase.cs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs b/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs index 90781e89a3a..dd51f2c80e4 100644 --- a/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs +++ b/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs @@ -33,5 +33,5 @@ public interface IValidateComponent /// 显示或者隐藏提示信息方法 /// /// - void ToggleMessage(IEnumerable results); + void ToggleMessage(IReadOnlyCollection results); } diff --git a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs index 5f2c2a55e4c..6dad39a0473 100644 --- a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs +++ b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs @@ -327,7 +327,7 @@ protected override void OnParametersSet() } /// - /// OnAfterRender 方法 + /// /// /// protected override async Task OnAfterRenderAsync(bool firstRender) @@ -460,7 +460,7 @@ private void ValidateType(ValidationContext context, List resu /// 显示/隐藏验证结果方法 /// /// - public virtual void ToggleMessage(IEnumerable results) + public virtual void ToggleMessage(IReadOnlyCollection results) { if (FieldIdentifier != null) { @@ -483,9 +483,16 @@ public virtual void ToggleMessage(IEnumerable results) StateHasChanged(); } - private JSModule? ValidateModule { get; set; } + /// + /// Gets or sets the module of validate instance. + /// + protected JSModule? ValidateModule { get; set; } - private Task LoadValidateModule() => JSRuntime.LoadModuleByName("validate"); + /// + /// 加载 validate 模块方法 + /// + /// + protected Task LoadValidateModule() => JSRuntime.LoadModuleByName("validate"); /// /// 增加客户端 Tooltip 方法 From 82e416f42de2997bca59b6d21142ebc595019453 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 28 May 2025 17:37:31 +0800 Subject: [PATCH 157/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=8F=90=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 56 +++++++++++++++++-- .../Components/Upload/UploadBase.cs | 30 +--------- .../wwwroot/modules/validate.js | 17 ++++++ 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index fff68ffcfd3..0f1e48dda8b 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -128,15 +128,57 @@ protected override void OnParametersSet() } /// - /// 获得 数据验证客户端 ID + /// + /// + /// + protected override async ValueTask ShowValidResult() + { + ValidateModule ??= await LoadValidateModule(); + + var items = Files.Count == 0 && _results.Count > 0 + ? [new { Id = AddId, _results.First().ErrorMessage }] + : _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }); + await ValidateModule.InvokeVoidAsync("executeBatch", items); + + if (Files.Count > 0) + { + await ValidateModule.InvokeVoidAsync("dispose", AddId); + } + } + + /// + /// /// /// - protected override string? RetrieveId() + protected override async ValueTask RemoveValidResult(string? validateId = null) + { + ValidateModule ??= await LoadValidateModule(); + + var items = new List(); + if (!string.IsNullOrEmpty(validateId)) + { + items.Add(validateId); + } + else + { + items.AddRange(Files.Select(f => f.ValidateId)); + } + await ValidateModule.InvokeVoidAsync("disposeBatch", items); + } + + private IReadOnlyCollection _results = []; + + /// + /// + /// + /// + public override void ToggleMessage(IReadOnlyCollection results) { - return Files.Count == 0 ? $"{Id}_new" : Files[0].ValidateId; + _results = results; + IsValid = results.Count == 0; } - private string? AddId => Files.Count == 0 ? $"{Id}_new" : null; + private string? AddId => $"{Id}_new"; private string? GetValidStatus(UploadFile? item = null) { @@ -145,6 +187,12 @@ protected override void OnParametersSet() return null; } + if (item == null && Files.Count > 0) + { + // 如果没有文件则使用组件本身的 IsValid 状态 + return null; + } + var state = item?.IsValid ?? IsValid; return state.HasValue ? state.Value ? "is-valid" : "is-invalid" diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 6018098da93..7871c9d6b7a 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -181,7 +181,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) // 回调给用户,用于存储文件并生成预览地址给 PreUrl if (OnChange != null) { - await OnChange(item); + //await OnChange(item); } item.Uploaded = true; StateHasChanged(); @@ -328,34 +328,6 @@ public virtual void Reset() StateHasChanged(); } - /// - /// - /// - /// - public override void ToggleMessage(IEnumerable results) - { - if (FieldIdentifier != null) - { - var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.Value.FieldName)).ToList(); - if (messages.Count == 0) - { - messages = [.. results.Where(item => item.MemberNames.Any(m => UploadFiles.Any(f => f.ValidateId?.Equals(m, StringComparison.OrdinalIgnoreCase) ?? false)))]; - } - if (messages.Count > 0) - { - ErrorMessage = messages.First().ErrorMessage; - IsValid = false; - } - else - { - ErrorMessage = null; - IsValid = true; - } - - OnValidate(IsValid); - } - } - /// /// append html attribute method. /// diff --git a/src/BootstrapBlazor/wwwroot/modules/validate.js b/src/BootstrapBlazor/wwwroot/modules/validate.js index f06138ae67a..96a09825917 100644 --- a/src/BootstrapBlazor/wwwroot/modules/validate.js +++ b/src/BootstrapBlazor/wwwroot/modules/validate.js @@ -37,3 +37,20 @@ export function dispose(id) { } } } + +export function executeBatch(items) { + console.log("executeBatch", items); + + items.forEach(item => { + const { id, errorMessage } = item; + execute(id, errorMessage); + }) +} + +export function disposeBatch(items) { + console.log("disposeBatch", items); + + items.forEach(id => { + dispose(id); + }) +} From 954dd32e2bdff1469b97b31d13b8b8903bb1c454 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 09:22:03 +0800 Subject: [PATCH 158/177] =?UTF-8?q?refactor:=20ToggleMessage=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=9B=B4=E6=94=B9=E4=B8=BA=20Task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Validate/IValidateComponent.cs | 2 +- src/BootstrapBlazor/Components/Validate/ValidateBase.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs b/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs index dd51f2c80e4..c00d08a52b1 100644 --- a/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs +++ b/src/BootstrapBlazor/Components/Validate/IValidateComponent.cs @@ -33,5 +33,5 @@ public interface IValidateComponent /// 显示或者隐藏提示信息方法 /// /// - void ToggleMessage(IReadOnlyCollection results); + Task ToggleMessage(IReadOnlyCollection results); } diff --git a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs index 6dad39a0473..bc6b72bb54e 100644 --- a/src/BootstrapBlazor/Components/Validate/ValidateBase.cs +++ b/src/BootstrapBlazor/Components/Validate/ValidateBase.cs @@ -460,7 +460,7 @@ private void ValidateType(ValidationContext context, List resu /// 显示/隐藏验证结果方法 /// /// - public virtual void ToggleMessage(IReadOnlyCollection results) + public virtual Task ToggleMessage(IReadOnlyCollection results) { if (FieldIdentifier != null) { @@ -481,6 +481,7 @@ public virtual void ToggleMessage(IReadOnlyCollection results) // 必须刷新一次 UI 保证状态正确 StateHasChanged(); + return Task.CompletedTask; } /// From 1e99c95b10bf68fa4637deecc926167c01a3c4b9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 09:49:33 +0800 Subject: [PATCH 159/177] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20await?= =?UTF-8?q?=20=E5=85=B3=E9=94=AE=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Select/MultiSelect.razor.cs | 2 +- .../SelectGeneric/MultiSelectGeneric.razor.cs | 2 +- .../Components/Transfer/Transfer.razor.cs | 2 +- .../ValidateForm/ValidateForm.razor.cs | 20 +++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs b/src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs index cf4771c2ef1..04b277eae73 100644 --- a/src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs +++ b/src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs @@ -454,7 +454,7 @@ private async Task SetValue() var validationResults = new List(); await ValidatePropertyAsync(CurrentValue, validationContext, validationResults); - ToggleMessage(validationResults); + await ToggleMessage(validationResults); } if (OnSelectedItemsChanged != null) diff --git a/src/BootstrapBlazor/Components/SelectGeneric/MultiSelectGeneric.razor.cs b/src/BootstrapBlazor/Components/SelectGeneric/MultiSelectGeneric.razor.cs index e2ae8e1e182..096f5352a02 100644 --- a/src/BootstrapBlazor/Components/SelectGeneric/MultiSelectGeneric.razor.cs +++ b/src/BootstrapBlazor/Components/SelectGeneric/MultiSelectGeneric.razor.cs @@ -430,7 +430,7 @@ private async Task SetValue() var validationResults = new List(); await ValidatePropertyAsync(CurrentValue, validationContext, validationResults); - ToggleMessage(validationResults); + await ToggleMessage(validationResults); } if (OnSelectedItemsChanged != null) diff --git a/src/BootstrapBlazor/Components/Transfer/Transfer.razor.cs b/src/BootstrapBlazor/Components/Transfer/Transfer.razor.cs index e24245d6acf..e2ef7309c59 100644 --- a/src/BootstrapBlazor/Components/Transfer/Transfer.razor.cs +++ b/src/BootstrapBlazor/Components/Transfer/Transfer.razor.cs @@ -317,7 +317,7 @@ private async Task TransferItems(List source, List t var validationResults = new List(); await ValidatePropertyAsync(RightItems, validationContext, validationResults); - ToggleMessage(validationResults); + await ToggleMessage(validationResults); } } } diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 46fc03b698d..d274c8038c1 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -169,20 +169,20 @@ internal void AddValidator((string FieldName, Type ModelType) key, (FieldIdentif /// /// /// 错误描述信息,可为空,为空时查找资源文件 - public void SetError(Expression> expression, string errorMessage) + public async Task SetError(Expression> expression, string errorMessage) { switch (expression.Body) { case UnaryExpression { Operand: MemberExpression mem }: - InternalSetError(mem, errorMessage); + await InternalSetError(mem, errorMessage); break; case MemberExpression exp: - InternalSetError(exp, errorMessage); + await InternalSetError(exp, errorMessage); break; } } - private void InternalSetError(MemberExpression exp, string errorMessage) + private async Task InternalSetError(MemberExpression exp, string errorMessage) { if (exp.Expression != null) { @@ -198,7 +198,7 @@ private void InternalSetError(MemberExpression exp, string errorMessage) { new(errorMessage, [fieldName]) }; - validator.ToggleMessage(results); + await validator.ToggleMessage(results); } } @@ -207,7 +207,7 @@ private void InternalSetError(MemberExpression exp, string errorMessage) /// /// 字段名,可以使用多层,如 a.b.c /// 错误描述信息,可为空,为空时查找资源文件 - public void SetError(string propertyName, string errorMessage) + public async Task SetError(string propertyName, string errorMessage) { if (TryGetModelField(propertyName, out var modelType, out var fieldName) && TryGetValidator(modelType, fieldName, out var validator)) { @@ -215,7 +215,7 @@ public void SetError(string propertyName, string errorMessage) { new(errorMessage, [fieldName]) }; - validator.ToggleMessage(results); + await validator.ToggleMessage(results); } } @@ -327,7 +327,7 @@ internal async Task ValidateObject(ValidationContext context, List _validateResults.Values.SelectMany(i => i).Any(i => i.MemberNames.Contains(name))); foreach (var (validator, messages) in _validateResults) { - validator.ToggleMessage(messages); + await validator.ToggleMessage(messages); } } } @@ -352,7 +352,7 @@ internal async Task ValidateFieldAsync(ValidationContext context, List Date: Thu, 29 May 2025 09:50:29 +0800 Subject: [PATCH 160/177] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20Trigge?= =?UTF-8?q?rOnChanged=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 6 ------ .../Components/Upload/UploadBase.cs | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 0f1e48dda8b..84d912fa6ff 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -119,12 +119,6 @@ protected override void OnParametersSet() AddIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadAddIcon); ValidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadValidStatusIcon); InvalidStatusIcon ??= IconTheme.GetIconByKey(ComponentIcons.AvatarUploadInvalidStatusIcon); - - // 头像上传时如果用户没有设置 OnChanged 回调,需要使用内置方法将文件头像转化未 Base64 格式用于预览 - OnChange ??= async item => - { - await item.RequestBase64ImageFileAsync(); - }; } /// diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 7871c9d6b7a..77c9cc61b05 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -179,10 +179,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) // trigger OnChange event callback // 回调给用户,用于存储文件并生成预览地址给 PreUrl - if (OnChange != null) - { - //await OnChange(item); - } + await TriggerOnChanged(item); item.Uploaded = true; StateHasChanged(); } @@ -211,6 +208,19 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) } } + /// + /// 触发 OnChanged 事件回调方法 + /// + /// + /// + protected virtual async Task TriggerOnChanged(UploadFile file) + { + if (OnChange != null) + { + await OnChange(file); + } + } + /// /// Delete file method. /// From f77b3e94e99e29db1bc52409fff322fc69ddf910 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 09:51:45 +0800 Subject: [PATCH 161/177] =?UTF-8?q?fix(SelectGeneric):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20body=20=E4=B8=A2=E5=A4=B1=E9=AB=98=E5=BA=A6?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SelectGeneric/SelectGeneric.razor | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor b/src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor index 8b30ab99f01..635e0a65d2d 100644 --- a/src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor +++ b/src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor @@ -41,7 +41,7 @@ } @if (IsVirtualize) { - /// - public override void ToggleMessage(IReadOnlyCollection results) + public override Task ToggleMessage(IReadOnlyCollection results) { _results = results; IsValid = results.Count == 0; + return Task.CompletedTask; } private string? AddId => $"{Id}_new"; diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 9719c8eb5a7..77c9cc61b05 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -134,7 +134,6 @@ protected override void OnParametersSet() { return base.FormatValueAsString(value); } - return Task.CompletedTask; } /// From bdcb57ea2b2f8440d63341584b828503a0b52afc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 12:03:08 +0800 Subject: [PATCH 163/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 2 +- .../Components/Samples/UploadAvatars.razor.cs | 4 ++-- src/BootstrapBlazor.Server/Locales/en-US.json | 6 +++++- src/BootstrapBlazor.Server/Locales/zh-CN.json | 6 +++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index 696abf997b9..c18a81a9598 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -67,7 +67,7 @@
      - +
      diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index ec25883b579..32cc4d8fba2 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -69,7 +69,7 @@ private async Task OnChange(UploadFile file) private Task OnAvatarValidSubmit(EditContext context) { - return Task.CompletedTask; + return ToastService.Error(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormValidContent"]); } /// @@ -125,6 +125,6 @@ class Person [Required] [FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 5 * 1024 * 1024)] - public IBrowserFile? Picture { get; set; } + public List? Picture { get; set; } } } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index e5c988aeddb..e33fbac72d3 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3476,7 +3476,11 @@ "UploadsWidth": "The width of the preview box", "UploadsHeight": "The height of the preview box", "UploadsIsCircle": "Whether it is circular avatar mode", - "UploadsBorderRadius": "Border radius" + "UploadsBorderRadius": "Border radius", + "UploadsValidateFormTitle": "ValidateForm", + "UploadsValidateFormValidContent": "Saved successfully", + "UploadsFormatError": "The file format is incorrect", + "UploadsAvatarMsg": "Avatar upload" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "InputUpload", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index c3522439233..32a45b2bafa 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3476,7 +3476,11 @@ "UploadsWidth": "预览框宽度", "UploadsHeight": "预览框高度", "UploadsIsCircle": "是否为圆形头像模式", - "UploadsBorderRadius": "预览框圆角曲率" + "UploadsBorderRadius": "预览框圆角曲率", + "UploadsValidateFormTitle": "表单应用", + "UploadsValidateFormValidContent": "数据合规,保存成功", + "UploadsFormatError": "文件格式不正确", + "UploadsAvatarMsg": "头像上传" }, "BootstrapBlazor.Server.Components.Samples.UploadInputs": { "UploadsTitle": "InputUpload 上传组件", From 5c1b47560a48e178e8499977f16354deb5d2965c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 12:03:27 +0800 Subject: [PATCH 164/177] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=AF=B9=20U?= =?UTF-8?q?pload=20=E7=BB=84=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index d274c8038c1..af3facc7658 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -513,6 +513,12 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext // 未选择文件 ValidateDataAnnotations(propertyValue, context, messages, pi); } + + if (messages.Count > 0) + { + _tcs = new TaskCompletionSource(); + _tcs.TrySetResult(false); + } } else { From f493b4991bc9145f424c69363fdb734abf537c11 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 12:03:57 +0800 Subject: [PATCH 165/177] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=A4=9A?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=A0=BC=E5=BC=8F=E6=A3=80=E6=9F=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor | 2 +- .../Components/Upload/AvatarUpload.razor.cs | 83 +++++++++---------- .../wwwroot/modules/validate.js | 39 ++++++--- 3 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor index f26406c9d78..f803d0d2739 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor @@ -14,7 +14,7 @@ } @foreach (var item in Files) { -
      +
      diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 2a70c41147f..1afae5e658a 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -79,10 +79,9 @@ public partial class AvatarUpload .AddClassFromAttributes(AdditionalAttributes) .Build(); - private string? GetItemClassString(UploadFile? item = null) => CssBuilder.Default("upload-item") + private string? GetItemClassString() => CssBuilder.Default("upload-item") .AddClass("is-circle", IsCircle) .AddClass("disabled", IsDisabled) - .AddClass(GetValidStatus(item)) .Build(); /// @@ -124,40 +123,18 @@ protected override void OnParametersSet() /// /// /// + /// /// - protected override async ValueTask ShowValidResult() + protected override async Task TriggerOnChanged(UploadFile file) { - ValidateModule ??= await LoadValidateModule(); - - var items = Files.Count == 0 && _results.Count > 0 - ? [new { Id = AddId, _results.First().ErrorMessage }] - : _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }); - await ValidateModule.InvokeVoidAsync("executeBatch", items); - - if (Files.Count > 0) - { - await ValidateModule.InvokeVoidAsync("dispose", AddId); - } - } - - /// - /// - /// - /// - protected override async ValueTask RemoveValidResult(string? validateId = null) - { - ValidateModule ??= await LoadValidateModule(); - - var items = new List(); - if (!string.IsNullOrEmpty(validateId)) + if (OnChange == null) { - items.Add(validateId); + await file.RequestBase64ImageFileAsync(); } else { - items.AddRange(Files.Select(f => f.ValidateId)); + await OnChange(file); } - await ValidateModule.InvokeVoidAsync("disposeBatch", items); } private IReadOnlyCollection _results = []; @@ -166,31 +143,45 @@ protected override async ValueTask RemoveValidResult(string? validateId = null) /// /// /// - public override Task ToggleMessage(IReadOnlyCollection results) + public override async Task ToggleMessage(IReadOnlyCollection results) { _results = results; IsValid = results.Count == 0; - return Task.CompletedTask; + + ValidateModule ??= await LoadValidateModule(); + + var invalidItems = IsInValiadOnAddItem + ? [new { Id = AddId, _results.First().ErrorMessage }] + : _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }); + + var items = IsInValiadOnAddItem + ? [AddId] + : Files.Select(i => i.ValidateId); + + var addId = IsInValiadOnAddItem ? null : AddId; + await ValidateModule.InvokeVoidAsync("executeBatch", items, invalidItems, addId); } - private string? AddId => $"{Id}_new"; + private bool IsInValiadOnAddItem => Files.Count == 0 && _results.Count > 0; - private string? GetValidStatus(UploadFile? item = null) - { - if (IsDisabled || ValidateForm == null) - { - return null; - } + /// + /// + /// + /// + protected override ValueTask ShowValidResult() => ValueTask.CompletedTask; - if (item == null && Files.Count > 0) + /// + /// + /// + /// + /// + protected override async ValueTask RemoveValidResult(string? validateId = null) + { + if (!string.IsNullOrEmpty(validateId)) { - // 如果没有文件则使用组件本身的 IsValid 状态 - return null; + await base.RemoveValidResult(validateId); } - - var state = item?.IsValid ?? IsValid; - return state.HasValue - ? state.Value ? "is-valid" : "is-invalid" - : null; } + + private string? AddId => $"{Id}_new"; } diff --git a/src/BootstrapBlazor/wwwroot/modules/validate.js b/src/BootstrapBlazor/wwwroot/modules/validate.js index 96a09825917..5fb9a657526 100644 --- a/src/BootstrapBlazor/wwwroot/modules/validate.js +++ b/src/BootstrapBlazor/wwwroot/modules/validate.js @@ -38,19 +38,32 @@ export function dispose(id) { } } -export function executeBatch(items) { - console.log("executeBatch", items); - - items.forEach(item => { - const { id, errorMessage } = item; - execute(id, errorMessage); - }) -} - -export function disposeBatch(items) { - console.log("disposeBatch", items); +export function executeBatch(items, invalidItems, addId) { + console.log("executeBatch", items, invalidItems); items.forEach(id => { - dispose(id); - }) + const el = document.getElementById(id); + if (el) { + const item = invalidItems.find(i => i.id === id); + if (item) { + const { id, errorMessage } = item; + execute(id, errorMessage); + el.classList.remove('is-valid'); + el.classList.add('is-invalid'); + } + else { + dispose(id); + el.classList.remove('is-invalid'); + el.classList.add('is-valid'); + } + } + }); + + if (addId) { + const el = document.getElementById(addId); + if (el) { + el.classList.remove('is-valid', 'is-invalid'); + dispose(addId); + } + } } From 8ea653543fff8d5004112fcf177a5213e911eb5b Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:03:24 +0800 Subject: [PATCH 166/177] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadAvatarTest.cs | 1 - test/UnitTest/Components/UploadButtonTest.cs | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index f5799cc04bd..46dc2ac58e6 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Components.Forms; using System.Runtime.CompilerServices; -using System.Threading.Tasks; namespace UnitTest.Components; diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 215c97acfab..63f84ae49aa 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -121,7 +121,7 @@ public void InputUpload_IsMultiple() } [Fact] - public void ButtonUpload_ValidateForm_Ok() + public async Task ButtonUpload_ValidateForm_Ok() { var foo = new Foo(); var cut = Context.RenderComponent(pb => @@ -150,7 +150,7 @@ public void ButtonUpload_ValidateForm_Ok() { new("test", ["bb_validate_123"]) }; - uploader.Instance.ToggleMessage(results); + await cut.InvokeAsync(() => uploader.Instance.ToggleMessage(results)); } [Fact] @@ -304,7 +304,6 @@ await cut.InvokeAsync(async () => [Fact] public async Task ButtonUpload_IsDirectory_Ok() { - var fileCount = 0; var fileNames = new List(); List fileList = []; var cut = Context.RenderComponent>(pb => @@ -312,7 +311,6 @@ public async Task ButtonUpload_IsDirectory_Ok() pb.Add(a => a.IsDirectory, true); pb.Add(a => a.OnChange, file => { - fileCount = file.FileCount; fileNames.Add(file.OriginFileName!); return Task.CompletedTask; }); @@ -328,7 +326,6 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha new(), new("UploadTestFile2") }))); - Assert.Equal(2, fileCount); Assert.Equal(2, fileNames.Count); Assert.Equal(2, fileList.Count); } From 1dcbe29b74df07eb29996d6d985f6714f4a5b279 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:03:55 +0800 Subject: [PATCH 167/177] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=86=85?= =?UTF-8?q?=E9=83=A8=E5=8F=98=E9=87=8F=20IsValid=20=E7=A7=81=E6=9C=89?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadFile.cs | 5 ----- .../Components/ValidateForm/ValidateForm.razor.cs | 3 --- 2 files changed, 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index 1649d9ed892..bafedb8428a 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -72,11 +72,6 @@ public class UploadFile ///
      internal string? ValidateId { get; set; } - /// - /// 获得/设置 当前上传文件是否合规 默认为 null 未检查 - /// - internal bool? IsValid { get; set; } - /// /// 获得 UploadFile 文件名 /// diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index af3facc7658..a0c915ce24d 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -503,9 +503,6 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext { // 优先检查 File 流,不需要检查 FileName ValidateDataAnnotations(file.File, context, messages, pi, file.ValidateId); - - // 如果 message 不为空表示验证失败 - file.IsValid = messages.Count == 0; }); } else From 76506096e776dfe8c4396755554a83582b5b13f0 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:04:23 +0800 Subject: [PATCH 168/177] =?UTF-8?q?refactor:=20=E5=BC=83=E7=94=A8=20FileCo?= =?UTF-8?q?unt=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 1 - src/BootstrapBlazor/Components/Upload/UploadFile.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index 77c9cc61b05..c3d3e604d68 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -164,7 +164,6 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) OriginFileName = f.Name, Size = f.Size, File = f, - FileCount = args.FileCount, Uploaded = false, UpdateCallback = Update }; diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index bafedb8428a..59172ac7a73 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -50,7 +50,9 @@ public class UploadFile /// /// 获得/设置 上传文件数量 /// - public int FileCount { get; init; } = 1; + [Obsolete("已弃用,删除即可;Deprecated, just delete")] + [ExcludeFromCodeCoverage] + public int FileCount { get; } = 1; /// /// 获得/设置 更新进度回调委托 From 0f6b20a6432f66952056d8d6a3b3a3261cf85e9c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:04:43 +0800 Subject: [PATCH 169/177] =?UTF-8?q?Revert=20"refactor:=20=E5=BC=83?= =?UTF-8?q?=E7=94=A8=20FileCount=20=E5=8F=82=E6=95=B0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 76506096e776dfe8c4396755554a83582b5b13f0. --- src/BootstrapBlazor/Components/Upload/UploadBase.cs | 1 + src/BootstrapBlazor/Components/Upload/UploadFile.cs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/UploadBase.cs b/src/BootstrapBlazor/Components/Upload/UploadBase.cs index c3d3e604d68..77c9cc61b05 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadBase.cs @@ -164,6 +164,7 @@ protected async Task OnFileChange(InputFileChangeEventArgs args) OriginFileName = f.Name, Size = f.Size, File = f, + FileCount = args.FileCount, Uploaded = false, UpdateCallback = Update }; diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index 59172ac7a73..bafedb8428a 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -50,9 +50,7 @@ public class UploadFile /// /// 获得/设置 上传文件数量 /// - [Obsolete("已弃用,删除即可;Deprecated, just delete")] - [ExcludeFromCodeCoverage] - public int FileCount { get; } = 1; + public int FileCount { get; init; } = 1; /// /// 获得/设置 更新进度回调委托 From 2d78e1a4e0d3093caabc9872bba788de8998cb4d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:05:05 +0800 Subject: [PATCH 170/177] =?UTF-8?q?refactor:=20=E4=BF=AE=E5=A4=8D=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=88=E8=A7=84=E6=A3=80=E6=9F=A5=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/ValidateForm/ValidateForm.razor.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index a0c915ce24d..7787dd1308d 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -511,11 +511,8 @@ private async Task ValidateAsync(IValidateComponent validator, ValidationContext ValidateDataAnnotations(propertyValue, context, messages, pi); } - if (messages.Count > 0) - { - _tcs = new TaskCompletionSource(); - _tcs.TrySetResult(false); - } + _tcs = new TaskCompletionSource(); + _tcs.TrySetResult(messages.Count == 0); } else { From cfa692ff45a7d807eb494611d6beb10f26dbed2d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 14:05:24 +0800 Subject: [PATCH 171/177] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=96=B9=E6=B3=95=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 29 ++++++++++++++++++- .../wwwroot/modules/validate.js | 13 +++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 1afae5e658a..b7c92687c21 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -159,7 +159,7 @@ public override async Task ToggleMessage(IReadOnlyCollection r : Files.Select(i => i.ValidateId); var addId = IsInValiadOnAddItem ? null : AddId; - await ValidateModule.InvokeVoidAsync("executeBatch", items, invalidItems, addId); + await ValidateModule.InvokeVoidAsync("executeUpload", items, invalidItems, addId); } private bool IsInValiadOnAddItem => Files.Count == 0 && _results.Count > 0; @@ -184,4 +184,31 @@ protected override async ValueTask RemoveValidResult(string? validateId = null) } private string? AddId => $"{Id}_new"; + + /// + /// + /// + /// + /// + protected override async ValueTask DisposeAsync(bool disposing) + { + if (disposing) + { + if (ValidateForm != null && FieldIdentifier.HasValue) + { + ValidateForm.TryRemoveValidator((FieldIdentifier.Value.FieldName, FieldIdentifier.Value.Model.GetType()), out _); + } + + if (ValidateModule != null) + { + var items = IsInValiadOnAddItem + ? [AddId] + : Files.Select(i => i.ValidateId); + + await ValidateModule.InvokeVoidAsync("disposeUpload", items); + } + } + + await base.DisposeAsync(false); + } } diff --git a/src/BootstrapBlazor/wwwroot/modules/validate.js b/src/BootstrapBlazor/wwwroot/modules/validate.js index 5fb9a657526..776a5e1a7e0 100644 --- a/src/BootstrapBlazor/wwwroot/modules/validate.js +++ b/src/BootstrapBlazor/wwwroot/modules/validate.js @@ -38,9 +38,7 @@ export function dispose(id) { } } -export function executeBatch(items, invalidItems, addId) { - console.log("executeBatch", items, invalidItems); - +export function executeUpload(items, invalidItems, addId) { items.forEach(id => { const el = document.getElementById(id); if (el) { @@ -67,3 +65,12 @@ export function executeBatch(items, invalidItems, addId) { } } } + +export function disposeUpload(items) { + items.forEach(id => { + const el = document.getElementById(id); + if (el) { + dispose(id); + } + }); +} From c16c4d99e05a0e458dcafc644158880c1847dc7a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 15:16:37 +0800 Subject: [PATCH 172/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=E8=A6=86=E7=9B=96=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 6 +- .../Components/Upload/UploadFile.cs | 2 +- test/UnitTest/Components/UploadAvatarTest.cs | 83 +++++++++++++++++++ test/UnitTest/Components/UploadButtonTest.cs | 3 + 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index b7c92687c21..d10cc17aede 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -152,11 +152,11 @@ public override async Task ToggleMessage(IReadOnlyCollection r var invalidItems = IsInValiadOnAddItem ? [new { Id = AddId, _results.First().ErrorMessage }] - : _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }); + : _results.Select(i => new { Id = i.MemberNames.FirstOrDefault(), i.ErrorMessage }).ToList(); var items = IsInValiadOnAddItem ? [AddId] - : Files.Select(i => i.ValidateId); + : Files.Select(i => i.ValidateId).ToList(); var addId = IsInValiadOnAddItem ? null : AddId; await ValidateModule.InvokeVoidAsync("executeUpload", items, invalidItems, addId); @@ -203,7 +203,7 @@ protected override async ValueTask DisposeAsync(bool disposing) { var items = IsInValiadOnAddItem ? [AddId] - : Files.Select(i => i.ValidateId); + : Files.Select(i => i.ValidateId).ToList(); await ValidateModule.InvokeVoidAsync("disposeUpload", items); } diff --git a/src/BootstrapBlazor/Components/Upload/UploadFile.cs b/src/BootstrapBlazor/Components/Upload/UploadFile.cs index bafedb8428a..8c985d92c83 100644 --- a/src/BootstrapBlazor/Components/Upload/UploadFile.cs +++ b/src/BootstrapBlazor/Components/Upload/UploadFile.cs @@ -48,7 +48,7 @@ public class UploadFile public IBrowserFile? File { get; set; } /// - /// 获得/设置 上传文件数量 + /// 获得/设置 上传文件总数量 /// public int FileCount { get; init; } = 1; diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 46dc2ac58e6..4fe935794ec 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -4,6 +4,7 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using Microsoft.AspNetCore.Components.Forms; +using System.ComponentModel.DataAnnotations; using System.Runtime.CompilerServices; namespace UnitTest.Components; @@ -144,6 +145,16 @@ await input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List< }); Assert.DoesNotContain("is-invalid", upload.Markup); + + upload.SetParametersAndRender(pb => + { + pb.Add(a => a.IsDisabled, false); + }); + // 清空所有文件 + var items = cut.FindAll(".upload-item-delete"); + Assert.Single(items); + await cut.InvokeAsync(() => items[0].Click()); + form.Submit(); } [Fact] @@ -181,6 +192,78 @@ public void IsImage_Ok() Assert.True(file.IsImage()); } + [Fact] + public async Task ValidateForm_ToggleMessage() + { + bool? invalid = null; + var foo = new Person(); + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.Model, foo); + pb.AddChildContent>>(pb => + { + pb.Add(a => a.IsMultiple, true); + pb.Add(a => a.OnChange, async file => + { + await Task.Delay(10); + }); + pb.Add(a => a.OnDelete, async file => + { + await Task.Delay(1); + return true; + }); + pb.Add(a => a.Value, foo.Picture); + pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, nameof(Person.Picture), typeof(List))); + }); + pb.Add(a => a.OnValidSubmit, context => + { + invalid = false; + return Task.CompletedTask; + }); + pb.Add(a => a.OnInvalidSubmit, context => + { + invalid = true; + return Task.CompletedTask; + }); + }); + + // 直接提交表单 + var form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.True(invalid); + + // 上传合规图片 + var input = cut.FindComponent(); + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test3.png"), + }))); + form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.False(invalid); + + // 上传不合规图片 + await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileChangeEventArgs(new List() + { + new("test3.text"), + }))); + form = cut.Find("form"); + await cut.InvokeAsync(() => form.Submit()); + Assert.True(invalid); + + // 删除不合规图片调用 RemoveValidResult 方法 + var items = cut.FindAll(".upload-item-delete"); + Assert.Equal(2, items.Count); + await cut.InvokeAsync(() => items[1].Click()); + } + + private class Person + { + [Required] + [FileValidation(Extensions = [".png", ".jpg", ".jpeg"])] + public List? Picture { get; set; } + } + private class MockBrowserFile(string name = "UploadTestFile", string contentType = "text") : IBrowserFile { public string Name { get; } = name; diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 63f84ae49aa..2df918ea63f 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -304,6 +304,7 @@ await cut.InvokeAsync(async () => [Fact] public async Task ButtonUpload_IsDirectory_Ok() { + var fileCount = 0; var fileNames = new List(); List fileList = []; var cut = Context.RenderComponent>(pb => @@ -311,6 +312,7 @@ public async Task ButtonUpload_IsDirectory_Ok() pb.Add(a => a.IsDirectory, true); pb.Add(a => a.OnChange, file => { + fileCount = file.FileCount; fileNames.Add(file.OriginFileName!); return Task.CompletedTask; }); @@ -326,6 +328,7 @@ await cut.InvokeAsync(() => input.Instance.OnChange.InvokeAsync(new InputFileCha new(), new("UploadTestFile2") }))); + Assert.Equal(2, fileCount); Assert.Equal(2, fileNames.Count); Assert.Equal(2, fileList.Count); } From 2eeac0cf27aa9388bda220ba0343e49487513459 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 15:17:00 +0800 Subject: [PATCH 173/177] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20AllowExten?= =?UTF-8?q?sions=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor.cs | 2 +- .../Components/Upload/AvatarUpload.razor.cs | 8 +++++++- .../Extensions/UploadFileExtensions.cs | 20 +++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index 32cc4d8fba2..bdef10c2e00 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -52,7 +52,7 @@ private async Task OnChange(UploadFile file) _token = new CancellationTokenSource(); } - await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, _token.Token); + await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, null, _token.Token); } else { diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index d10cc17aede..6c45f79c416 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -35,6 +35,12 @@ public partial class AvatarUpload [Parameter] public string? BorderRadius { get; set; } + /// + /// 获得/设置 图标文件扩展名集合 ".png" + /// + [Parameter] + public List? AllowExtensions { get; set; } + /// /// 获得/设置 删除图标 /// @@ -129,7 +135,7 @@ protected override async Task TriggerOnChanged(UploadFile file) { if (OnChange == null) { - await file.RequestBase64ImageFileAsync(); + await file.RequestBase64ImageFileAsync(allowExtensions: AllowExtensions); } else { diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index 657dc3f70de..9897efed35d 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -20,22 +20,26 @@ public static class UploadFileExtensions /// /// /// + /// /// [ExcludeFromCodeCoverage] - public static async Task RequestBase64ImageFileAsync(this UploadFile upload, string? format = null, int maxWidth = 320, int maxHeight = 240, long? maxAllowedSize = null, CancellationToken token = default) + public static async Task RequestBase64ImageFileAsync(this UploadFile upload, string? format = null, int maxWidth = 320, int maxHeight = 240, long? maxAllowedSize = null, List? allowExtensions = null, CancellationToken token = default) { if (upload.File != null) { try { - format ??= upload.File.ContentType; - var imageFile = await upload.File.RequestImageFileAsync(format, maxWidth, maxHeight); + format ??= upload.File.ContentType; + if (upload.IsImage(allowExtensions)) + { + var imageFile = await upload.File.RequestImageFileAsync(format, maxWidth, maxHeight); - maxAllowedSize ??= upload.File.Size; - using var fileStream = imageFile.OpenReadStream(maxAllowedSize.Value, token); - using var memoryStream = new MemoryStream(); - await fileStream.CopyToAsync(memoryStream, token); - upload.PrevUrl = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}"; + maxAllowedSize ??= upload.File.Size; + using var fileStream = imageFile.OpenReadStream(maxAllowedSize.Value, token); + using var memoryStream = new MemoryStream(); + await fileStream.CopyToAsync(memoryStream, token); + upload.PrevUrl = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}"; + } upload.Uploaded = true; } catch (Exception ex) From 3400a5db80bffcf585317e718a8a8730a7d32845 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 15:57:11 +0800 Subject: [PATCH 174/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadAvatarTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 4fe935794ec..6afe95d8472 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -108,6 +108,7 @@ public async Task AvatarUpload_ValidateForm_Ok() pb.Add(a => a.Accept, "Image"); pb.Add(a => a.Value, foo.Name); pb.Add(a => a.ValueExpression, foo.GenerateValueExpression()); + pb.Add(a => a.AllowExtensions, [".jpg"]); }); pb.Add(a => a.OnValidSubmit, context => { From 478ad073eaf81fc9c0b6888d9a7e577aed570cbb Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 29 May 2025 15:59:14 +0800 Subject: [PATCH 175/177] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadButtonTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/UnitTest/Components/UploadButtonTest.cs b/test/UnitTest/Components/UploadButtonTest.cs index 2df918ea63f..73394a539d8 100644 --- a/test/UnitTest/Components/UploadButtonTest.cs +++ b/test/UnitTest/Components/UploadButtonTest.cs @@ -261,7 +261,7 @@ public async Task ButtonUpload_OnDeleteFile_Ok() { pb.Add(a => a.DefaultFileList, [ - new() { FileName = "Test-File2", Code = 1001 } + new() { FileName = "Test-File2", Code = 1001, Error = "Error" } ]); }); await cut.InvokeAsync(() => cut.Find(".delete-icon").Click()); From 65b744d9cbb714222446e95c637facd76278ce64 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 10:17:14 +0800 Subject: [PATCH 176/177] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadDrops.razor.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs index 800b30870e9..f74d75b4fba 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadDrops.razor.cs @@ -20,7 +20,12 @@ public partial class UploadDrops private Task OnDropUpload(UploadFile file) { // 模拟保存文件等处理 - return Task.Delay(1000); + if (file.File is { Size: > 5 * 1024 * 1024 }) + { + file.Code = 1004; + ToastService.Information("Error", Localizer["DropUploadFooterText"]); + } + return Task.CompletedTask; } private List GetAttributes() => From 9d18b75ee7e95aef0a3a85727e62ae7d74514614 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 10:19:47 +0800 Subject: [PATCH 177/177] chore: bump version 9.7.1-beta04 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 3496eb35f13..8b68a932561 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 9.7.1-beta03 + 9.7.1-beta04