😎1、去掉简称处理相关(建议在应用层实现) 2、优化代码生成
This commit is contained in:
parent
8663139322
commit
69be46b158
@ -1,110 +1,94 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Application.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 代码自动生成DEMO
|
||||
/// </summary>
|
||||
/// <remarks>这个类型主要用于给新人快速体验代码自动生成功能和测试该功能是否正常</remarks>
|
||||
[SugarTable(null, "代码自动生成DEMO")]
|
||||
public class TestCodeGenDemo : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 重写主键类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "Id", ColumnDescription = "主键Id", IsPrimaryKey = true, IsIdentity = false)]
|
||||
public new Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 流水号
|
||||
/// </summary>
|
||||
[BindSerial(nameof(SerialTypeProvider.Test))]
|
||||
[SugarColumn(ColumnDescription = "流水号", Length = 128)]
|
||||
public string? SeqNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "文本", Length = 128)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名简拼
|
||||
/// </summary>
|
||||
[BindTextAbbr(nameof(Name))]
|
||||
[SugarColumn(ColumnDescription = "简拼", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public virtual string? Pinyin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名全拼
|
||||
/// </summary>
|
||||
[BindTextAbbr(nameof(Name), true)]
|
||||
[SugarColumn(ColumnDescription = "姓名全拼", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public virtual string? AllPinyin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数值")]
|
||||
public int? Age { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间选择
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "时间选择")]
|
||||
public DateTime? Date1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开关
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "开关")]
|
||||
public bool? IsOk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键(sys_user)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键(sys_user)")]
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 树选择框1(sys_org)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "树选择框1(sys_org)")]
|
||||
public long? OrgId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 树选择框2(sys_menu)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "树选择框2(sys_menu)")]
|
||||
public long? MenuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字典1")]
|
||||
public string? Dict1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 枚举1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "枚举1")]
|
||||
public int? Enum1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 常量1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "常量1")]
|
||||
public int? Const1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传控件
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "上传控件")]
|
||||
public string? UploadImage { get; set; }
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Application.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 代码自动生成DEMO
|
||||
/// </summary>
|
||||
/// <remarks>这个类型主要用于给新人快速体验代码自动生成功能和测试该功能是否正常</remarks>
|
||||
[SugarTable(null, "代码自动生成DEMO")]
|
||||
public class TestCodeGenDemo : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 重写主键类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "Id", ColumnDescription = "主键Id", IsPrimaryKey = true, IsIdentity = false)]
|
||||
public new Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 流水号
|
||||
/// </summary>
|
||||
[BindSerial(nameof(SerialTypeProvider.Test))]
|
||||
[SugarColumn(ColumnDescription = "流水号", Length = 128)]
|
||||
public string? SeqNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "文本", Length = 128)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "数值")]
|
||||
public int? Age { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间选择
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "时间选择")]
|
||||
public DateTime? Date1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开关
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "开关")]
|
||||
public bool? IsOk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外键(sys_user)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "外键(sys_user)")]
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 树选择框1(sys_org)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "树选择框1(sys_org)")]
|
||||
public long? OrgId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 树选择框2(sys_menu)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "树选择框2(sys_menu)")]
|
||||
public long? MenuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "字典1")]
|
||||
public string? Dict1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 枚举1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "枚举1")]
|
||||
public int? Enum1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 常量1
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "常量1")]
|
||||
public int? Const1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传控件
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "上传控件")]
|
||||
public string? UploadImage { get; set; }
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 绑定文本简称字段特性
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class BindTextAbbrAttribute : Attribute
|
||||
{
|
||||
public string PropertyName { get; }
|
||||
public bool SaveFullAbbr { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化绑定文本简称字段特性
|
||||
/// </summary>
|
||||
/// <param name="propertyName">关联的属性名称</param>
|
||||
/// <param name="saveFullAbbr">是否保存全称</param>
|
||||
public BindTextAbbrAttribute(string propertyName, bool saveFullAbbr = false)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
SaveFullAbbr = saveFullAbbr;
|
||||
}
|
||||
}
|
||||
@ -121,12 +121,4 @@ public partial class SysCodeGen : EntityBase
|
||||
/// </summary>
|
||||
[Navigate(NavigateType.OneToMany, nameof(SysCodeGenTable.CodeGenId))]
|
||||
public List<SysCodeGenTable> TableList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 简拼
|
||||
/// </summary>
|
||||
[BindTextAbbr(nameof(BusName))]
|
||||
[SugarColumn(ColumnDescription = "简拼", Length = 128)]
|
||||
[MaxLength(128)]
|
||||
public virtual string? Pinyin { get; set; }
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统文字简称表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统文字简称表")]
|
||||
[SysTable]
|
||||
public partial class SysTextAbbr : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 文字
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "文字", Length = 4)]
|
||||
[MaxLength(4)]
|
||||
public virtual string Word { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文字全称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "文字全称", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public virtual string FullName { get; set; }
|
||||
}
|
||||
@ -51,7 +51,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
|
||||
{
|
||||
return await _db.Queryable<SysCodeGen>().Includes(u => u.TableList)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableList.Any(a => a.TableName.Contains(input.TableName.Trim()) || a.EntityName.Contains(input.TableName.Trim())))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName.Contains(input.BusName.Trim()) || u.Pinyin.Contains(input.BusName.Trim()))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName.Contains(input.BusName.Trim()))
|
||||
.OrderBy(u => u.Id, OrderByType.Desc)
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 获取文本简称
|
||||
/// </summary>
|
||||
public class NameAbbrInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全称
|
||||
/// </summary>
|
||||
public bool All { get; set; }
|
||||
}
|
||||
@ -16,17 +16,14 @@ namespace Admin.NET.Core.Service;
|
||||
[ApiDescriptionSettings(Order = 101, Description = "通用接口")]
|
||||
public class SysCommonService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysTextAbbr> _sysTextAbbrRep;
|
||||
private readonly IApiDescriptionGroupCollectionProvider _apiProvider;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
private readonly IHttpRemoteService _httpRemoteService;
|
||||
|
||||
public SysCommonService(SqlSugarRepository<SysTextAbbr> sysTextAbbrRep,
|
||||
IApiDescriptionGroupCollectionProvider apiProvider,
|
||||
public SysCommonService(IApiDescriptionGroupCollectionProvider apiProvider,
|
||||
SysCacheService sysCacheService,
|
||||
IHttpRemoteService httpRemoteService)
|
||||
{
|
||||
_sysTextAbbrRep = sysTextAbbrRep;
|
||||
_apiProvider = apiProvider;
|
||||
_sysCacheService = sysCacheService;
|
||||
_httpRemoteService = httpRemoteService;
|
||||
@ -279,21 +276,4 @@ public class SysCommonService : IDynamicApiController, ITransient
|
||||
.SetJsonContent(input.JsonContent)));
|
||||
return stressTestHarnessResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文本简称
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[DisplayName("获取文本简称")]
|
||||
[ApiDescriptionSettings(Order = 1, Description = "获取文本简称")]
|
||||
public async Task<string> GetNameAbbr(NameAbbrInput input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.Text)) return "";
|
||||
var map = (await _sysTextAbbrRep.GetListAsync(u => input.Text.Contains(u.Word)))?.ToDictionary(u => u.Word, u => u.FullName);
|
||||
return map == null || map.Count == 0 ? input.Text : input.Text.Select(c =>
|
||||
{
|
||||
var val = map.GetValueOrDefault(c.ToString(), c.ToString());
|
||||
return input.All ? val : val[..1].ToLower();
|
||||
}).Join(input.All ? " " : "");
|
||||
}
|
||||
}
|
||||
@ -717,7 +717,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
||||
}
|
||||
}
|
||||
|
||||
Type[] cosType = types.Where(u => IsMyAttribute(Attribute.GetCustomAttributes(u, true))).ToArray();
|
||||
Type[] cosType = types.Where(u => IsMyAttribute(Attribute.GetCustomAttributes(u, false))).ToArray();
|
||||
foreach (var c in cosType)
|
||||
{
|
||||
var sugarAttribute = c.GetCustomAttributes(type, true)?.FirstOrDefault();
|
||||
|
||||
@ -515,89 +515,6 @@ public static class SqlSugarExtension
|
||||
|
||||
#endregion 视图操作
|
||||
|
||||
#region 简称操作
|
||||
|
||||
/// <summary>
|
||||
/// 延迟初始化流水号服务实例
|
||||
/// </summary>
|
||||
private static readonly Lazy<SysCommonService> SysCommon = new(() => App.GetService<SysCommonService>());
|
||||
|
||||
/// <summary>
|
||||
/// 包含缩写特性的类型属性缓存表
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, Dictionary<string, (PropertyInfo Prop, BindTextAbbrAttribute Attr)>?> _textAbbrPropCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化文本简称数据
|
||||
/// </summary>
|
||||
/// <param name="dbProvider"></param>
|
||||
public static void InitTextAbbData(this SqlSugarScopeProvider dbProvider)
|
||||
{
|
||||
// 表数据为空,则导入数据
|
||||
if (dbProvider.Queryable<SysTextAbbr>().Any()) return;
|
||||
|
||||
var totalWatch = Stopwatch.StartNew();
|
||||
var path = AppDomain.CurrentDomain.BaseDirectory + "pinyin.csv";
|
||||
using var reader = new StreamReader(path);
|
||||
using var csv = new CsvFile(reader.BaseStream);
|
||||
var lines = csv.ReadAll().Select(u => new SysTextAbbr
|
||||
{
|
||||
Word = u[0],
|
||||
FullName = u[1]
|
||||
}).ToList();
|
||||
var count = dbProvider.Storageable(lines).WhereColumns(u => new { u.Word, u.FullName }).ExecuteCommand();
|
||||
Console.WriteLine($"初始化简称数据 {count} 条,总耗时:{totalWatch.ElapsedMilliseconds} ms");
|
||||
totalWatch.Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动注入文本缩写到绑定字段
|
||||
/// </summary>
|
||||
/// <param name="entityInfo"></param>
|
||||
public static void SetTextAbbrProperty(this DataFilterModel entityInfo)
|
||||
{
|
||||
// 仅处理新增/更新操作
|
||||
if (entityInfo.OperationType != DataFilterType.InsertByObject && entityInfo.OperationType != DataFilterType.UpdateByObject) return;
|
||||
|
||||
var entityValue = entityInfo.EntityValue;
|
||||
var entityType = entityValue.GetType();
|
||||
|
||||
// 仅在目标属性值为空时触发自动生成
|
||||
if (entityValue.GetValue(entityInfo.PropertyName) != null) return;
|
||||
|
||||
// 获取或创建类型属性缓存(原子化操作避免竞争条件)
|
||||
var propDict = _textAbbrPropCache.GetOrAdd(entityType, type =>
|
||||
{
|
||||
// 反射获取带[BindTextAbbr]特性的属性,预存属性元数据
|
||||
var props = type.GetProperties()
|
||||
.Where(p => p.IsDefined(typeof(BindTextAbbrAttribute)))
|
||||
.Select(p => (p, p.GetCustomAttribute<BindTextAbbrAttribute>()!))
|
||||
.ToDictionary(t => t.p.Name, t => (t.p, t.Item2));
|
||||
|
||||
return props.Count != 0 ? props : null;
|
||||
});
|
||||
|
||||
// 无绑定属性或当前属性不匹配时提前结束
|
||||
if (propDict == null || !propDict.TryGetValue(entityInfo.PropertyName, out var propData)) return;
|
||||
|
||||
// 解构预存的属性和特性信息
|
||||
var (_, attribute) = propData;
|
||||
var value = entityValue.GetValue(attribute.PropertyName)?.ToString();
|
||||
|
||||
// 源文本非空时生成缩写
|
||||
if (string.IsNullOrWhiteSpace(value)) return;
|
||||
|
||||
// 使用线程安全的延迟初始化服务实例获取文本缩写
|
||||
var abbrValue = SysCommon.Value
|
||||
.GetNameAbbr(new() { Text = value, All = attribute.SaveFullAbbr })
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
entityInfo.SetValue(abbrValue);
|
||||
}
|
||||
|
||||
#endregion 简称操作
|
||||
|
||||
#region 流水号操作
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -282,9 +282,6 @@ public static class SqlSugarSetup
|
||||
entityInfo.SetValue(App.User?.FindFirst(ClaimConst.RealName)?.Value);
|
||||
}
|
||||
|
||||
// 设置绑定简称字段数据
|
||||
entityInfo.SetTextAbbrProperty();
|
||||
|
||||
// 设置绑定流水号字段数据
|
||||
entityInfo.SetSerialProperty();
|
||||
|
||||
@ -370,9 +367,6 @@ public static class SqlSugarSetup
|
||||
// 初始化种子数据
|
||||
if (config.SeedSettings.EnableInitSeed) InitSeedData(dbProvider, config.SeedSettings.EnableIncreSeed);
|
||||
|
||||
// 初始化文本简称表数据
|
||||
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) dbProvider.InitTextAbbData();
|
||||
|
||||
// 由于修改定时任务后数据库无法更新,暂时先清空内置的定时任务数据
|
||||
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId)
|
||||
{
|
||||
|
||||
@ -20,9 +20,6 @@
|
||||
<EmbeddedResource Remove="publish\**" />
|
||||
<None Remove="logs\**" />
|
||||
<None Remove="publish\**" />
|
||||
<None Update="pinyin.csv">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@
|
||||
</template>
|
||||
</el-popover>
|
||||
</el-button-group>
|
||||
<el-button icon="ele-Refresh" type="warning" @click="handleInitTableAndSeedData"> 初始化库表结构及种子数据 </el-button>
|
||||
<el-button icon="ele-Refresh" type="warning" plain @click="handleInitTableAndSeedData"> 初始化库表结构及种子数据 </el-button>
|
||||
<el-button icon="ele-View" type="primary" plain @click="visualTable"> 库表关系可视化 </el-button>
|
||||
</template>
|
||||
<template #toolbar_tools> </template>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user