Skip to content

Commit

Permalink
feat(Select): add LookupService parameter (#4898)
Browse files Browse the repository at this point in the history
* refactor: 增加 LookupService 扩展方法

* refactor: 增加 LookupService 参数

* feat: 增加扩展方法

* feat: 支持 LookupService 服务

* test: 提高代码覆盖率

* refactor: 增加 LookupService 支持

* feat: 增加 Select 组件对 LookupService 自动赋值逻辑
  • Loading branch information
ArgoZhang authored Dec 20, 2024
1 parent c4901f2 commit efb2508
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 55 deletions.
9 changes: 3 additions & 6 deletions src/BootstrapBlazor/Components/EditorForm/EditorForm.razor
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,9 @@
</div>
}

@if (!_inited)
{
<div class="ef-loading">
<Spinner Color="Color.Primary" />
</div>
}
<div class="ef-loading">
<Spinner Color="Color.Primary" />
</div>
</div>

@code
Expand Down
26 changes: 1 addition & 25 deletions src/BootstrapBlazor/Components/EditorForm/EditorForm.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ public partial class EditorForm<TModel> : IShowLabel
.GroupBy(i => i.GroupOrder).OrderBy(i => i.Key)
.Select(i => new KeyValuePair<string, IOrderedEnumerable<IEditorItem>>(i.First().GroupName!, i.OrderBy(x => x.Order)));

private bool _inited;
private List<IEditorItem>? _itemsCache;

private List<IEditorItem> RenderItems
Expand Down Expand Up @@ -238,29 +237,6 @@ protected override void OnParametersSet()
_itemsCache = null;
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);

if (firstRender)
{
foreach (var item in RenderItems)
{
if (item.Lookup == null && !string.IsNullOrEmpty(item.LookupServiceKey))
{
var lookupServcie = item.LookupService ?? LookupService;
item.Lookup = await lookupServcie.GetItemsAsync(item.LookupServiceKey, item.LookupServiceData);
}
}
_inited = true;
StateHasChanged();
}
}

private List<IEditorItem> GetRenderItems()
{
var items = new List<IEditorItem>();
Expand Down Expand Up @@ -315,7 +291,7 @@ private RenderFragment AutoGenerateTemplate(IEditorItem item) => builder =>
else
{
item.PlaceHolder ??= PlaceHolderText;
builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value);
builder.CreateComponentByFieldType(this, item, Model, ItemChangedType, IsSearch.Value, item.GetLookupService(LookupService));
}
};

Expand Down
26 changes: 24 additions & 2 deletions src/BootstrapBlazor/Components/Select/Select.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,10 @@ private SelectedItem? SelectedRow
private List<SelectedItem> GetRowsByItems()
{
var items = new List<SelectedItem>();
items.AddRange(Items);
if (Items != null)
{
items.AddRange(Items);
}
items.AddRange(_children);
return items;
}
Expand All @@ -306,11 +309,20 @@ protected override void OnParametersSet()
{
base.OnParametersSet();

Items ??= [];
PlaceHolder ??= Localizer[nameof(PlaceHolder)];
NoSearchDataText ??= Localizer[nameof(NoSearchDataText)];
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectDropdownIcon);
ClearIcon ??= IconTheme.GetIconByKey(ComponentIcons.SelectClearIcon);
}

/// <summary>
/// <inheritdoc/>
/// </summary>
protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();

Items ??= await GetItemsAsync();

// 内置对枚举类型的支持
if (!Items.Any() && ValueType.IsEnum())
Expand Down Expand Up @@ -338,6 +350,16 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
}
}

private async Task<IEnumerable<SelectedItem>> GetItemsAsync()
{
IEnumerable<SelectedItem>? items = null;
if (LookupService != null)
{
items = await LookupService.GetItemsByKeyAsync(LookupServiceKey, LookupServiceData);
}
return items ?? [];
}

/// <summary>
/// 获得/设置 数据总条目
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions src/BootstrapBlazor/Components/Select/SelectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
[Parameter]
public RenderFragment<string>? GroupItemTemplate { get; set; }

