😎 feat(文本简称): 增加文本简称功能并应用到用户姓名
- 新增 BindTextAbbrAttribute 特性用于绑定文本简称字段 - 创建 SysTextAbbr 表存储文字简称数据 - 在 SysUser 表中添加姓名简称相关字段 - 实现 GetNameAbbr 方法获取文本简称 - 在数据初始化时导入简称数据 - 在数据审计操作中智能设置带[BindTextAbbr]特性字段值
This commit is contained in:
parent
776d4f195a
commit
d9e56baeb9
28
Admin.NET/Admin.NET.Core/Attribute/BindTextAbbrAttribute.cs
Normal file
28
Admin.NET/Admin.NET.Core/Attribute/BindTextAbbrAttribute.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
29
Admin.NET/Admin.NET.Core/Entity/SysTextAbbr.cs
Normal file
29
Admin.NET/Admin.NET.Core/Entity/SysTextAbbr.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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>
|
||||
[MaxLength(1)]
|
||||
[SugarColumn(ColumnDescription = "文字", Length = 1)]
|
||||
public virtual string Word { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文字全称
|
||||
/// </summary>
|
||||
[MaxLength(8)]
|
||||
[SugarColumn(ColumnDescription = "文字全称", Length = 8)]
|
||||
public virtual string FullName { get; set; }
|
||||
}
|
||||
@ -38,6 +38,22 @@ public partial class SysUser : EntityTenant
|
||||
[MaxLength(32)]
|
||||
public virtual string RealName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名简拼
|
||||
/// </summary>
|
||||
[BindTextAbbr(nameof(RealName))]
|
||||
[SugarColumn(ColumnDescription = "简拼", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public virtual string? Pinyin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名全拼
|
||||
/// </summary>
|
||||
[BindTextAbbr(nameof(RealName), true)]
|
||||
[SugarColumn(ColumnDescription = "姓名全拼", Length = 32)]
|
||||
[MaxLength(32)]
|
||||
public virtual string? AllPinyin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
|
||||
23
Admin.NET/Admin.NET.Core/Service/Common/Dto/NameAbbrInput.cs
Normal file
23
Admin.NET/Admin.NET.Core/Service/Common/Dto/NameAbbrInput.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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; }
|
||||
}
|
||||
@ -17,13 +17,18 @@ namespace Admin.NET.Core.Service;
|
||||
[AllowAnonymous]
|
||||
public class SysCommonService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysTextAbbr> _sysTextAbbrRep;
|
||||
private readonly IApiDescriptionGroupCollectionProvider _apiProvider;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
private readonly IHttpRemoteService _httpRemoteService;
|
||||
|
||||
public SysCommonService(IApiDescriptionGroupCollectionProvider apiProvider, SysCacheService sysCacheService, IHttpRemoteService httpRemoteService)
|
||||
public SysCommonService(IApiDescriptionGroupCollectionProvider apiProvider,
|
||||
SysCacheService sysCacheService,
|
||||
SqlSugarRepository<SysTextAbbr> sysTextAbbrRep,
|
||||
IHttpRemoteService httpRemoteService)
|
||||
{
|
||||
_apiProvider = apiProvider;
|
||||
_sysTextAbbrRep = sysTextAbbrRep;
|
||||
_sysCacheService = sysCacheService;
|
||||
_httpRemoteService = httpRemoteService;
|
||||
}
|
||||
@ -285,4 +290,22 @@ 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 ? " " : "");
|
||||
}
|
||||
}
|
||||
@ -57,7 +57,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取用户分页列表")]
|
||||
[DisplayName("获取用户分页列表")]
|
||||
public virtual async Task<SqlSugarPagedList<UserOutput>> Page(PageUserInput input)
|
||||
{
|
||||
// 获取用户拥有的机构集合
|
||||
@ -82,7 +82,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
.Where(u => u.AccountType != AccountTypeEnum.SuperAdmin)
|
||||
.WhereIF(orgList != null || extOrgUserIdList != null, u => orgList.Contains(u.OrgId) || extOrgUserIdList.Contains(u.Id))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Account.Contains(input.Account))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.RealName), u => u.RealName.Contains(input.RealName))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.RealName), u => u.RealName.Contains(input.RealName) || u.Pinyin.Contains(input.RealName) || u.AllPinyin.Replace(" ", "").Contains(input.RealName))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.PosName), (u, a, b) => b.Name.Contains(input.PosName))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Phone), u => u.Phone.Contains(input.Phone))
|
||||
.OrderBy(u => new { u.OrderNo, u.Id })
|
||||
@ -103,18 +103,18 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
[DisplayName("增加用户")]
|
||||
[DisplayName("增加用户")]
|
||||
public virtual async Task<long> AddUser(AddUserInput input)
|
||||
{
|
||||
// 是否有权操作此账号
|
||||
{
|
||||
// 是否有权操作此账号
|
||||
if (!_userManager.SuperAdmin && input.AccountType is AccountTypeEnum.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D1033);
|
||||
|
||||
var query = _sysUserRep.AsQueryable().ClearFilter();
|
||||
if (await query.AnyAsync(u => u.Account == input.Account)) throw Oops.Oh(ErrorCodeEnum.D1003);
|
||||
if (!string.IsNullOrWhiteSpace(input.Phone) && await query.AnyAsync(u => u.Phone == input.Phone)) throw Oops.Oh(ErrorCodeEnum.D1032);
|
||||
|
||||
|
||||
// 若没有设置密码则取默认密码
|
||||
var password = !string.IsNullOrWhiteSpace(input.Password) ? input.Password : await _sysConfigService.GetConfigValueByCode<string>(ConfigConst.SysPassword);
|
||||
var password = !string.IsNullOrWhiteSpace(input.Password) ? input.Password : await _sysConfigService.GetConfigValueByCode<string>(ConfigConst.SysPassword);
|
||||
var user = input.Adapt<SysUser>();
|
||||
user.Password = CryptogramHelper.Encrypt(password);
|
||||
var newUser = await _sysUserRep.AsInsertable(user).ExecuteReturnEntityAsync();
|
||||
@ -139,22 +139,22 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
[DisplayName("更新用户")]
|
||||
[DisplayName("更新用户")]
|
||||
public virtual async Task UpdateUser(UpdateUserInput input)
|
||||
{
|
||||
{
|
||||
var query = _sysUserRep.AsQueryable().ClearFilter().Where(u => u.Id != input.Id);
|
||||
if (await query.AnyAsync(u => u.Account == input.Account)) throw Oops.Oh(ErrorCodeEnum.D1003);
|
||||
if (!string.IsNullOrWhiteSpace(input.Phone) && await query.AnyAsync(u => u.Phone == input.Phone)) throw Oops.Oh(ErrorCodeEnum.D1032);
|
||||
|
||||
// 若账号的角色和组织架构发生变化,则强制下线账号进行权限更新
|
||||
if (!string.IsNullOrWhiteSpace(input.Phone) && await query.AnyAsync(u => u.Phone == input.Phone)) throw Oops.Oh(ErrorCodeEnum.D1032);
|
||||
|
||||
// 若账号的角色和组织架构发生变化,则强制下线账号进行权限更新
|
||||
var user = await _sysUserRep.GetByIdAsync(input.Id);
|
||||
var roleIds = await _sysUserRoleService.GetUserRoleIdList(input.Id);
|
||||
if (input.OrgId != user.OrgId || !input.RoleIdList.OrderBy(u => u).SequenceEqual(roleIds.OrderBy(u => u)))
|
||||
{
|
||||
// 强制下线账号和失效Token
|
||||
await OfflineAndExpireToken(user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
await _sysUserRep.AsUpdateable(input.Adapt<SysUser>()).IgnoreColumns(true).IgnoreColumns(u => new { u.Password, u.Status, u.TenantId }).ExecuteCommandAsync();
|
||||
|
||||
@ -190,7 +190,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
[DisplayName("删除用户")]
|
||||
[DisplayName("删除用户")]
|
||||
public virtual async Task DeleteUser(DeleteUserInput input)
|
||||
{
|
||||
var user = await _sysUserRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
@ -231,7 +231,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// 查看用户基本信息 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("查看用户基本信息")]
|
||||
[DisplayName("查看用户基本信息")]
|
||||
public virtual async Task<SysUser> GetBaseInfo()
|
||||
{
|
||||
return await _sysUserRep.GetByIdAsync(_userManager.UserId);
|
||||
@ -242,7 +242,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "UpdateBaseInfo"), HttpPost]
|
||||
[DisplayName("更新用户基本信息")]
|
||||
[DisplayName("更新用户基本信息")]
|
||||
public virtual async Task<int> UpdateBaseInfo(SysUser user)
|
||||
{
|
||||
return await _sysUserRep.AsUpdateable(user)
|
||||
@ -255,7 +255,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[DisplayName("设置用户状态")]
|
||||
[DisplayName("设置用户状态")]
|
||||
public virtual async Task<int> SetStatus(BaseStatusInput input)
|
||||
{
|
||||
if (_userManager.UserId == input.Id)
|
||||
@ -288,7 +288,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[DisplayName("授权用户角色")]
|
||||
[DisplayName("授权用户角色")]
|
||||
public async Task GrantRole(UserRoleInput input)
|
||||
{
|
||||
var user = await _sysUserRep.GetByIdAsync(input.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
@ -311,7 +311,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("修改用户密码")]
|
||||
[DisplayName("修改用户密码")]
|
||||
public virtual async Task<int> ChangePwd(ChangePwdInput input)
|
||||
{
|
||||
// 国密SM2解密(前端密码传输SM2加密后的)
|
||||
@ -376,7 +376,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("重置用户密码")]
|
||||
[DisplayName("重置用户密码")]
|
||||
public virtual async Task<string> ResetPwd(ResetPwdUserInput input)
|
||||
{
|
||||
var user = await _sysUserRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
@ -404,7 +404,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// 验证密码有效期 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("验证密码有效期")]
|
||||
[DisplayName("验证密码有效期")]
|
||||
public async Task<bool> VerifyPwdExpirationTime()
|
||||
{
|
||||
var sysConfig = await _sysConfigService.GetConfig(ConfigConst.SysPasswordExpirationTime);
|
||||
@ -424,7 +424,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("解除登录锁定")]
|
||||
[DisplayName("解除登录锁定")]
|
||||
public virtual async Task UnlockLogin(BaseIdInput input)
|
||||
{
|
||||
var user = await _sysUserRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
@ -442,7 +442,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取用户拥有角色集合")]
|
||||
[DisplayName("获取用户拥有角色集合")]
|
||||
public async Task<GrantRoleOutput> GetOwnRoleList(long userId)
|
||||
{
|
||||
// 获取当前用户已分配角色
|
||||
@ -461,7 +461,7 @@ public class SysUserService : IDynamicApiController, ITransient
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取用户扩展机构集合")]
|
||||
[DisplayName("获取用户扩展机构集合")]
|
||||
public async Task<List<SysUserExtOrg>> GetOwnExtOrgList(long userId)
|
||||
{
|
||||
return await _sysUserExtOrgService.GetUserExtOrgList(userId);
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using System.Text.Json;
|
||||
using Minio.DataModel;
|
||||
using NewLife.IO;
|
||||
using NewLife.Reflection;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
@ -173,8 +176,8 @@ public static class SqlSugarExtension
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
Expression bExpresionFilter;
|
||||
|
||||
Expression bExpresionFilter;
|
||||
|
||||
if (Enum.IsDefined(typeof(FilterLogicEnum), filter.Logic))
|
||||
{
|
||||
if (filter.Filters is null) throw new ArgumentException("The Filters attribute is required when declaring a logic");
|
||||
@ -384,37 +387,37 @@ public static class SqlSugarExtension
|
||||
{
|
||||
if (entityType.GetCustomAttribute<SysTableAttribute>() == null &&
|
||||
(entityType.GetCustomAttribute<LogTableAttribute>() != null ||
|
||||
entityType.GetCustomAttribute<TenantAttribute>() != null))
|
||||
{
|
||||
entityType.GetCustomAttribute<TenantAttribute>() != null))
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 非SysTable 与 (LogTable 或 Tenant)表");
|
||||
return default;
|
||||
return default;
|
||||
}
|
||||
}
|
||||
else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库
|
||||
{
|
||||
if (entityType.GetCustomAttribute<LogTableAttribute>() == null)
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 非LogTable表");
|
||||
return default;
|
||||
if (entityType.GetCustomAttribute<LogTableAttribute>() == null)
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 非LogTable表");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var att = entityType.GetCustomAttribute<TenantAttribute>(); // 自定义的库
|
||||
if (att == null || att.configId.ToString() != config.ConfigId.ToString())
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 非Tenant表");
|
||||
return default;
|
||||
if (att == null || att.configId.ToString() != config.ConfigId.ToString())
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 非Tenant表");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
var instance = Activator.CreateInstance(seedType);
|
||||
var hasDataMethod = seedType.GetMethod("HasData");
|
||||
var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>().ToArray() ?? [];
|
||||
if (seedData.Length == 0)
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 没有种子数据");
|
||||
return default;
|
||||
if (seedData.Length == 0)
|
||||
{
|
||||
Console.WriteLine($" 忽略 {seedType.FullName,-58} ({dbProvider.CurrentConnectionConfig.ConfigId}) 原因: 没有种子数据");
|
||||
return default;
|
||||
}
|
||||
|
||||
// 若实体包含Id字段,则设置为当前租户Id递增1
|
||||
@ -510,4 +513,89 @@ public static class SqlSugarExtension
|
||||
}
|
||||
|
||||
#endregion 视图操作
|
||||
|
||||
#region 简称操作
|
||||
/// <summary>
|
||||
/// 包含缩写特性的类型属性缓存表
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, Dictionary<string, (PropertyInfo Prop, BindTextAbbrAttribute Attr)>?> _textAbbrPropCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 系统通用服务
|
||||
/// </summary>
|
||||
private static readonly Lazy<SysCommonService> _lazySysCommonService = new(() => App.GetService<SysCommonService>());
|
||||
|
||||
/// <summary>
|
||||
/// 初始化文本简称数据
|
||||
/// </summary>
|
||||
/// <param name="dbProvider"></param>
|
||||
public static async Task InitTextAbbDataAsync(this SqlSugarScopeProvider dbProvider)
|
||||
{
|
||||
// 表数据为空,则导入数据
|
||||
if (await dbProvider.Queryable<SysTextAbbr>().CountAsync() == 0)
|
||||
{
|
||||
var totalWatch = Stopwatch.StartNew(); // 开始总计时
|
||||
var message = "尝试初始化简称表数据,";
|
||||
var path = AppDomain.CurrentDomain.BaseDirectory + "pinyin.csv";
|
||||
using var reader = new StreamReader(path);
|
||||
await using var csv = new CsvFile(reader.BaseStream);
|
||||
var lines = csv.ReadAll().Select(u => new SysTextAbbr
|
||||
{
|
||||
Word = u[0],
|
||||
FullName = u[1]
|
||||
}).ToList();
|
||||
var count = await dbProvider.Storageable(lines).WhereColumns(u => new { u.Word, u.FullName }).ExecuteCommandAsync();
|
||||
message += $"成功导入 {count} 条,总耗时:{totalWatch.ElapsedMilliseconds} ms";
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动注入文本缩写到绑定字段
|
||||
/// </summary>
|
||||
/// <param name="entityInfo"></param>
|
||||
public static void SetTextAbbrProperty(this DataFilterModel entityInfo)
|
||||
{
|
||||
// 仅处理新增/更新操作
|
||||
if (entityInfo.OperationType is DataFilterType.InsertByObject or DataFilterType.UpdateByObject)
|
||||
{
|
||||
var entityValue = entityInfo.EntityValue;
|
||||
var entityType = entityValue.GetType();
|
||||
|
||||
// 仅在目标属性值为空时触发自动生成
|
||||
if (entityValue.GetValue(entityInfo.PropertyName) == null)
|
||||
{
|
||||
// 获取或创建类型属性缓存(原子化操作避免竞争条件)
|
||||
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.Any() ? 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))
|
||||
{
|
||||
// 使用线程安全的延迟初始化服务实例获取文本缩写
|
||||
var abbrValue = _lazySysCommonService.Value
|
||||
.GetNameAbbr(new() { Text = value, All = attribute.SaveFullAbbr })
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
entityInfo.SetValue(abbrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@ -283,6 +283,9 @@ public static class SqlSugarSetup
|
||||
entityInfo.SetValue(App.User?.FindFirst(ClaimConst.RealName)?.Value);
|
||||
}
|
||||
|
||||
// 设置绑定简称字段数据
|
||||
entityInfo.SetTextAbbrProperty();
|
||||
|
||||
//// 自定义数据审计
|
||||
//SqlSugarDataExecuting.Execute(oldValue, entityInfo);
|
||||
};
|
||||
@ -364,6 +367,9 @@ public static class SqlSugarSetup
|
||||
|
||||
// 初始化种子数据
|
||||
if (config.SeedSettings.EnableInitSeed) InitSeedData(dbProvider, config.SeedSettings.EnableIncreSeed);
|
||||
|
||||
// 初始化文本简称表数据
|
||||
_ = dbProvider.InitTextAbbDataAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -23,6 +23,7 @@ import { AdminNETResultListString } from '../models';
|
||||
import { AdminNETResultSmKeyPairOutput } from '../models';
|
||||
import { AdminNETResultStressTestHarnessResult } from '../models';
|
||||
import { AdminNETResultString } from '../models';
|
||||
import { NameAbbrInput } from '../models';
|
||||
import { StressTestInput } from '../models';
|
||||
/**
|
||||
* SysCommonApi - axios parameter creator
|
||||
@ -325,6 +326,54 @@ export const SysCommonApiAxiosParamCreator = function (configuration?: Configura
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* 获取文本简称
|
||||
* @summary 获取文本简称
|
||||
* @param {NameAbbrInput} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
apiSysCommonNameAbbrPost: async (body?: NameAbbrInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/api/sysCommon/nameAbbr`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication Bearer required
|
||||
// http bearer authentication required
|
||||
if (configuration && configuration.accessToken) {
|
||||
const accessToken = typeof configuration.accessToken === 'function'
|
||||
? await configuration.accessToken()
|
||||
: await configuration.accessToken;
|
||||
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
||||
}
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
|
||||
|
||||
const query = new URLSearchParams(localVarUrlObj.search);
|
||||
for (const key in localVarQueryParameter) {
|
||||
query.set(key, localVarQueryParameter[key]);
|
||||
}
|
||||
for (const key in options.params) {
|
||||
query.set(key, options.params[key]);
|
||||
}
|
||||
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
|
||||
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
|
||||
|
||||
return {
|
||||
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary 国密SM2解密字符串 🔖
|
||||
@ -608,6 +657,20 @@ export const SysCommonApiFp = function(configuration?: Configuration) {
|
||||
return axios.request(axiosRequestArgs);
|
||||
};
|
||||
},
|
||||
/**
|
||||
* 获取文本简称
|
||||
* @summary 获取文本简称
|
||||
* @param {NameAbbrInput} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async apiSysCommonNameAbbrPost(body?: NameAbbrInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultString>>> {
|
||||
const localVarAxiosArgs = await SysCommonApiAxiosParamCreator(configuration).apiSysCommonNameAbbrPost(body, options);
|
||||
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||
return axios.request(axiosRequestArgs);
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary 国密SM2解密字符串 🔖
|
||||
@ -733,6 +796,16 @@ export const SysCommonApiFactory = function (configuration?: Configuration, base
|
||||
async apiSysCommonMachineSerialKeyGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultString>> {
|
||||
return SysCommonApiFp(configuration).apiSysCommonMachineSerialKeyGet(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* 获取文本简称
|
||||
* @summary 获取文本简称
|
||||
* @param {NameAbbrInput} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async apiSysCommonNameAbbrPost(body?: NameAbbrInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultString>> {
|
||||
return SysCommonApiFp(configuration).apiSysCommonNameAbbrPost(body, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary 国密SM2解密字符串 🔖
|
||||
@ -849,6 +922,17 @@ export class SysCommonApi extends BaseAPI {
|
||||
public async apiSysCommonMachineSerialKeyGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultString>> {
|
||||
return SysCommonApiFp(this.configuration).apiSysCommonMachineSerialKeyGet(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
/**
|
||||
* 获取文本简称
|
||||
* @summary 获取文本简称
|
||||
* @param {NameAbbrInput} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof SysCommonApi
|
||||
*/
|
||||
public async apiSysCommonNameAbbrPost(body?: NameAbbrInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultString>> {
|
||||
return SysCommonApiFp(this.configuration).apiSysCommonNameAbbrPost(body, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @summary 国密SM2解密字符串 🔖
|
||||
|
||||
@ -99,6 +99,22 @@ export interface AddUserInput {
|
||||
*/
|
||||
tenantId?: number | null;
|
||||
|
||||
/**
|
||||
* 姓名简拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AddUserInput
|
||||
*/
|
||||
pinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名全拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AddUserInput
|
||||
*/
|
||||
allPinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*
|
||||
|
||||
@ -332,6 +332,7 @@ export * from './mqtt-client-status';
|
||||
export * from './mqtt-protocol-version';
|
||||
export * from './mqtt-session-status';
|
||||
export * from './mzb-input';
|
||||
export * from './name-abbr-input';
|
||||
export * from './navigate';
|
||||
export * from './network-info';
|
||||
export * from './network-interface-statistics';
|
||||
|
||||
38
Web/src/api-services/system/models/name-abbr-input.ts
Normal file
38
Web/src/api-services/system/models/name-abbr-input.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Admin.NET 通用权限开发平台
|
||||
* 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
|
||||
*
|
||||
* OpenAPI spec version: 1.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取文本简称
|
||||
*
|
||||
* @export
|
||||
* @interface NameAbbrInput
|
||||
*/
|
||||
export interface NameAbbrInput {
|
||||
|
||||
/**
|
||||
* 文本
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof NameAbbrInput
|
||||
*/
|
||||
text?: string | null;
|
||||
|
||||
/**
|
||||
* 是否全称
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof NameAbbrInput
|
||||
*/
|
||||
all?: boolean;
|
||||
}
|
||||
@ -114,6 +114,22 @@ export interface SysUser {
|
||||
*/
|
||||
realName?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名简拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SysUser
|
||||
*/
|
||||
pinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名全拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SysUser
|
||||
*/
|
||||
allPinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*
|
||||
|
||||
@ -99,6 +99,22 @@ export interface UpdateUserInput {
|
||||
*/
|
||||
tenantId?: number | null;
|
||||
|
||||
/**
|
||||
* 姓名简拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UpdateUserInput
|
||||
*/
|
||||
pinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名全拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UpdateUserInput
|
||||
*/
|
||||
allPinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*
|
||||
|
||||
@ -114,6 +114,22 @@ export interface UserOutput {
|
||||
*/
|
||||
realName?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名简拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserOutput
|
||||
*/
|
||||
pinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 姓名全拼
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserOutput
|
||||
*/
|
||||
allPinyin?: string | null;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*
|
||||
|
||||
@ -84,6 +84,8 @@ export default {
|
||||
messageDetail: '消息详情',
|
||||
account: '账号',
|
||||
realName: '姓名',
|
||||
pinyin: '簡拼',
|
||||
allPinyin: '全拼',
|
||||
jobTitle: '职位名称',
|
||||
phoneNumber: '手机号码',
|
||||
resetPassword: '重置密码',
|
||||
|
||||
@ -80,6 +80,8 @@ export default {
|
||||
messageDetail: '消息詳情',
|
||||
account: '賬號',
|
||||
realName: '姓名',
|
||||
pinyin: '簡拼',
|
||||
allPinyin: '全拼',
|
||||
jobTitle: '職位名稱',
|
||||
phoneNumber: '手機號碼',
|
||||
resetPassword: '重置密碼',
|
||||
|
||||
@ -80,6 +80,8 @@ export default {
|
||||
messageDetail: '訊息詳細',
|
||||
account: '帳號',
|
||||
realName: '姓名',
|
||||
pinyin: '简拼',
|
||||
allPinyin: '全拼',
|
||||
jobTitle: '職稱',
|
||||
phoneNumber: '手機號碼',
|
||||
resetPassword: '重設密碼',
|
||||
|
||||
@ -3,6 +3,9 @@ import useClipboard from 'vue-clipboard3';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { formatDate } from '/@/utils/formatTime';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {debounce} from "lodash-es";
|
||||
import {getAPI} from "/@/utils/axios-utils";
|
||||
import {SysCommonApi} from "/@/api-services/system";
|
||||
|
||||
export default function () {
|
||||
const { t } = useI18n();
|
||||
@ -83,6 +86,18 @@ export default function () {
|
||||
.join('&');
|
||||
return `${url}${url.includes('?') ? '&' : '?'}${queryString}`;
|
||||
};
|
||||
// 获取简称
|
||||
const getNameAbbr = (text: string, callback?: (abbr: any) => void) => {
|
||||
if (!text) return ElMessage.error('获取简称文本不能为空');
|
||||
try {
|
||||
return getAPI(SysCommonApi).apiSysCommonNameAbbrPost({ text: text }).then(res => {
|
||||
if (callback) callback(res.data.result);
|
||||
return res.data.result;
|
||||
})
|
||||
} catch (e) {
|
||||
ElMessage.error('获取失败');
|
||||
}
|
||||
};
|
||||
return {
|
||||
percentFormat,
|
||||
dateFormatYMD,
|
||||
@ -96,5 +111,6 @@ export default function () {
|
||||
removeHtml,
|
||||
getEnumDesc,
|
||||
appendQueryParams,
|
||||
getNameAbbr,
|
||||
};
|
||||
}
|
||||
|
||||
@ -159,6 +159,9 @@ const options = useVxeTable<UserOutput>(
|
||||
{ field: 'nickName', title: t('message.list.nickname'), minWidth: 120, showOverflow: 'tooltip' },
|
||||
|
||||
{ field: 'realName', title: t('message.list.realName'), minWidth: 120, showOverflow: 'tooltip' },
|
||||
{ field: 'pinyin', title: t('message.list.pinyin'), minWidth: 120, showOverflow: 'tooltip' },
|
||||
{ field: 'allPinyin', title: t('message.list.allPinyin'), minWidth: 120, showOverflow: 'tooltip' },
|
||||
|
||||
{ field: 'phone', title: t('message.list.phoneNumber'), minWidth: 120, showOverflow: 'tooltip' },
|
||||
|
||||
{ field: 'birthday', title: t('message.list.birthDate'), minWidth: 100, showOverflow: 'tooltip', formatter: ({ cellValue }: any) => XEUtils.toDateString(cellValue, 'yyyy-MM-dd') },
|
||||
|
||||
Loading…
Reference in New Issue
Block a user