mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-30 02:58:37 +08:00
!2682 feat(#I5338U): add GroupName on IEditItem interface
* chore: bump version 6.5.9-beta01 * Merge branch 'main' into Group * test: 增加 EditorForm 单元测试 * test: 增加 LookupStringComparison 单元测试 * style: 增加样式兼容 row 排前面情况 * revert: 撤销分组排序代码 * feat: 增加分组排序渲染逻辑 * test: 增加 Group 单元测试 * refactor: 格式化代码 * feat: 增加 GroupName 与 GroupOrder * feat: 增加 CategoryOrder 参数 * Update BootstrapBlazor.sln * 移除分组测试工程 * refactor: 更改 GroupBox 内部使用 row * doc: 移除背景色 * refactor: 更改 Group 为 Category * Merge branch 'main' into Group * SearchDialog 高级搜索 * 测试 ValidateForm 表单组件 * Table 的 ColumnAttribute 添加属性分组 Group 特性 https://gitee.com/LongbowEnter…
This commit is contained in:
parent
6b1b7aad27
commit
2720c8746e
@ -215,4 +215,14 @@ public class AutoGenerateColumnAttribute : AutoGenerateBaseAttribute, ITableColu
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetFieldName() => FieldName;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组
|
||||
/// </summary>
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组排序 默认 0
|
||||
/// </summary>
|
||||
public int GroupOrder { get; set; }
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>6.5.8</Version>
|
||||
<Version>6.5.9-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
|
||||
|
@ -15,24 +15,52 @@
|
||||
else
|
||||
{
|
||||
<div class="form-body">
|
||||
<div class="@FormClassString">
|
||||
<CascadingValue Value="this" Name="EidtorForm">
|
||||
@foreach (var item in FormItems)
|
||||
<CascadingValue Value="this" Name="EidtorForm">
|
||||
@foreach (var g in FormItems.GroupBy(i => i.GroupOrder).OrderBy(i => i.Key).Select(i => new { i.First().GroupName, Items = i.OrderBy(x => x.Order) }))
|
||||
{
|
||||
if (string.IsNullOrEmpty(g.GroupName))
|
||||
{
|
||||
var render = GetRenderTemplate(item);
|
||||
@if (render != null)
|
||||
{
|
||||
@render(Model)
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="@GetCssString(item)">
|
||||
@AutoGenerateTemplate(item)
|
||||
</div>
|
||||
}
|
||||
<div class="@FormClassString">
|
||||
@foreach (var item in g.Items)
|
||||
{
|
||||
var render = GetRenderTemplate(item);
|
||||
@if (render != null)
|
||||
{
|
||||
@render(Model)
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="@GetCssString(item)">
|
||||
@AutoGenerateTemplate(item)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</CascadingValue>
|
||||
</div>
|
||||
else
|
||||
{
|
||||
<GroupBox Title="@g.GroupName">
|
||||
<div class="@FormClassString">
|
||||
@foreach (var item in g.Items)
|
||||
{
|
||||
|
||||
var render = GetRenderTemplate(item);
|
||||
@if (render != null)
|
||||
{
|
||||
@render(Model)
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="@GetCssString(item)">
|
||||
@AutoGenerateTemplate(item)
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</GroupBox>
|
||||
}
|
||||
}
|
||||
</CascadingValue>
|
||||
</div>
|
||||
@if (Buttons != null)
|
||||
{
|
||||
|
@ -134,12 +134,12 @@ public sealed partial class EditorForm<TModel> : IShowLabel
|
||||
/// <summary>
|
||||
/// 获得/设置 配置编辑项目集合
|
||||
/// </summary>
|
||||
private List<IEditorItem> EditorItems { get; } = new List<IEditorItem>();
|
||||
private List<IEditorItem> EditorItems { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 渲染的编辑项集合
|
||||
/// </summary>
|
||||
private List<IEditorItem> FormItems { get; } = new List<IEditorItem>();
|
||||
private List<IEditorItem> FormItems { get; } = new();
|
||||
|
||||
[NotNull]
|
||||
private string? PlaceHolderText { get; set; }
|
||||
|
@ -180,6 +180,18 @@ public class EditorItem<TValue> : ComponentBase, IEditorItem
|
||||
[CascadingParameter]
|
||||
private List<IEditorItem>? EditorItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组排序 默认 0
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int GroupOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
|
@ -116,4 +116,19 @@ public interface IEditorItem
|
||||
/// 获取绑定字段信息方法
|
||||
/// </summary>
|
||||
string GetFieldName();
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 顺序号
|
||||
/// </summary>
|
||||
int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组
|
||||
/// </summary>
|
||||
string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组排序 默认 0
|
||||
/// </summary>
|
||||
int GroupOrder { get; set; }
|
||||
}
|
||||
|
@ -13,3 +13,12 @@
|
||||
background-color: #fff;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.form-body > .groupbox:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.form-body > .row + .groupbox {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
@ -116,11 +116,6 @@ public interface ITableColumn : IEditorItem
|
||||
/// </summary>
|
||||
bool ShowTips { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 顺序号
|
||||
/// </summary>
|
||||
int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 单元格回调方法
|
||||
/// </summary>
|
||||
|
@ -141,6 +141,16 @@ internal class InternalTableColumn : ITableColumn
|
||||
/// </summary>
|
||||
public List<IValidator>? ValidateRules { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组
|
||||
/// </summary>
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组排序 默认 0
|
||||
/// </summary>
|
||||
public int GroupOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@ -286,5 +296,7 @@ internal class InternalTableColumn : ITableColumn
|
||||
if (source.Width != null) dest.Width = source.Width;
|
||||
if (source.ValidateRules != null) dest.ValidateRules = source.ValidateRules;
|
||||
if (source.ShowLabelTooltip != null) dest.ShowLabelTooltip = source.ShowLabelTooltip;
|
||||
if (!string.IsNullOrEmpty(source.GroupName)) dest.GroupName = source.GroupName;
|
||||
if (source.GroupOrder != 0) dest.GroupOrder = source.GroupOrder;
|
||||
}
|
||||
}
|
||||
|
@ -397,6 +397,17 @@ public class TableColumn<TItem, TType> : BootstrapComponentBase, ITableColumn
|
||||
[Parameter]
|
||||
public string? FieldName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组 默认 null
|
||||
/// </summary>
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前属性分组排序 默认 0
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int GroupOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定字段信息方法
|
||||
/// </summary>
|
||||
|
File diff suppressed because one or more lines are too long
@ -344,6 +344,7 @@ public class EditorFormTest : BootstrapBlazorTestBase
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Name), typeof(string)));
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Text), "Test-Text");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.LookUpServiceKey), "FooLookup");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.LookupStringComparison), StringComparison.OrdinalIgnoreCase);
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
@ -353,6 +354,47 @@ public class EditorFormTest : BootstrapBlazorTestBase
|
||||
Assert.Equal(lookup!.Count(), select.Instance.Items.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GroupName_Order_Ok()
|
||||
{
|
||||
var foo = new Foo();
|
||||
var cut = Context.RenderComponent<EditorForm<Foo>>(pb =>
|
||||
{
|
||||
pb.AddCascadingValue("IsSearch", true);
|
||||
pb.Add(a => a.Model, foo);
|
||||
pb.Add(a => a.AutoGenerateAllItem, false);
|
||||
pb.Add(a => a.FieldItems, f => builder =>
|
||||
{
|
||||
var index = 0;
|
||||
builder.OpenComponent<EditorItem<Foo, string>>(index++);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Field), f.Name);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Name), typeof(string)));
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Text), "Test-Text");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Order), 1);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.GroupName), "Test-Group-1");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.GroupOrder), 1);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.EditTemplate), new RenderFragment<Foo>(foo => builder => builder.AddContent(0, "Test")));
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<EditorItem<Foo, string>>(index++);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Field), f.Address);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Address), typeof(string)));
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Text), "Test-Address");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.Order), 1);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.GroupName), "Test-Group-2");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, string>.GroupOrder), 2);
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<EditorItem<Foo, bool>>(index++);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, bool>.Field), f.Complete);
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, bool>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Complete), typeof(bool)));
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, bool>.Text), "Test-Complete");
|
||||
builder.AddAttribute(index++, nameof(EditorItem<Foo, bool>.Order), 1);
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static RenderFragment<Foo> GenerateEditorItems(Foo foo) => f => builder =>
|
||||
{
|
||||
builder.OpenComponent<EditorItem<Foo, string>>(0);
|
||||
|
@ -106,4 +106,8 @@ internal class MockTableColumn : ITableColumn
|
||||
public string GetDisplayName() => Text ?? FieldName;
|
||||
|
||||
public string GetFieldName() => FieldName;
|
||||
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
public int GroupOrder { get; set; }
|
||||
}
|
||||
|
39
test/UnitTest/Utils/GroupTest.cs
Normal file
39
test/UnitTest/Utils/GroupTest.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace UnitTest.Utils;
|
||||
|
||||
public class GroupTest
|
||||
{
|
||||
ITestOutputHelper Logger { get; set; }
|
||||
|
||||
public GroupTest(ITestOutputHelper logger) => Logger = logger;
|
||||
|
||||
[Fact]
|
||||
public void Group_Order_Ok()
|
||||
{
|
||||
var results = new List<string>();
|
||||
|
||||
var items = new List<MockTableColumn>(50)
|
||||
{
|
||||
new MockTableColumn("Test1", typeof(string)) { GroupName = "Test1", GroupOrder = 2, Order = 2 },
|
||||
new MockTableColumn("Test2", typeof(string)) { GroupName = "Test1", GroupOrder = 2, Order = 1 },
|
||||
new MockTableColumn("Test3", typeof(string)) { GroupName = "Test2", GroupOrder = 1, Order = 2 },
|
||||
new MockTableColumn("Test4", typeof(string)) { GroupName = "Test2", GroupOrder = 1, Order = 1 }
|
||||
};
|
||||
var groups = items.GroupBy(i => i.GroupOrder).OrderBy(i => i.Key).Select(i => new { i.Key, Items = i.OrderBy(x => x.Order) });
|
||||
foreach (var g in groups)
|
||||
{
|
||||
foreach (var item in g.Items)
|
||||
{
|
||||
results.Add(item.FieldName);
|
||||
Logger.WriteLine($"{item.FieldName} - {item.GroupName} - {item.GroupOrder}");
|
||||
}
|
||||
}
|
||||
|
||||
var expected = string.Join(",", new List<string>() { "Test4", "Test3", "Test2", "Test1" });
|
||||
var actual = string.Join(",", results);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user