/// <summary>
/// 获得/设置 <see cref="ILookupService"/> 服务实例
/// </summary>
[Parameter]
public ILookupService? LookupService { get; set; }

/// <summary>
/// 获得/设置 <see cref="ILookupService"/> 服务获取 Lookup 数据集合键值 常用于外键自动转换为名称操作,可以通过 <see cref="LookupServiceData"/> 传递自定义数据
/// </summary>
[Parameter]
public string? LookupServiceKey { get; set; }

/// <summary>
/// 获得/设置 <see cref="ILookupService"/> 服务获取 Lookup 数据集合键值自定义数据,通过 <see cref="LookupServiceKey"/> 指定键值
/// </summary>
[Parameter]
public object? LookupServiceData { get; set; }

/// <summary>
/// 获得/设置 IIconTheme 服务实例
/// </summary>
Expand Down
10 changes: 2 additions & 8 deletions src/BootstrapBlazor/Components/Table/Table.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,12 +1141,6 @@ private async Task ProcessFirstRender()
Columns.Clear();
Columns.AddRange(cols.OrderFunc());

// 准备 Lookup 数据
foreach (var column in Columns)
{
column.Lookup ??= await LookupService.GetItemsAsync(column.LookupServiceKey, column.LookupServiceData);
}

// 查看是否开启列宽序列化
_clientColumnWidths = await ReloadColumnWidthFromBrowserAsync();
ResetColumnWidth();
Expand Down Expand Up @@ -1329,7 +1323,7 @@ RenderFragment RenderTemplate() => col.Template == null
: col.Template(item);

RenderFragment RenderEditTemplate() => col.EditTemplate == null
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false))
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, false, col.GetLookupService(LookupService)))
: col.EditTemplate(item);
}

Expand Down Expand Up @@ -1371,7 +1365,7 @@ void SetDynamicEditTemplate()
parameters.Add(new(nameof(ValidateBase<string>.OnValueChanged), onValueChanged.Invoke(d, col, (model, column, val) => DynamicContext.OnValueChanged(model, column, val))));
col.ComponentParameters = parameters;
}
builder.CreateComponentByFieldType(this, col, row, changedType, false);
builder.CreateComponentByFieldType(this, col, row, changedType, false, col.GetLookupService(LookupService));
};
}

