refactor: 字典表功能完善
This commit is contained in:
parent
0ef303540e
commit
60b0f2225d
|
@ -22,11 +22,6 @@ namespace Bootstrap.Admin.Components
|
|||
[CascadingParameter(Name = "Default")]
|
||||
public DefaultLayout RootLayout { get; protected set; } = new DefaultLayout();
|
||||
|
||||
/// <summary>
|
||||
/// Toast 组件实例
|
||||
/// </summary>
|
||||
protected Toast Toast { get; set; } = new Toast();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -44,21 +39,11 @@ namespace Bootstrap.Admin.Components
|
|||
/// <returns></returns>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender) RootLayout.JSRuntime.EnableAnimation();
|
||||
|
||||
var requestUrl = RootLayout.NavigationManager?.Uri ?? "";
|
||||
var path = new Uri(requestUrl).PathAndQuery;
|
||||
var menus = DataAccess.MenuHelper.RetrieveAllMenus(RootLayout.UserName);
|
||||
var menu = menus.FirstOrDefault(menu => path.Contains(menu.Url.ToBlazorMenuUrl()));
|
||||
if (menu != null) TabSet?.AddTab(menu);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="cate"></param>
|
||||
public void ShowMessage(string title, string text, ToastCategory cate = ToastCategory.Success) => Toast.ShowMessage(title, text, cate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,16 +28,12 @@ namespace Bootstrap.Admin.Components
|
|||
{
|
||||
if (CurrentEditContext == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " +
|
||||
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} " +
|
||||
$"inside an EditForm.");
|
||||
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} inside an EditForm.");
|
||||
}
|
||||
|
||||
if (EditForm == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " +
|
||||
$"parameter of type {nameof(LgbEditFormBase)}. For example, you can use {nameof(BootstrapAdminDataAnnotationsValidator)} " +
|
||||
$"inside an EditForm.");
|
||||
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading parameter of type {nameof(LgbEditFormBase)}. For example, you can use {nameof(BootstrapAdminDataAnnotationsValidator)} inside an EditForm.");
|
||||
}
|
||||
|
||||
CurrentEditContext.AddBootstrapAdminDataAnnotationsValidation(EditForm);
|
||||
|
|
|
@ -9,11 +9,6 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
public class BootstrapComponentBase : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[CascadingParameter(Name = "Admin")]
|
||||
protected AdminLayout Layout { get; set; } = new AdminLayout();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -26,13 +21,10 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
[Inject]
|
||||
protected IJSRuntime? JSRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="cate"></param>
|
||||
protected void ShowMessage(string title, string text, ToastCategory cate = ToastCategory.Success) => Layout.ShowMessage(title, text, cate);
|
||||
[CascadingParameter(Name = "Admin")]
|
||||
protected AdminLayout Layout { get; set; } = new AdminLayout();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,16 +39,6 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
public NavigatorBarModel Model { get; set; } = new NavigatorBarModel("");
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SideBar? SideBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Header? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -95,23 +85,22 @@ namespace Bootstrap.Admin.Components
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置参数方法
|
||||
/// </summary>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
RequestUrl = new UriBuilder(NavigationManager?.Uri ?? "").Path;
|
||||
Model = new NavigatorBarModel(UserName, RequestUrl.ToMvcMenuUrl());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (!firstRender) ResetSideBar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新侧边栏方法
|
||||
/// </summary>
|
||||
public void ResetSideBar()
|
||||
{
|
||||
RequestUrl = new UriBuilder(NavigationManager?.Uri ?? "").Path;
|
||||
Model = new NavigatorBarModel(UserName, RequestUrl.ToMvcMenuUrl());
|
||||
SideBar?.Update(Model);
|
||||
if (firstRender) JSRuntime.InitDocument();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,5 +59,11 @@ namespace Bootstrap.Admin.Components
|
|||
///
|
||||
/// </summary>
|
||||
protected bool Delete(IEnumerable<BootstrapDict> items) => DataAccess.DictHelper.Delete(items.Select(item => item.Id ?? ""));
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override bool ShouldRender() => false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Bootstrap.Admin.Components
|
|||
/// <summary>
|
||||
/// 可编辑页面组件包含查询与数据表格
|
||||
/// </summary>
|
||||
public class EditPageBase<TItem> : BootstrapComponentBase
|
||||
public class EditPageBase<TItem> : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -12,6 +12,12 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
public class LgbEditFormBase : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Id { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a collection of additional attributes that will be applied to the created <c>form</c> element.
|
||||
/// </summary>
|
||||
|
@ -54,14 +60,14 @@ namespace Bootstrap.Admin.Components
|
|||
/// <summary>
|
||||
/// 验证组件缓存 静态全局提高性能
|
||||
/// </summary>
|
||||
private static ConcurrentDictionary<(Type ModelType, string FieldName), IValidateComponent> _validatorCache = new ConcurrentDictionary<(Type, string), IValidateComponent>();
|
||||
private static ConcurrentDictionary<(LgbEditFormBase EditForm, Type ModelType, string FieldName), IValidateComponent> _validatorCache = new ConcurrentDictionary<(LgbEditFormBase, Type, string), IValidateComponent>();
|
||||
|
||||
/// <summary>
|
||||
/// 添加数据验证组件到 EditForm 中
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="comp"></param>
|
||||
public void AddValidator((Type ModelType, string FieldName) key, IValidateComponent comp) => _validatorCache.AddOrUpdate(key, k => comp, (k, c) => c = comp);
|
||||
public void AddValidator((LgbEditFormBase EditForm, Type ModelType, string FieldName) key, IValidateComponent comp) => _validatorCache.AddOrUpdate(key, k => comp, (k, c) => c = comp);
|
||||
|
||||
/// <summary>
|
||||
/// EditModel 数据模型验证方法
|
||||
|
@ -74,7 +80,7 @@ namespace Bootstrap.Admin.Components
|
|||
// 遍历所有可验证组件进行数据验证
|
||||
foreach (var key in _validatorCache)
|
||||
{
|
||||
if (key.Key.ModelType == context.ObjectType)
|
||||
if (key.Key.EditForm == this && key.Key.ModelType == context.ObjectType)
|
||||
{
|
||||
if (BootstrapAdminEditContextDataAnnotationsExtensions.TryGetValidatableProperty(new FieldIdentifier(model, key.Key.FieldName), out var propertyInfo))
|
||||
{
|
||||
|
@ -100,20 +106,11 @@ namespace Bootstrap.Admin.Components
|
|||
/// <param name="results"></param>
|
||||
public void ValidateProperty(object? propertyValue, ValidationContext context, List<ValidationResult> results)
|
||||
{
|
||||
if (_validatorCache.TryGetValue((context.ObjectType, context.MemberName), out var validator))
|
||||
if (_validatorCache.TryGetValue((this, context.ObjectType, context.MemberName), out var validator))
|
||||
{
|
||||
validator.ValidateProperty(propertyValue, context, results);
|
||||
validator.ToggleMessage(results, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
base.OnAfterRender(firstRender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
using Bootstrap.Admin.Extensions;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bootstrap.Admin.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// LgbInputText 组件
|
||||
/// </summary>
|
||||
public class LgbInputText : InputText, IValidateComponent
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Inject]
|
||||
protected IJSRuntime? JSRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public LgbEditFormBase? EditForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Id { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string ErrorMessage { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string ValidCss { get; set; } = "";
|
||||
|
||||
private string _tooltipMethod = "";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="propertyValue"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="results"></param>
|
||||
public void ValidateProperty(object? propertyValue, ValidationContext context, List<ValidationResult> results)
|
||||
{
|
||||
Rules.ToList().ForEach(validator => validator.Validate(propertyValue, context, results));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示/隐藏验证结果方法
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <param name="validProperty">是否对本属性进行数据验证</param>
|
||||
public void ToggleMessage(IEnumerable<ValidationResult> results, bool validProperty)
|
||||
{
|
||||
if (results.Where(r => r.MemberNames.Any(m => m == FieldIdentifier.FieldName)).Any())
|
||||
{
|
||||
ErrorMessage = results.First().ErrorMessage;
|
||||
ValidCss = "is-invalid";
|
||||
|
||||
// 控件自身数据验证时显示 tooltip
|
||||
// EditForm 数据验证时调用 tooltip('enable') 保证 tooltip 组件生成
|
||||
// 调用 tooltip('hide') 后导致鼠标悬停时 tooltip 无法正常显示
|
||||
_tooltipMethod = validProperty ? "show" : "enable";
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "";
|
||||
ValidCss = "is-valid";
|
||||
_tooltipMethod = "dispose";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
EditForm?.AddValidator((FieldIdentifier.Model.GetType(), FieldIdentifier.FieldName), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_tooltipMethod) && !string.IsNullOrEmpty(Id))
|
||||
{
|
||||
JSRuntime.Tooltip(Id, _tooltipMethod);
|
||||
_tooltipMethod = "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ICollection<ValidatorComponentBase> Rules { get; } = new HashSet<ValidatorComponentBase>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.OpenElement(0, "input");
|
||||
builder.AddMultipleAttributes(1, AdditionalAttributes);
|
||||
builder.AddAttribute(2, "class", $"{CssClass} {ValidCss}");
|
||||
builder.AddAttribute(3, "value", BindConverter.FormatValue(CurrentValue));
|
||||
builder.AddAttribute(4, "oninput", EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString));
|
||||
if (!string.IsNullOrEmpty(ErrorMessage)) builder.AddAttribute(5, "data-original-title", ErrorMessage);
|
||||
if (!string.IsNullOrEmpty(Id)) builder.AddAttribute(6, "id", Id);
|
||||
builder.OpenComponent<CascadingValue<LgbInputText>>(7);
|
||||
builder.AddAttribute(8, "IsFixed", true);
|
||||
builder.AddAttribute(9, "Value", this);
|
||||
builder.AddAttribute(10, "ChildContent", ChildContent);
|
||||
builder.CloseComponent();
|
||||
builder.CloseElement();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bootstrap.Admin.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// LgbInputText 组件
|
||||
/// </summary>
|
||||
public class LgbInputTextBase : ValidateInputBase<string>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="validationErrorMessage"></param>
|
||||
/// <returns></returns>
|
||||
protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
|
||||
{
|
||||
result = value;
|
||||
validationErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected int? MaxLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Rules.Count == 0 &&
|
||||
AdditionalAttributes != null &&
|
||||
AdditionalAttributes.TryGetValue("maxlength", out var maxlength) &&
|
||||
int.TryParse(Convert.ToString(maxlength), out int ml))
|
||||
{
|
||||
return ml;
|
||||
}
|
||||
return (Rules.FirstOrDefault(r => r is StringLengthValidator) as StringLengthValidator)?.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@ namespace Bootstrap.Admin.Components
|
|||
protected void MovePrev()
|
||||
{
|
||||
if (PageIndex > 1) OnPageClick(PageIndex - 1, PageItems);
|
||||
else OnPageClick(PageCount, PageItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -64,6 +65,7 @@ namespace Bootstrap.Admin.Components
|
|||
protected void MoveNext()
|
||||
{
|
||||
if (PageIndex < PageCount) OnPageClick(PageIndex + 1, PageItems);
|
||||
else OnPageClick(1, PageItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -95,14 +97,21 @@ namespace Bootstrap.Admin.Components
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="totalCount"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageItems"></param>
|
||||
public void Update(int totalCount, int pageIndex, int pageItems)
|
||||
protected int StartPageIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected int EndPageIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
TotalCount = totalCount;
|
||||
PageIndex = pageIndex;
|
||||
PageItems = pageItems;
|
||||
// 计算 分页开始页码与结束页码
|
||||
StartPageIndex = Math.Max(1, PageIndex - 4);
|
||||
EndPageIndex = Math.Min(PageCount, PageIndex + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@ namespace Bootstrap.Admin.Components
|
|||
private readonly string _defaultTitle = "查询条件";
|
||||
private readonly string _defaultText = "查询";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Id { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 查询组件标题 默认为 查询条件
|
||||
/// </summary>
|
||||
|
@ -37,12 +43,6 @@ namespace Bootstrap.Admin.Components
|
|||
public TItem QueryModel { get; set; }
|
||||
#nullable restore
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<TItem> QueryModelChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 查询按钮回调方法
|
||||
/// </summary>
|
||||
|
@ -57,5 +57,7 @@ namespace Bootstrap.Admin.Components
|
|||
if (string.IsNullOrEmpty(Title)) Title = _defaultTitle;
|
||||
if (string.IsNullOrEmpty(Text)) Text = _defaultText;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender) => base.OnAfterRender(firstRender);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Bootstrap.Admin.Components
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class QueryInputTextBase<TItem> : LgbInputTextBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -9,11 +9,19 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
public class RequiredValidator : ValidatorComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RequiredValidator()
|
||||
{
|
||||
ErrorMessage = "这是必填字段";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否允许空字符串 默认 false 不允许
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool AllowEmptyString { get; set; } = false;
|
||||
public bool AllowEmptyString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -8,20 +8,8 @@ namespace Bootstrap.Admin.Components
|
|||
/// <summary>
|
||||
/// Select 组件基类
|
||||
/// </summary>
|
||||
public class SelectBase<TItem> : ComponentBase
|
||||
public class SelectBase<TItem> : ValidateInputBase<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 控件 ID
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Id { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 背景显示文字
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PlaceHolder { get; set; } = "请选择 ...";
|
||||
|
||||
/// <summary>
|
||||
/// 当前选择项实例
|
||||
/// </summary>
|
||||
|
@ -33,38 +21,24 @@ namespace Bootstrap.Admin.Components
|
|||
[Parameter]
|
||||
public List<SelectedItem> Items { get; set; } = new List<SelectedItem>();
|
||||
|
||||
#nullable disable
|
||||
private TItem _value;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public TItem SelectedValue
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
Items.ForEach(t =>
|
||||
{
|
||||
t.Active = t.Value == _value.ToString();
|
||||
t.Active = t.Value == Value?.ToString();
|
||||
if (t.Active) SelectedItem = t;
|
||||
});
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
||||
///<summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<TItem> SelectedValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
if (!SelectedItem.Active)
|
||||
{
|
||||
SelectedItem = Items.FirstOrDefault(item => item.Active) ?? Items.First();
|
||||
|
@ -75,16 +49,15 @@ namespace Bootstrap.Admin.Components
|
|||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<SelectedItem> SelectedItemChanged { get; set; } = new Action<SelectedItem>(v => { });
|
||||
public Action<SelectedItem>? SelectedItemChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void ItemClickCallback(SelectedItem item)
|
||||
{
|
||||
SelectedItemChanged(item);
|
||||
SelectedItem = item;
|
||||
StateHasChanged();
|
||||
CurrentValueAsString = item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,9 @@ namespace Bootstrap.Admin.Components
|
|||
public NavigatorBarModel Model { get; set; } = new NavigatorBarModel("");
|
||||
|
||||
/// <summary>
|
||||
/// 视图更新方法
|
||||
/// 侧边栏绑定 Model 改变事件
|
||||
/// </summary>
|
||||
public void Update(NavigatorBarModel model)
|
||||
{
|
||||
Model = model;
|
||||
StateHasChanged();
|
||||
}
|
||||
[Parameter]
|
||||
public EventCallback<NavigatorBarModel> ModelChanged { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,20 @@ namespace Bootstrap.Admin.Components
|
|||
/// </summary>
|
||||
public class StringLengthValidator : ValidatorComponentBase
|
||||
{
|
||||
private int _length = 50;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Length { get; set; }
|
||||
public int Length
|
||||
{
|
||||
get { return _length; }
|
||||
set
|
||||
{
|
||||
_length = value;
|
||||
ErrorMessage = $"不可为空,{_length}字以内";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Bootstrap.Admin.Components
|
|||
/// <summary>
|
||||
/// 表格组件类
|
||||
/// </summary>
|
||||
public class TableBase<TItem> : BootstrapComponentBase
|
||||
public class TableBase<TItem> : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -245,6 +245,19 @@ namespace Bootstrap.Admin.Components
|
|||
EditModal?.Toggle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toast 组件实例
|
||||
/// </summary>
|
||||
protected Toast? Toast { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="cate"></param>
|
||||
protected void ShowMessage(string title, string text, ToastCategory cate = ToastCategory.Success) => Toast?.ShowMessage(title, text, cate);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -322,5 +335,7 @@ namespace Bootstrap.Admin.Components
|
|||
}
|
||||
ShowMessage("删除数据", "删除数据" + (result ? "成功" : "失败"), result ? ToastCategory.Success : ToastCategory.Error);
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender) => base.OnAfterRender(firstRender);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
using Bootstrap.Admin.Extensions;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bootstrap.Admin.Components
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class ValidateInputBase<TItem> : InputBase<TItem>, IValidateComponent
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Inject]
|
||||
protected IJSRuntime? JSRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public LgbEditFormBase? EditForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Id
|
||||
{
|
||||
get { return $"{EditForm?.Id}_{FieldIdentifier.FieldName}"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string? PlaceHolder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (AdditionalAttributes != null &&
|
||||
AdditionalAttributes.TryGetValue("placeholder", out var ph) &&
|
||||
!string.IsNullOrEmpty(Convert.ToString(ph)))
|
||||
{
|
||||
return ph.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string ErrorMessage { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string ValidCss { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string DisplayName { get; set; } = "-";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
EditForm?.AddValidator((EditForm, FieldIdentifier.Model.GetType(), FieldIdentifier.FieldName), this);
|
||||
DisplayName = FieldIdentifier.GetDisplayName();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_tooltipMethod) && !string.IsNullOrEmpty(Id))
|
||||
{
|
||||
JSRuntime.Tooltip(Id, _tooltipMethod);
|
||||
_tooltipMethod = "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ICollection<ValidatorComponentBase> Rules { get; } = new HashSet<ValidatorComponentBase>();
|
||||
|
||||
private string _tooltipMethod = "";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="propertyValue"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="results"></param>
|
||||
public void ValidateProperty(object? propertyValue, ValidationContext context, List<ValidationResult> results)
|
||||
{
|
||||
Rules.ToList().ForEach(validator => validator.Validate(propertyValue, context, results));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示/隐藏验证结果方法
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <param name="validProperty">是否对本属性进行数据验证</param>
|
||||
public void ToggleMessage(IEnumerable<ValidationResult> results, bool validProperty)
|
||||
{
|
||||
if (Rules.Any())
|
||||
{
|
||||
var messages = results.Where(item => item.MemberNames.Any(m => m == FieldIdentifier.FieldName));
|
||||
if (messages.Any())
|
||||
{
|
||||
ErrorMessage = messages.First().ErrorMessage;
|
||||
ValidCss = "is-invalid";
|
||||
|
||||
// 控件自身数据验证时显示 tooltip
|
||||
// EditForm 数据验证时调用 tooltip('enable') 保证 tooltip 组件生成
|
||||
// 调用 tooltip('hide') 后导致鼠标悬停时 tooltip 无法正常显示
|
||||
_tooltipMethod = validProperty ? "show" : "enable";
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "";
|
||||
ValidCss = "is-valid";
|
||||
_tooltipMethod = "dispose";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="validationErrorMessage"></param>
|
||||
/// <returns></returns>
|
||||
protected override bool TryParseValueFromString(string value, out TItem result, out string? validationErrorMessage)
|
||||
{
|
||||
if (typeof(TItem) == typeof(string))
|
||||
{
|
||||
result = (TItem)(object)value;
|
||||
validationErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
else if (typeof(TItem).IsEnum)
|
||||
{
|
||||
var success = BindConverter.TryConvertTo<TItem>(value, CultureInfo.CurrentCulture, out var parsedValue);
|
||||
if (success)
|
||||
{
|
||||
result = parsedValue;
|
||||
validationErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#nullable disable
|
||||
result = default;
|
||||
#nullable restore
|
||||
validationErrorMessage = $"The {FieldIdentifier.FieldName} field is not valid.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof(TItem).IsValueType)
|
||||
{
|
||||
result = (TItem)Convert.ChangeType(value, typeof(TItem));
|
||||
validationErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"{GetType()} does not support the type '{typeof(TItem)}'.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ namespace Bootstrap.Admin.Components
|
|||
///
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public LgbInputText? Input { get; set; }
|
||||
public LgbInputTextBase? Input { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法
|
||||
|
@ -30,7 +30,7 @@ namespace Bootstrap.Admin.Components
|
|||
if (Input == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(ValidatorComponentBase)} requires a cascading " +
|
||||
$"parameter of type {nameof(LgbInputText)}. For example, you can use {nameof(ValidatorComponentBase)} " +
|
||||
$"parameter of type {nameof(LgbInputTextBase)}. For example, you can use {nameof(ValidatorComponentBase)} " +
|
||||
$"inside an LgbInputText.");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
using Bootstrap.Security;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class DisplayNamesExtensions
|
||||
{
|
||||
|
||||
private static ConcurrentDictionary<(Type ModelType, string FieldName), string> _displayNameCache = new ConcurrentDictionary<(Type, string), string>();
|
||||
|
||||
/// <summary>
|
||||
/// 向系统中加入实体类显示名称字典
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddDisplayNames(this IServiceCollection services)
|
||||
{
|
||||
_displayNameCache.TryAdd((typeof(BootstrapDict), nameof(BootstrapDict.Category)), "字典标签");
|
||||
_displayNameCache.TryAdd((typeof(BootstrapDict), nameof(BootstrapDict.Name)), "字典名称");
|
||||
_displayNameCache.TryAdd((typeof(BootstrapDict), nameof(BootstrapDict.Code)), "字典代码");
|
||||
_displayNameCache.TryAdd((typeof(BootstrapDict), nameof(BootstrapDict.Define)), "字典类型");
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="displayName"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetValue((Type ModelType, string FieldName) cacheKey, out string? displayName) => _displayNameCache.TryGetValue(cacheKey, out displayName);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="valueFactory"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetOrAdd((Type ModelType, string FieldName) cacheKey, Func<(Type, string), string> valueFactory) => _displayNameCache.GetOrAdd(cacheKey, valueFactory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using Bootstrap.Admin.Components;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Bootstrap.Admin.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class FieldIdentifierExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fieldIdentifier"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDisplayName(this FieldIdentifier fieldIdentifier)
|
||||
{
|
||||
var cacheKey = (fieldIdentifier.Model.GetType(), fieldIdentifier.FieldName);
|
||||
if (!DisplayNamesExtensions.TryGetValue(cacheKey, out var dn))
|
||||
{
|
||||
if (BootstrapAdminEditContextDataAnnotationsExtensions.TryGetValidatableProperty(fieldIdentifier, out var propertyInfo))
|
||||
{
|
||||
var displayNameAttribute = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true);
|
||||
if (displayNameAttribute.Length > 0)
|
||||
{
|
||||
dn = ((DisplayNameAttribute)displayNameAttribute[0]).DisplayName;
|
||||
|
||||
// add display name into cache
|
||||
DisplayNamesExtensions.GetOrAdd((fieldIdentifier.Model.GetType(), fieldIdentifier.FieldName), key => dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dn ?? "未设置";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ namespace Bootstrap.Admin.Extensions
|
|||
/// 启用动画
|
||||
/// </summary>
|
||||
/// <param name="jSRuntime"></param>
|
||||
public static void EnableAnimation(this IJSRuntime? jSRuntime) => jSRuntime.InvokeVoidAsync("$.initDocument");
|
||||
public static void InitDocument(this IJSRuntime? jSRuntime) => jSRuntime.InvokeVoidAsync("$.initDocument");
|
||||
|
||||
/// <summary>
|
||||
/// 修复 Modal 组件
|
||||
|
|
|
@ -2,18 +2,9 @@
|
|||
|
||||
<EditPage Id="dict" TItem="Bootstrap.Security.BootstrapDict" QueryModel="QueryModel" OnQuery="Query" OnAdd="Add" OnDelete="Delete" OnSave="Save">
|
||||
<QueryBody>
|
||||
<div class="form-group col-sm-6 col-md-auto">
|
||||
<label class="control-label" for="txt_dict_cate">字典标签</label>
|
||||
<input type="text" class="form-control" @bind="context.Category" data-provide="typeahead" />
|
||||
</div>
|
||||
<div class="form-group col-sm-6 col-md-auto">
|
||||
<label class="control-label" for="txt_dict_name">字典名称</label>
|
||||
<input type="text" class="form-control" @bind="context.Name" />
|
||||
</div>
|
||||
<div class="form-group col-sm-6 col-md-auto">
|
||||
<label class="control-label" for="txt_dict_define">字典类型</label>
|
||||
<Select Items="QueryDefine" TItem="int" SelectedItemChanged="item=>context.Define = int.Parse(item.Value)"></Select>
|
||||
</div>
|
||||
<LgbInputText @bind-Value="@context.Category" maxlength="50" />
|
||||
<Select Items="QueryDefine" TItem="int" @bind-Value="@context.Define" />
|
||||
<LgbInputText @bind-Value="@context.Name" maxlength="50" />
|
||||
</QueryBody>
|
||||
<TableHeader>
|
||||
<th>字典标签</th>
|
||||
|
@ -25,32 +16,23 @@
|
|||
<td>@context.Category</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Code</td>
|
||||
<td>@context.Define</td>
|
||||
<td>@(DefineItems.FirstOrDefault(d => d.Value == context.Define.ToString())?.Text ?? "-")</td>
|
||||
</RowTemplate>
|
||||
<EditTemplate>
|
||||
<div class="row">
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="dictCate">字典标签</label>
|
||||
<LgbInputText Id="dictCate" type="text" class="form-control" data-toggle="tooltip" @bind-Value="context.Category" placeholder="不可为空,50字以内">
|
||||
<RequiredValidator AllowEmptyString="false" ErrorMessage="这是必填字段" />
|
||||
<StringLengthValidator Length="5" ErrorMessage="不可为空,50字以内" />
|
||||
<LgbInputText @bind-Value="@context.Category" placeholder="不可为空,50字以内" maxlength="50">
|
||||
<RequiredValidator />
|
||||
<StringLengthValidator Length="50" />
|
||||
</LgbInputText>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="dictDefine">字典类型</label>
|
||||
<Select Id="dictDefine" Items="DefineItems" TItem="int" @bind-SelectedValue="context.Define" SelectedItemChanged="@(item=>context.Define = int.Parse(item.Value))"></Select>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="dictName">字典名称</label>
|
||||
<LgbInputText Id="dictName" type="text" class="form-control" @bind-Value="context.Name" placeholder="不可为空,50字以内" maxlength="50">
|
||||
<RequiredValidator AllowEmptyString="false" ErrorMessage="这是必填字段" />
|
||||
<StringLengthValidator Length="5" ErrorMessage="不可为空,50字以内" />
|
||||
<Select Items="DefineItems" TItem="int" @bind-Value="@context.Define"></Select>
|
||||
<LgbInputText @bind-Value="@context.Name" placeholder="不可为空,50字以内" maxlength="50">
|
||||
<RequiredValidator />
|
||||
<StringLengthValidator Length="50" />
|
||||
</LgbInputText>
|
||||
<LgbInputText @bind-Value="@context.Code" placeholder="不可为空,2000字以内" maxlength="2000">
|
||||
<RequiredValidator />
|
||||
<StringLengthValidator Length="2000" />
|
||||
</LgbInputText>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="dictCode">字典代码</label>
|
||||
<LgbInputText Id="dictCode" type="text" class="form-control" @bind-Value="context.Code" placeholder="不可为空,2000字以内" maxlength="2000" />
|
||||
</div>
|
||||
</div>
|
||||
</EditTemplate>
|
||||
</EditPage>
|
||||
|
|
|
@ -5,5 +5,4 @@
|
|||
<Section ShowCardTitle="@RootLayout.Model.ShowCardTitle" LockScreenPeriod=@RootLayout.Model.LockScreenPeriod>
|
||||
<TabSet @ref="TabSet"></TabSet>
|
||||
</Section>
|
||||
<Toast @ref="Toast"></Toast>
|
||||
</CascadingValue>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@inherits DefaultLayoutComponentBase
|
||||
|
||||
<CascadingValue Value=this Name="Default">
|
||||
<Header @ref="Header" Icon="@Model.Icon" Title="@Model.Title" IsAdmin=@IsAdmin UserName="@Model.UserName" @bind-DisplayName="@DisplayName"></Header>
|
||||
<SideBar @ref="SideBar" Model=@Model />
|
||||
<Header Icon="@Model.Icon" Title="@Model.Title" IsAdmin=@IsAdmin UserName="@Model.UserName" @bind-DisplayName="@DisplayName"></Header>
|
||||
<SideBar @bind-Model=@Model />
|
||||
@Body
|
||||
<Footer Text="@Model.Footer" IsDemo=@Model.IsDemo></Footer>
|
||||
</CascadingValue>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@typeparam TItem
|
||||
@inherits EditPageBase<TItem>
|
||||
|
||||
<Query OnQuery="Query" TItem="TItem" @bind-QueryModel="QueryModel">
|
||||
<Query Id="@($"{Id}_query")" OnQuery="Query" TItem="TItem" QueryModel="QueryModel">
|
||||
@QueryBody?.Invoke(context)
|
||||
</Query>
|
||||
<div class="card">
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
@inherits LgbInputTextBase
|
||||
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="@Id">@DisplayName</label>
|
||||
<input Id="@Id" data-original-title="@ErrorMessage" class="@($"form-control {CssClass} {ValidCss}")" placeholder="@PlaceHolder" maxlength=@MaxLength type="text" @bind="Value" @oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
|
||||
<CascadingValue Value="this" IsFixed="true">
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</div>
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
<ul class="@(PageCount > 1 ? "pagination" : "pagination d-none")">
|
||||
<li class="page-item" @onclick="MovePrev"><div class="page-link" aria-label="上一页"><i class="fa fa-angle-double-left"></i></div></li>
|
||||
@for (int i = 1; i <= PageCount; i++)
|
||||
@for (int i = StartPageIndex; i <= EndPageIndex; i++)
|
||||
{
|
||||
<PaginationItem Active="i == PageIndex" PageIndex="i"></PaginationItem>
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
<div class="card">
|
||||
<div class="card-header">@Title</div>
|
||||
<div class="card-body">
|
||||
<div class="form-inline">
|
||||
<LgbEditForm class="form-inline" Id="@Id" Model="QueryModel" OnValidSubmit="e => OnQuery?.Invoke()">
|
||||
<div class="row">
|
||||
@ChildContent?.Invoke(QueryModel)
|
||||
<div class="form-group col-sm-6 col-md-auto flex-sm-fill justify-content-sm-end align-self-sm-end">
|
||||
<button type="button" id="btn_query" class="btn btn-primary btn-fill" @onclick="e => OnQuery?.Invoke()"><i class="fa fa-search" aria-hidden="true"></i><span>@Text</span></button>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-fill"><i class="fa fa-search"></i><span>@Text</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</LgbEditForm>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
@typeparam TItem
|
||||
@inherits SelectBase<TItem>
|
||||
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="@Id">@DisplayName</label>
|
||||
<div data-toggle="lgbSelect" class="form-select dropdown">
|
||||
<input type="text" readonly="readonly" class="form-control form-select-input" id="@Id" data-toggle="dropdown" placeholder="@PlaceHolder" value="@SelectedItem.Text">
|
||||
<input type="text" readonly="readonly" class="form-control form-select-input" id="@Id" data-toggle="dropdown" placeholder="@PlaceHolder" value="@SelectedItem.Text" />
|
||||
<span class="form-select-append"><i class="fa fa-angle-up"></i></span>
|
||||
<div class="dropdown-menu-arrow"></div>
|
||||
<div class="dropdown-menu">
|
||||
|
@ -12,6 +14,7 @@
|
|||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@typeparam TItem
|
||||
@inherits SubmitModalBase<TItem>
|
||||
|
||||
<Modal Id="@Id" Title="Title" Size="Size">
|
||||
<Modal Id="@Id" Title="@Title" Size="@Size">
|
||||
<ModalBody>
|
||||
<LgbEditForm class="form-inline" Model="Model" OnValidSubmit="OnValidSubmit" OnInvalidSubmit="OnInvalidSubmit" OnSubmit="OnSubmit">
|
||||
<LgbEditForm class="form-inline" Id="@Id" Model="Model" OnValidSubmit="OnValidSubmit" OnInvalidSubmit="OnInvalidSubmit" OnSubmit="OnSubmit">
|
||||
@ModalBody
|
||||
</LgbEditForm>
|
||||
</ModalBody>
|
||||
|
|
|
@ -79,12 +79,10 @@
|
|||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
<SubmitModal @ref="EditModal" Id="@($"{Id}_submit")" TItem="TItem" Title="字典编辑窗口" Size="ModalSize.ExtraLarge" @bind-Model="EditModel" OnValidSubmit="Save">
|
||||
<SubmitModal @ref="EditModal" Id="@($"{Id}_edit")" TItem="TItem" Title="字典编辑窗口" Size="ModalSize.ExtraLarge" @bind-Model="EditModel" OnValidSubmit="Save">
|
||||
<ModalBody>
|
||||
@EditTemplate?.Invoke(EditModel)
|
||||
</ModalBody>
|
||||
</SubmitModal>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
<Toast @ref="Toast"></Toast>
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace Bootstrap.Admin
|
|||
{
|
||||
if (Enviroment.IsDevelopment()) options.DetailedErrors = true;
|
||||
});
|
||||
services.AddDisplayNames();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
|
|
@ -215,8 +215,3 @@ nav .dropdown .nav-link-close.dropdown-toggle:after {
|
|||
margin-bottom: 15px;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
/* Validation */
|
||||
input[type="text"].valid, input[type="password"].valid {
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
|
|
@ -109,14 +109,8 @@
|
|||
initDocument: function () {
|
||||
$('body').removeClass('trans-mute');
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
},
|
||||
initSidebar: function () {
|
||||
$('.sidebar').addNiceScroll().autoScrollSidebar();
|
||||
},
|
||||
enableBackground: function (val) {
|
||||
if (val) $('.main-content').addClass('welcome-bg').find('nav').addClass('d-none').removeClass('d-flex');
|
||||
else $('.main-content').removeClass('welcome-bg').find('nav').addClass('d-flex').removeClass('d-none');
|
||||
},
|
||||
initModal: function () {
|
||||
$('.modal').appendTo($('body'));
|
||||
},
|
||||
|
@ -130,7 +124,12 @@
|
|||
$('.toast').toast('show');
|
||||
},
|
||||
tooltip: function (id, method) {
|
||||
$(id).tooltip(method);
|
||||
var $ele = $(id);
|
||||
if (method === 'enable') {
|
||||
$ele.tooltip();
|
||||
$ele.parents('form').find('.invalid:first').focus();
|
||||
}
|
||||
else $ele.tooltip(method);
|
||||
},
|
||||
submitForm: function (btn) {
|
||||
$(btn).parent().prev().find('form :submit').click();
|
||||
|
|
Loading…
Reference in New Issue