Expand Down
15 changes: 15 additions & 0 deletions src/BootstrapBlazor/Extensions/IEditorItemExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ namespace BootstrapBlazor.Components;
/// </summary>
public static class IEditorItemExtensions
{
/// <summary>
/// 判断当前 IEditorItem 实例是否为 Lookup 类型
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static bool IsLookup(this IEditorItem item) => item.Lookup != null || item.LookupService != null || !string.IsNullOrEmpty(item.LookupServiceKey);

/// <summary>
/// 判断当前 IEditorItem 实例是否可以编辑
/// </summary>
Expand Down Expand Up @@ -110,4 +117,12 @@ bool ComplexCanWrite()
internal static bool GetIgnore(this IEditorItem col) => col.Ignore ?? false;

internal static bool GetReadonly(this IEditorItem col) => col.Readonly ?? false;

/// <summary>
/// 获得 ILookupService 实例
/// </summary>
/// <param name="item"></param>
/// <param name="service"></param>
/// <returns></returns>
public static ILookupService GetLookupService(this IEditorItem item, ILookupService service) => item.LookupService ?? service;
}
28 changes: 14 additions & 14 deletions src/BootstrapBlazor/Utils/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi
/// <param name="item"></param>
/// <param name="changedType"></param>
/// <param name="isSearch"></param>
public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false)
/// <param name="lookupService"></param>
public static void CreateComponentByFieldType(this RenderTreeBuilder builder, ComponentBase component, IEditorItem item, object model, ItemChangedType changedType = ItemChangedType.Update, bool isSearch = false, ILookupService? lookupService = null)
{
var fieldType = item.PropertyType;
var fieldName = item.GetFieldName();
Expand All @@ -468,8 +469,7 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co
var fieldValue = GenerateValue(model, fieldName);
var fieldValueChanged = GenerateValueChanged(component, model, fieldName, fieldType);
var valueExpression = GenerateValueExpression(model, fieldName, fieldType);
var lookup = item.Lookup;
var componentType = item.ComponentType ?? GenerateComponentType(fieldType, item.Rows != 0, lookup);
var componentType = item.ComponentType ?? GenerateComponentType(item);
builder.OpenComponent(0, componentType);
if (componentType.IsSubclassOf(typeof(ValidateBase<>).MakeGenericType(fieldType)))
{
Expand Down Expand Up @@ -513,20 +513,22 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co
}

// Nullable<bool?>
if (item.ComponentType == typeof(Select<bool?>) && fieldType == typeof(bool?) && lookup == null && item.Items == null)
if (item.ComponentType == typeof(Select<bool?>) && fieldType == typeof(bool?) && !item.IsLookup() && item.Items == null)
{
builder.AddAttribute(100, nameof(Select<bool?>.Items), GetNullableBoolItems(model, fieldName));
}

// Lookup
if (lookup != null && item.Items == null)
if (item.IsLookup() && item.Items == null)
{
builder.AddAttribute(110, nameof(Select<SelectedItem>.ShowSearch), item.ShowSearchWhenSelect);
builder.AddAttribute(120, nameof(Select<SelectedItem>.Items), lookup.Clone());
builder.AddAttribute(120, nameof(Select<SelectedItem>.LookupService), lookupService);
builder.AddAttribute(121, nameof(Select<SelectedItem>.LookupServiceKey), item.LookupServiceKey);
builder.AddAttribute(122, nameof(Select<SelectedItem>.LookupServiceData), item.LookupServiceData);
builder.AddAttribute(130, nameof(Select<SelectedItem>.StringComparison), item.LookupStringComparison);
}

// 增加非枚举类,手动设定 ComponentType 为 Select 并且 Data 有值 自动生成下拉框
// 增加非枚举类,手动设定 ComponentType 为 Select 并且 Items 有值 自动生成下拉框
if (item.Items != null && item.ComponentType == typeof(Select<>).MakeGenericType(fieldType))
{
builder.AddAttribute(140, nameof(Select<SelectedItem>.Items), item.Items.Clone());
Expand Down Expand Up @@ -615,15 +617,13 @@ object ComplexPropertyValueExpression()
/// <summary>
/// 通过指定类型生成组件类型
/// </summary>
/// <param name="fieldType"></param>
/// <param name="hasRows">是否为 TextArea 组件</param>
/// <param name="lookup"></param>
/// <returns></returns>
private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumerable<SelectedItem>? lookup)
/// <param name="item"></param>
private static Type GenerateComponentType(IEditorItem item)
{
var fieldType = item.PropertyType;
Type? ret = null;
var type = (Nullable.GetUnderlyingType(fieldType) ?? fieldType);
if (type.IsEnum || lookup != null)
if (type.IsEnum || item.IsLookup())
{
ret = typeof(Select<>).MakeGenericType(fieldType);
}
Expand All @@ -649,7 +649,7 @@ private static Type GenerateComponentType(Type fieldType, bool hasRows, IEnumera
}
else if (fieldType == typeof(string))
{
ret = hasRows ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string));
ret = item.Rows > 0 ? typeof(Textarea) : typeof(BootstrapInput<>).MakeGenericType(typeof(string));
}
return ret ?? typeof(BootstrapInput<>).MakeGenericType(fieldType);
}
Expand Down
3 changes: 3 additions & 0 deletions test/UnitTest/Components/EditorFormTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ public async Task LookupServiceKey_Ok()
var lookup = await lookupService.GetItemsAsync("FooLookup", "");
Assert.NotNull(lookup);
Assert.Equal(lookup.Count(), select.Instance.Items.Count());

lookup = await lookupService.GetItemsAsync(null, "");
Assert.Null(lookup);
}

[Fact]
Expand Down

0 comments on commit efb2508

Please sign in to comment.