feat: 框架代码同步 (#178)

Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
nsnail 2024-10-14 13:55:53 +08:00 committed by GitHub
parent dfe6b03b21
commit 58e4572723
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
185 changed files with 4732 additions and 1086 deletions

View File

@ -10,6 +10,7 @@ ij_xml_text_wrap = off # IntelliJ IDEA 中 XML 文本不换行
indent_size = 4 # 缩进大小为 4 个空格 indent_size = 4 # 缩进大小为 4 个空格
indent_style = space # 使用空格进行缩进 indent_style = space # 使用空格进行缩进
insert_final_newline = false # 不在文件末尾插入空行 insert_final_newline = false # 不在文件末尾插入空行
max_line_length = 150 # 行长度限制为 150 个字符
trim_trailing_whitespace = true # 删除行尾的空格 trim_trailing_whitespace = true # 删除行尾的空格
[{*.json,*.yml}] [{*.json,*.yml}]

View File

@ -25,7 +25,7 @@
<Title>$(AssemblyName)</Title> <Title>$(AssemblyName)</Title>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MinVer" Version="6.0.0-rc.1"> <PackageReference Include="MinVer" Version="6.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.7 AS base FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 8080 EXPOSE 8080
RUN apt update RUN apt update

View File

@ -78,6 +78,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.12.4"> <PackageReference Include="Roslynator.Analyzers" Version="4.12.8">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,8 +1,8 @@
{ {
"version": "1.6.0", "version": "1.6.0",
"devDependencies": { "devDependencies": {
"cz-git": "^1.9.4", "cz-git": "^1.10.1",
"commitizen": "^4.3.0", "commitizen": "^4.3.1",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"standard-version": "^9.5.0" "standard-version": "^9.5.0"
}, },

View File

@ -9,7 +9,7 @@
"packages": [ "packages": [
{ {
"packageName": "Furion.Pure.NS", "packageName": "Furion.Pure.NS",
"version": "4.9.5.2-ns1" "version": "4.9.5.8-ns1"
} }
] ]
} }

View File

@ -21,8 +21,7 @@ public static class ServiceCollectionExtensions
(Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => { (Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => {
// 数据权限过滤器 // 数据权限过滤器
_ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( // _ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( //
Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA, () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false
, () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false
, a => a.OwnerId == ContextUserInfo.Create().Id); , a => a.OwnerId == ContextUserInfo.Create().Id);
}); });
} }

View File

@ -1,3 +1,26 @@
/*
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BUG
*/
using NetAdmin.AdmServer.Host; using NetAdmin.AdmServer.Host;
using NetAdmin.AdmServer.Host.Extensions; using NetAdmin.AdmServer.Host.Extensions;
using NetAdmin.Host.Extensions; using NetAdmin.Host.Extensions;

View File

@ -4,6 +4,6 @@
<ProjectReference Include="../NetAdmin.AdmServer.Host/NetAdmin.AdmServer.Host.csproj"/> <ProjectReference Include="../NetAdmin.AdmServer.Host/NetAdmin.AdmServer.Host.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,10 +5,8 @@ namespace NetAdmin.Application.Repositories;
/// <summary> /// <summary>
/// 基础仓储 /// 基础仓储
/// </summary> /// </summary>
public sealed class BasicRepository<TEntity, TPrimary>( public sealed class BasicRepository<TEntity, TPrimary>(IFreeSql fSql, UnitOfWorkManager uowManger, ContextUserToken userToken)
IFreeSql fSql : DefaultRepository<TEntity, TPrimary>(fSql, uowManger)
, UnitOfWorkManager uowManger
, ContextUserToken userToken) : DefaultRepository<TEntity, TPrimary>(fSql, uowManger)
where TEntity : EntityBase<TPrimary> // where TEntity : EntityBase<TPrimary> //
where TPrimary : IEquatable<TPrimary> where TPrimary : IEquatable<TPrimary>
{ {

View File

@ -20,19 +20,15 @@ public abstract class RedisService<TEntity, TPrimary, TLogger>(BasicRepository<T
/// </summary> /// </summary>
protected IDatabase RedisDatabase { get; } // protected IDatabase RedisDatabase { get; } //
= App.GetService<IConnectionMultiplexer>() = App.GetService<IConnectionMultiplexer>()
.GetDatabase(App.GetOptions<RedisOptions>() .GetDatabase(App.GetOptions<RedisOptions>().Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE).Database);
.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
.Database);
/// <summary> /// <summary>
/// 获取锁 /// 获取锁
/// </summary> /// </summary>
protected Task<RedisLocker> GetLockerAsync(string lockerName) protected Task<RedisLocker> GetLockerAsync(string lockerName)
{ {
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY)
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY) , Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
, Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
} }
/// <summary> /// <summary>
@ -40,8 +36,7 @@ public abstract class RedisService<TEntity, TPrimary, TLogger>(BasicRepository<T
/// </summary> /// </summary>
protected Task<RedisLocker> GetLockerOnceAsync(string lockerName) protected Task<RedisLocker> GetLockerOnceAsync(string lockerName)
{ {
return RedisLocker.GetLockerAsync(RedisDatabase, lockerName return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), 1
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), 1
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY)); , TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
} }
} }

View File

@ -12,8 +12,7 @@ namespace NetAdmin.Application.Services;
/// <typeparam name="TEntity">实体类型</typeparam> /// <typeparam name="TEntity">实体类型</typeparam>
/// <typeparam name="TPrimary">主键类型</typeparam> /// <typeparam name="TPrimary">主键类型</typeparam>
/// <typeparam name="TLogger">日志类型</typeparam> /// <typeparam name="TLogger">日志类型</typeparam>
public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo) public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo) : ServiceBase<TLogger>
: ServiceBase<TLogger>
where TEntity : EntityBase<TPrimary> // where TEntity : EntityBase<TPrimary> //
where TPrimary : IEquatable<TPrimary> where TPrimary : IEquatable<TPrimary>
{ {
@ -46,8 +45,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
/// 导出实体 /// 导出实体
/// </summary> /// </summary>
protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( // protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( //
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName, Expression<Func<TEntity, object>> listExp = null)
, Expression<Func<TEntity, object>> listExp = null)
where TQuery : DataAbstraction, new() where TQuery : DataAbstraction, new()
{ {
var select = selector(query) var select = selector(query)
@ -56,9 +54,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
#endif #endif
.Take(Numbers.MAX_LIMIT_EXPORT); .Take(Numbers.MAX_LIMIT_EXPORT);
object list = listExp == null object list = listExp == null ? await select.ToListAsync().ConfigureAwait(false) : await select.ToListAsync(listExp).ConfigureAwait(false);
? await select.ToListAsync().ConfigureAwait(false)
: await select.ToListAsync(listExp).ConfigureAwait(false);
return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false); return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false);
} }
@ -108,10 +104,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
{ {
// 默认匹配主键 // 默认匹配主键
whereExp ??= a => a.Id.Equals(newValue.Id); whereExp ??= a => a.Id.Equals(newValue.Id);
return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion) return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql).ExecuteUpdatedAsync();
.Where(whereExp)
.Where(whereSql)
.ExecuteUpdatedAsync();
} }
#endif #endif
@ -134,7 +127,8 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
App.HttpContext.Response.Headers.ContentDisposition App.HttpContext.Response.Headers.ContentDisposition
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) { = new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv" FileNameStar
= $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
}.ToString(); }.ToString();
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM); return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
@ -149,9 +143,7 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
var updateExp = includeFields == null var updateExp = includeFields == null
? Rpo.UpdateDiy.SetSource(entity) ? Rpo.UpdateDiy.SetSource(entity)
: Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary( : Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary(
x => x x => x, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!.GetValue(entity)));
, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!
.GetValue(entity)));
if (excludeFields != null) { if (excludeFields != null) {
updateExp = updateExp.IgnoreColumns(excludeFields); updateExp = updateExp.IgnoreColumns(excludeFields);
} }

View File

@ -5,8 +5,7 @@ namespace NetAdmin.Cache;
/// <summary> /// <summary>
/// 缓存基类 /// 缓存基类
/// </summary> /// </summary>
public abstract class CacheBase<TCacheContainer, TService>(TCacheContainer cache, TService service) public abstract class CacheBase<TCacheContainer, TService>(TCacheContainer cache, TService service) : ICache<TCacheContainer, TService>
: ICache<TCacheContainer, TService>
where TService : IService where TService : IService
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@ -6,8 +6,7 @@ namespace NetAdmin.Cache;
/// <summary> /// <summary>
/// 分布式缓存 /// 分布式缓存
/// </summary> /// </summary>
public abstract class DistributedCache<TService>(IDistributedCache cache, TService service) public abstract class DistributedCache<TService>(IDistributedCache cache, TService service) : CacheBase<IDistributedCache, TService>(cache, service)
: CacheBase<IDistributedCache, TService>(cache, service)
where TService : IService where TService : IService
{ {
/// <summary> /// <summary>
@ -66,12 +65,10 @@ public abstract class DistributedCache<TService>(IDistributedCache cache, TServi
/// <param name="slideLifeTime">滑动过期时间</param> /// <param name="slideLifeTime">滑动过期时间</param>
/// <typeparam name="T">缓存对象类型</typeparam> /// <typeparam name="T">缓存对象类型</typeparam>
/// <returns>缓存对象</returns> /// <returns>缓存对象</returns>
protected async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> createProc, TimeSpan? absLifeTime = null protected async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> createProc, TimeSpan? absLifeTime = null, TimeSpan? slideLifeTime = null)
, TimeSpan? slideLifeTime = null)
{ {
var cacheRead = await GetAsync<T>(key).ConfigureAwait(false); var cacheRead = await GetAsync<T>(key).ConfigureAwait(false);
if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() != if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() != Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
return cacheRead; return cacheRead;
} }

View File

@ -5,6 +5,5 @@ namespace NetAdmin.Cache;
/// <summary> /// <summary>
/// 内存缓存 /// 内存缓存
/// </summary> /// </summary>
public abstract class MemoryCache<TService>(IMemoryCache cache, TService service) public abstract class MemoryCache<TService>(IMemoryCache cache, TService service) : CacheBase<IMemoryCache, TService>(cache, service)
: CacheBase<IMemoryCache, TService>(cache, service)
where TService : IService; where TService : IService;

View File

@ -12,8 +12,7 @@ public sealed class ApiIdAttribute : ValidationAttribute
/// <inheritdoc /> /// <inheritdoc />
protected override ValidationResult IsValid(object value, ValidationContext validationContext) protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{ {
var service = App.GetService(App.EffectiveTypes.Single( var service = App.GetService(App.EffectiveTypes.Single(x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IApiCache"));
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IApiCache"));
var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } }; var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } };

View File

@ -9,8 +9,6 @@ public sealed class JsonStringAttribute : ValidationAttribute
/// <inheritdoc /> /// <inheritdoc />
protected override ValidationResult IsValid(object value, ValidationContext validationContext) protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{ {
return (value as string).IsJsonString() return (value as string).IsJsonString() ? ValidationResult.Success : new ValidationResult(Ln.JSON字符串, [validationContext.MemberName]);
? ValidationResult.Success
: new ValidationResult(Ln.JSON字符串, new[] { validationContext.MemberName });
} }
} }

View File

@ -12,8 +12,7 @@ public sealed class UserIdAttribute : ValidationAttribute
/// <inheritdoc /> /// <inheritdoc />
protected override ValidationResult IsValid(object value, ValidationContext validationContext) protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{ {
var service = App.GetService(App.EffectiveTypes.Single( var service = App.GetService(App.EffectiveTypes.Single(x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IUserCache"));
x => x.FullName == "NetAdmin.SysComponent.Cache.Sys.Dependency.IUserCache"));
var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } }; var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } };

View File

@ -45,9 +45,7 @@ public sealed record ContextUserToken : DataAbstraction
/// </summary> /// </summary>
public static ContextUserToken Create(QueryUserRsp user) public static ContextUserToken Create(QueryUserRsp user)
{ {
return new ContextUserToken { return new ContextUserToken { Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId };
Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
};
} }
/// <summary> /// <summary>

View File

@ -30,9 +30,7 @@ public abstract record DataAbstraction
/// </summary> /// </summary>
public void TruncateStrings() public void TruncateStrings()
{ {
foreach (var property in GetType() foreach (var property in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType == typeof(string))) {
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.PropertyType == typeof(string))) {
var maxLen = property.GetCustomAttribute<MaxLengthAttribute>(true)?.Length; var maxLen = property.GetCustomAttribute<MaxLengthAttribute>(true)?.Length;
if (maxLen is null or 0) { if (maxLen is null or 0) {
continue; continue;

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// </summary> /// </summary>
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)] [SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
public record Sys_DicContent : VersionEntity public record Sys_DicContent : VersionEntity, IFieldEnabled, IFieldSummary
{ {
/// <summary> /// <summary>
/// 字典目录 /// 字典目录
@ -23,6 +23,12 @@ public record Sys_DicContent : VersionEntity
[JsonIgnore] [JsonIgnore]
public virtual long CatalogId { get; init; } public virtual long CatalogId { get; init; }
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual bool Enabled { get; init; }
/// <summary> /// <summary>
/// 键名称 /// 键名称
/// </summary> /// </summary>
@ -31,6 +37,14 @@ public record Sys_DicContent : VersionEntity
[JsonIgnore] [JsonIgnore]
public virtual string Key { get; init; } public virtual string Key { get; init; }
/// <summary>
/// 描述
/// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
/// <summary> /// <summary>
/// 键值 /// 键值
/// </summary> /// </summary>

View File

@ -7,8 +7,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)] [SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)] [SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_LoginLog))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_LoginLog))]
public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp, IFieldCreatedClientUserAgent
, IFieldCreatedClientUserAgent
{ {
/// <inheritdoc /> /// <inheritdoc />
[Column] [Column]

View File

@ -10,8 +10,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)] [SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)] [SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
[Table( // [Table( //
Name = $"{Chars.FLG_DB_TABLE_NAME_PREFIX}{nameof(Sys_RequestLog)}_{{yyyyMMdd}}" Name = $"{Chars.FLG_DB_TABLE_NAME_PREFIX}{nameof(Sys_RequestLog)}_{{yyyyMMdd}}", AsTable = $"{nameof(CreatedTime)}=2024-5-1(1 day)")]
, AsTable = $"{nameof(CreatedTime)}=2024-1-1(1 day)")]
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
{ {
/// <summary> /// <summary>

View File

@ -123,20 +123,11 @@ public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary
{ {
_ = config.ForType<CreateRoleReq, Sys_Role>() _ = config.ForType<CreateRoleReq, Sys_Role>()
.Map( // .Map( //
d => d.Depts d => d.Depts, s => s.DeptIds.NullOrEmpty() ? Array.Empty<Sys_Dept>() : s.DeptIds.Select(x => new Sys_Dept { Id = x }))
, s => s.DeptIds.NullOrEmpty()
? Array.Empty<Sys_Dept>()
: s.DeptIds.Select(x => new Sys_Dept { Id = x }))
.Map( // .Map( //
d => d.Menus d => d.Menus, s => s.MenuIds.NullOrEmpty() ? Array.Empty<Sys_Menu>() : s.MenuIds.Select(x => new Sys_Menu { Id = x }))
, s => s.MenuIds.NullOrEmpty()
? Array.Empty<Sys_Menu>()
: s.MenuIds.Select(x => new Sys_Menu { Id = x }))
.Map( // .Map( //
d => d.Apis d => d.Apis, s => s.ApiIds.NullOrEmpty() ? Array.Empty<Sys_Api>() : s.ApiIds.Select(x => new Sys_Api { Id = x }))
, s => s.ApiIds.NullOrEmpty()
? Array.Empty<Sys_Api>()
: s.ApiIds.Select(x => new Sys_Api { Id = x }))
// //
; ;

View File

@ -91,20 +91,11 @@ public record Sys_SiteMsg : VersionEntity, IRegister, IFieldSummary
.Map( // .Map( //
d => d.Summary, s => s.Content.RemoveHtmlTag().HtmlDe().Sub(0, 100)) d => d.Summary, s => s.Content.RemoveHtmlTag().HtmlDe().Sub(0, 100))
.Map( // .Map( //
d => d.Roles d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }))
, s => s.RoleIds.NullOrEmpty()
? Array.Empty<Sys_Role>()
: s.RoleIds.Select(x => new Sys_Role { Id = x }))
.Map( // .Map( //
d => d.Users d => d.Users, s => s.UserIds.NullOrEmpty() ? Array.Empty<Sys_User>() : s.UserIds.Select(x => new Sys_User { Id = x }))
, s => s.UserIds.NullOrEmpty()
? Array.Empty<Sys_User>()
: s.UserIds.Select(x => new Sys_User { Id = x }))
.Map( // .Map( //
d => d.Depts d => d.Depts, s => s.DeptIds.NullOrEmpty() ? Array.Empty<Sys_Dept>() : s.DeptIds.Select(x => new Sys_Dept { Id = x }))
, s => s.DeptIds.NullOrEmpty()
? Array.Empty<Sys_Dept>()
: s.DeptIds.Select(x => new Sys_Dept { Id = x }))
// //
; ;

View File

@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-部门映射表 /// 站内信-部门映射表
/// </summary> /// </summary>
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}" [SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}", true)]
, true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))]
public record Sys_SiteMsgDept : ImmutableEntity public record Sys_SiteMsgDept : ImmutableEntity
{ {

View File

@ -5,8 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信标记表 /// 站内信标记表
/// </summary> /// </summary>
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}" [SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}", true)]
, true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))]
public record Sys_SiteMsgFlag : MutableEntity public record Sys_SiteMsgFlag : MutableEntity
{ {

View File

@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-角色映射表 /// 站内信-角色映射表
/// </summary> /// </summary>
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}" [SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}", true)]
, true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))]
public record Sys_SiteMsgRole : ImmutableEntity public record Sys_SiteMsgRole : ImmutableEntity
{ {

View File

@ -3,8 +3,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-用户映射表 /// 站内信-用户映射表
/// </summary> /// </summary>
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}" [SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}", true)]
, true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))]
public record Sys_SiteMsgUser : ImmutableEntity public record Sys_SiteMsgUser : ImmutableEntity
{ {

View File

@ -130,18 +130,12 @@ public record Sys_User : VersionEntity, IFieldSummary, IFieldEnabled, IRegister
.Map(d => d.Password, s => s.PasswordText.Pwd().Guid()) .Map(d => d.Password, s => s.PasswordText.Pwd().Guid())
.Map(d => d.Token, _ => Guid.NewGuid()) .Map(d => d.Token, _ => Guid.NewGuid())
.Map( // .Map( //
d => d.Roles d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }));
, s => s.RoleIds.NullOrEmpty()
? Array.Empty<Sys_Role>()
: s.RoleIds.Select(x => new Sys_Role { Id = x }));
_ = config.ForType<EditUserReq, Sys_User>() _ = config.ForType<EditUserReq, Sys_User>()
.Map( // .Map( //
d => d.Password, s => s.PasswordText.NullOrEmpty() ? Guid.Empty : s.PasswordText.Pwd().Guid()) d => d.Password, s => s.PasswordText.NullOrEmpty() ? Guid.Empty : s.PasswordText.Pwd().Guid())
.Map( // .Map( //
d => d.Roles d => d.Roles, s => s.RoleIds.NullOrEmpty() ? Array.Empty<Sys_Role>() : s.RoleIds.Select(x => new Sys_Role { Id = x }));
, s => s.RoleIds.NullOrEmpty()
? Array.Empty<Sys_Role>()
: s.RoleIds.Select(x => new Sys_Role { Id = x }));
} }
} }

View File

@ -228,7 +228,6 @@ public record Sys_UserProfile : VersionEntity, IRegister
.Map(d => d.CompanyArea, s => s.CompanyArea == null ? null : s.CompanyArea.Value) .Map(d => d.CompanyArea, s => s.CompanyArea == null ? null : s.CompanyArea.Value)
.Map(d => d.HomeArea, s => s.HomeArea == null ? null : s.HomeArea.Value) .Map(d => d.HomeArea, s => s.HomeArea == null ? null : s.HomeArea.Value)
.Map( // .Map( //
d => d.EmergencyContactArea d => d.EmergencyContactArea, s => s.EmergencyContactArea == null ? null : s.EmergencyContactArea.Value);
, s => s.EmergencyContactArea == null ? null : s.EmergencyContactArea.Value);
} }
} }

View File

@ -74,8 +74,8 @@ public sealed record DynamicFilterInfo : DataAbstraction
} }
} }
if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) } if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) }.Contains(
.Contains(d?.Field, StringComparer.OrdinalIgnoreCase)) { d?.Field, StringComparer.OrdinalIgnoreCase)) {
var val = d!.Value?.ToString(); var val = d!.Value?.ToString();
if (val?.IsIpV4() == true) { if (val?.IsIpV4() == true) {
d.Value = val.IpV4ToInt32(); d.Value = val.IpV4ToInt32();

View File

@ -6,13 +6,13 @@ namespace NetAdmin.Domain.Dto.Sys.Cache;
public sealed record CacheStatisticsRsp : DataAbstraction public sealed record CacheStatisticsRsp : DataAbstraction
{ {
private static readonly Regex[] _regexes = [ private static readonly Regex[] _regexes = [
new Regex(@"keyspace_hits:(\d+)", RegexOptions.Compiled) // new(@"keyspace_hits:(\d+)", RegexOptions.Compiled) //
, new Regex(@"keyspace_misses:(\d+)", RegexOptions.Compiled) // , new(@"keyspace_misses:(\d+)", RegexOptions.Compiled) //
, new Regex(@"uptime_in_seconds:(\d+)", RegexOptions.Compiled) // , new(@"uptime_in_seconds:(\d+)", RegexOptions.Compiled) //
, new Regex(@"used_cpu_sys:([\d\\.]+)", RegexOptions.Compiled) // , new(@"used_cpu_sys:([\d\\.]+)", RegexOptions.Compiled) //
, new Regex(@"used_cpu_user:([\d\\.]+)", RegexOptions.Compiled) // , new(@"used_cpu_user:([\d\\.]+)", RegexOptions.Compiled) //
, new Regex(@"used_memory:(\d+)", RegexOptions.Compiled) // , new(@"used_memory:(\d+)", RegexOptions.Compiled) //
, new Regex("redis_version:(.+)", RegexOptions.Compiled) // , new("redis_version:(.+)", RegexOptions.Compiled) //
]; ];
/// <summary> /// <summary>
@ -28,8 +28,7 @@ public sealed record CacheStatisticsRsp : DataAbstraction
KeyspaceHits = _regexes[0].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); KeyspaceHits = _regexes[0].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
KeyspaceMisses = _regexes[1].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); KeyspaceMisses = _regexes[1].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
UpTime = _regexes[2].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); UpTime = _regexes[2].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
UsedCpu = _regexes[3].Match(redisResult).Groups[1].Value.Trim().DecTry(0) + UsedCpu = _regexes[3].Match(redisResult).Groups[1].Value.Trim().DecTry(0) + _regexes[4].Match(redisResult).Groups[1].Value.Trim().DecTry(0);
_regexes[4].Match(redisResult).Groups[1].Value.Trim().DecTry(0);
UsedMemory = _regexes[5].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); UsedMemory = _regexes[5].Match(redisResult).Groups[1].Value.Trim().Int64Try(0);
Version = _regexes[6].Match(redisResult).Groups[1].Value.Trim(); Version = _regexes[6].Match(redisResult).Groups[1].Value.Trim();
} }

View File

@ -10,13 +10,21 @@ public record CreateDicContentReq : Sys_DicContent
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典目录编号不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典目录编号不能为空))]
public override long CatalogId { get; init; } public override long CatalogId { get; init; }
/// <inheritdoc cref="Sys_DicContent.Key" /> /// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; } = true;
/// <inheritdoc cref="Sys_DicContent.Key" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键名称不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键名称不能为空))]
public override string Key { get; init; } public override string Key { get; init; }
/// <inheritdoc cref="Sys_DicContent.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
/// <inheritdoc cref="Sys_DicContent.Value" /> /// <inheritdoc cref="Sys_DicContent.Value" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键值不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键值不能为空))]
public override string Value { get; init; } public override string Value { get; init; }
} }

View File

@ -11,12 +11,24 @@ public sealed record ExportDicContentRsp : QueryDicContentRsp
[CsvName(nameof(Ln.创建时间))] [CsvName(nameof(Ln.创建时间))]
public override DateTime CreatedTime { get; init; } public override DateTime CreatedTime { get; init; }
/// <inheritdoc />
[CsvIndex(3)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.是否启用))]
public override bool Enabled { get; init; }
/// <inheritdoc /> /// <inheritdoc />
[CsvIndex(0)] [CsvIndex(0)]
[CsvIgnore(false)] [CsvIgnore(false)]
[CsvName(nameof(Ln.项名))] [CsvName(nameof(Ln.项名))]
public override string Key { get; init; } public override string Key { get; init; }
/// <inheritdoc />
[CsvIndex(4)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.备注))]
public override string Summary { get; init; }
/// <inheritdoc /> /// <inheritdoc />
[CsvIndex(1)] [CsvIndex(1)]
[CsvIgnore(false)] [CsvIgnore(false)]

View File

@ -13,10 +13,18 @@ public record QueryDicContentRsp : Sys_DicContent
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; } public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; }
/// <inheritdoc cref="Sys_DicContent.Key" /> /// <inheritdoc cref="Sys_DicContent.Key" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Key { get; init; } public override string Key { get; init; }
/// <inheritdoc cref="Sys_DicContent.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
/// <inheritdoc cref="Sys_DicContent.Value" /> /// <inheritdoc cref="Sys_DicContent.Value" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Value { get; init; } public override string Value { get; init; }

View File

@ -0,0 +1,15 @@
namespace NetAdmin.Domain.Dto.Sys.Dic.Content;
/// <summary>
/// 请求:设置字典内容启用状态
/// </summary>
public sealed record SetDicContentEnabledReq : Sys_DicContent
{
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -19,8 +19,7 @@ public record CreateJobReq : Sys_Job
public override string ExecutionCron { get; init; } public override string ExecutionCron { get; init; }
/// <inheritdoc cref="Sys_Job.HttpMethod" /> /// <inheritdoc cref="Sys_Job.HttpMethod" />
[EnumDataType(typeof(HttpMethods), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(HttpMethods), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求方法不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override HttpMethods HttpMethod { get; init; } public override HttpMethods HttpMethod { get; init; }

View File

@ -15,8 +15,7 @@ public record QueryJobRsp : Sys_Job
/// Cron 表达式描述 /// Cron 表达式描述
/// </summary> /// </summary>
[JsonInclude] [JsonInclude]
public string CronDescription => public string CronDescription => ExpressionDescriptor.GetDescription(ExecutionCron, new Options { Locale = "zh-CN" });
ExpressionDescriptor.GetDescription(ExecutionCron, new Options { Locale = "zh-CN" });
/// <inheritdoc cref="Sys_Job.LastStatusCode" /> /// <inheritdoc cref="Sys_Job.LastStatusCode" />
[JsonInclude] [JsonInclude]

View File

@ -15,8 +15,7 @@ public sealed record MetaInfo : DataAbstraction
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MetaInfo" /> class. /// Initializes a new instance of the <see cref="MetaInfo" /> class.
/// </summary> /// </summary>
public MetaInfo(string color, bool fullPage, bool hidden, bool hiddenBreadCrumb, string icon, string tag public MetaInfo(string color, bool fullPage, bool hidden, bool hiddenBreadCrumb, string icon, string tag, string title, MenuTypes type)
, string title, MenuTypes type)
{ {
Color = color; Color = color;
FullPage = fullPage; FullPage = fullPage;
@ -73,8 +72,7 @@ public sealed record MetaInfo : DataAbstraction
/// <summary> /// <summary>
/// 类型 /// 类型
/// </summary> /// </summary>
[EnumDataType(typeof(MenuTypes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(MenuTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.菜单类型不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonInclude] [JsonInclude]
public MenuTypes Type { get; init; } public MenuTypes Type { get; init; }
} }

View File

@ -18,8 +18,7 @@ public record CreateRoleReq : Sys_Role, IValidatableObject
public override string DashboardLayout { get; set; } public override string DashboardLayout { get; set; }
/// <inheritdoc cref="Sys_Role.DataScope" /> /// <inheritdoc cref="Sys_Role.DataScope" />
[EnumDataType(typeof(DataScopes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(DataScopes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色数据范围不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
public override DataScopes DataScope { get; init; } = DataScopes.All; public override DataScopes DataScope { get; init; } = DataScopes.All;
/// <summary> /// <summary>

View File

@ -20,8 +20,7 @@ public record CreateSiteMsgReq : Sys_SiteMsg
public IReadOnlyCollection<long> DeptIds { get; init; } public IReadOnlyCollection<long> DeptIds { get; init; }
/// <inheritdoc cref="Sys_SiteMsg.MsgType" /> /// <inheritdoc cref="Sys_SiteMsg.MsgType" />
[EnumDataType(typeof(SiteMsgTypes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(SiteMsgTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.站内信类型不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override SiteMsgTypes MsgType { get; init; } public override SiteMsgTypes MsgType { get; init; }

View File

@ -12,8 +12,7 @@ public record CreateSiteMsgFlagReq : Sys_SiteMsgFlag
public override long SiteMsgId { get; init; } public override long SiteMsgId { get; init; }
/// <inheritdoc cref="Sys_SiteMsgFlag.UserSiteMsgStatus" /> /// <inheritdoc cref="Sys_SiteMsgFlag.UserSiteMsgStatus" />
[EnumDataType(typeof(UserSiteMsgStatues), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(UserSiteMsgStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.站内信状态不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override UserSiteMsgStatues UserSiteMsgStatus { get; init; } public override UserSiteMsgStatues UserSiteMsgStatus { get; init; }
} }

View File

@ -0,0 +1,12 @@
namespace NetAdmin.Domain.Dto.Sys.Tool;
/// <summary>
/// 请求Aes解密
/// </summary>
public record AesDecodeReq : DataAbstraction
{
/// <summary>
/// 密文
/// </summary>
public string CipherText { get; init; }
}

View File

@ -16,6 +16,14 @@ public record QueryUserRsp : Sys_User
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; } public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? CreatedUserId { get; init; }
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string CreatedUserName { get; init; }
/// <inheritdoc cref="Sys_User.Dept" /> /// <inheritdoc cref="Sys_User.Dept" />
public new virtual QueryDeptRsp Dept { get; init; } public new virtual QueryDeptRsp Dept { get; init; }

View File

@ -17,8 +17,7 @@ public record CreateUserProfileReq : Sys_UserProfile
public override string CertificateNumber { get; init; } public override string CertificateNumber { get; init; }
/// <inheritdoc cref="Sys_UserProfile.CertificateType" /> /// <inheritdoc cref="Sys_UserProfile.CertificateType" />
[EnumDataType(typeof(CertificateTypes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(CertificateTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.证件类型不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override CertificateTypes? CertificateType { get; init; } public override CertificateTypes? CertificateType { get; init; }
@ -39,8 +38,7 @@ public record CreateUserProfileReq : Sys_UserProfile
public override string CompanyTelephone { get; init; } public override string CompanyTelephone { get; init; }
/// <inheritdoc cref="Sys_UserProfile.Education" /> /// <inheritdoc cref="Sys_UserProfile.Education" />
[EnumDataType(typeof(Educations), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(Educations), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.学历不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override Educations? Education { get; init; } public override Educations? Education { get; init; }
@ -82,8 +80,7 @@ public record CreateUserProfileReq : Sys_UserProfile
public override string HomeTelephone { get; init; } public override string HomeTelephone { get; init; }
/// <inheritdoc cref="Sys_UserProfile.MarriageStatus" /> /// <inheritdoc cref="Sys_UserProfile.MarriageStatus" />
[EnumDataType(typeof(MarriageStatues), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(MarriageStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.婚姻状况不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override MarriageStatues? MarriageStatus { get; init; } public override MarriageStatues? MarriageStatus { get; init; }
@ -96,8 +93,7 @@ public record CreateUserProfileReq : Sys_UserProfile
public new CreateDicContentReq NationArea { get; init; } public new CreateDicContentReq NationArea { get; init; }
/// <inheritdoc cref="Sys_UserProfile.PoliticalStatus" /> /// <inheritdoc cref="Sys_UserProfile.PoliticalStatus" />
[EnumDataType(typeof(PoliticalStatues), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(PoliticalStatues), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.政治面貌不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override PoliticalStatues? PoliticalStatus { get; init; } public override PoliticalStatues? PoliticalStatus { get; init; }

View File

@ -14,8 +14,7 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
public override string DestDevice { get; init; } public override string DestDevice { get; init; }
/// <inheritdoc cref="Sys_VerifyCode.DeviceType" /> /// <inheritdoc cref="Sys_VerifyCode.DeviceType" />
[EnumDataType(typeof(VerifyCodeDeviceTypes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(VerifyCodeDeviceTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码目标设备类型不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.设备类型不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.设备类型不能为空))]
public override VerifyCodeDeviceTypes DeviceType { get; init; } public override VerifyCodeDeviceTypes DeviceType { get; init; }
@ -24,8 +23,7 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
public override VerifyCodeStatues Status => VerifyCodeStatues.Waiting; public override VerifyCodeStatues Status => VerifyCodeStatues.Waiting;
/// <inheritdoc cref="Sys_VerifyCode.Type" /> /// <inheritdoc cref="Sys_VerifyCode.Type" />
[EnumDataType(typeof(VerifyCodeTypes), ErrorMessageResourceType = typeof(Ln) [EnumDataType(typeof(VerifyCodeTypes), ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不正确))]
, ErrorMessageResourceName = nameof(Ln.))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型不能为空))]
public override VerifyCodeTypes Type { get; init; } public override VerifyCodeTypes Type { get; init; }
@ -43,22 +41,20 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
switch (DeviceType) { switch (DeviceType) {
case VerifyCodeDeviceTypes.Email: case VerifyCodeDeviceTypes.Email:
validationResult = new EmailAttribute().GetValidationResult(DestDevice, validationContext); validationResult = new EmailAttribute().GetValidationResult(DestDevice, validationContext);
if (validationResult == null) {
yield break;
}
yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) });
break; break;
case VerifyCodeDeviceTypes.Mobile: case VerifyCodeDeviceTypes.Mobile:
validationResult = new MobileAttribute().GetValidationResult(DestDevice, validationContext); validationResult = new MobileAttribute().GetValidationResult(DestDevice, validationContext);
if (validationResult == null) {
yield break;
}
yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) });
break; break;
default: default:
yield break; yield break;
} }
if (validationResult == null) {
yield break;
}
yield return new ValidationResult(validationResult.ErrorMessage, [nameof(DestDevice)]);
} }
} }

View File

@ -17,7 +17,6 @@ public sealed record SyncStructureAfterEvent : SyncStructureBeforeEvent
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln. return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln., string.Join(',', EntityTypes.Select(x => x.Name)));
, string.Join(',', EntityTypes.Select(x => x.Name)));
} }
} }

View File

@ -10,8 +10,8 @@ public sealed record RequestLogEvent : DataAbstraction, IEventSourceGeneric<Crea
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestLogEvent" /> class. /// Initializes a new instance of the <see cref="RequestLogEvent" /> class.
/// </summary> /// </summary>
public RequestLogEvent(CreateRequestLogReq data, bool isConsumOnce = false, object payload = default public RequestLogEvent(CreateRequestLogReq data, bool isConsumOnce = false, object payload = default, DateTime createdTime = default
, DateTime createdTime = default, CancellationToken cancellationToken = default) , CancellationToken cancellationToken = default)
{ {
Data = data; Data = data;
IsConsumOnce = isConsumOnce; IsConsumOnce = isConsumOnce;

View File

@ -10,8 +10,8 @@ public sealed record UserUpdatedEvent : DataAbstraction, IEventSourceGeneric<Use
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserUpdatedEvent" /> class. /// Initializes a new instance of the <see cref="UserUpdatedEvent" /> class.
/// </summary> /// </summary>
public UserUpdatedEvent(UserInfoRsp data, DateTime createdTime = default, bool isConsumOnce = false public UserUpdatedEvent(UserInfoRsp data, DateTime createdTime = default, bool isConsumOnce = false, object payload = default
, object payload = default, CancellationToken cancellationToken = default) , CancellationToken cancellationToken = default)
{ {
Data = data; Data = data;
CancellationToken = cancellationToken; CancellationToken = cancellationToken;

View File

@ -10,8 +10,8 @@ public sealed record VerifyCodeCreatedEvent : DataAbstraction, IEventSourceGener
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="VerifyCodeCreatedEvent" /> class. /// Initializes a new instance of the <see cref="VerifyCodeCreatedEvent" /> class.
/// </summary> /// </summary>
public VerifyCodeCreatedEvent(QueryVerifyCodeRsp data, DateTime createdTime = default, bool isConsumOnce = false public VerifyCodeCreatedEvent(QueryVerifyCodeRsp data, DateTime createdTime = default, bool isConsumOnce = false, object payload = default
, object payload = default, CancellationToken cancellationToken = default) , CancellationToken cancellationToken = default)
{ {
Data = data; Data = data;
CancellationToken = cancellationToken; CancellationToken = cancellationToken;

View File

@ -67,11 +67,9 @@ public abstract class WorkBase<TLogger>
{ {
var db = ServiceProvider.GetService<IConnectionMultiplexer>() var db = ServiceProvider.GetService<IConnectionMultiplexer>()
.GetDatabase(ServiceProvider.GetService<IOptions<RedisOptions>>() .GetDatabase(ServiceProvider.GetService<IOptions<RedisOptions>>()
.Value.Instances .Value.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE)
.Database); .Database);
return RedisLocker.GetLockerAsync(db, lockId, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY) return RedisLocker.GetLockerAsync(db, lockId, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
, Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK
, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY)); , TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY));
} }
} }

View File

@ -8,6 +8,7 @@ namespace NetAdmin.Host.Controllers;
/// 探针组件 /// 探针组件
/// </summary> /// </summary>
[ApiDescriptionSettings("Probe")] [ApiDescriptionSettings("Probe")]
[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)]
public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, IService>, IService> public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, IService>, IService>
{ {
/// <summary> /// <summary>
@ -55,12 +56,7 @@ public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, I
public IActionResult IsSystemSafetyStopped(int logTimeoutSeconds = 15) public IActionResult IsSystemSafetyStopped(int logTimeoutSeconds = 15)
#pragma warning restore S3400, CA1822 #pragma warning restore S3400, CA1822
{ {
return new ContentResult { return new ContentResult { Content = (DateTime.Now - GlobalStatic.LatestLogTime).TotalSeconds > logTimeoutSeconds ? "1" : "0" };
Content = (DateTime.Now - GlobalStatic.LatestLogTime).TotalSeconds >
logTimeoutSeconds
? "1"
: "0"
};
} }
/// <summary> /// <summary>
@ -82,4 +78,21 @@ public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, I
SafetyShopHostMiddleware.Stop(); SafetyShopHostMiddleware.Stop();
return new OkResult(); return new OkResult();
} }
/// <summary>
/// 停止日志计数器
/// </summary>
[AllowAnonymous]
[HttpGet]
#pragma warning disable CA1822
public ActionResult StopLogCounter(string token)
#pragma warning restore CA1822
{
if (token != GlobalStatic.SecretKey) {
return new UnauthorizedResult();
}
GlobalStatic.LogCounterOff = true;
return new OkResult();
}
} }

View File

@ -17,23 +17,17 @@ public static class IMvcBuilderExtensions
public static IMvcBuilder AddDefaultApiResultHandler(this IMvcBuilder me) public static IMvcBuilder AddDefaultApiResultHandler(this IMvcBuilder me)
{ {
return me.AddInjectWithUnifyResult<DefaultApiResultHandler>(injectOptions => { return me.AddInjectWithUnifyResult<DefaultApiResultHandler>(injectOptions => {
injectOptions.ConfigureSwaggerGen( injectOptions.ConfigureSwaggerGen(genOptions => {
genOptions => {
// 替换自定义的EnumSchemaFilter支持多语言Resx资源 需将SpecificationDocumentSettings.EnableEnumSchemaFilter配置为false) // 替换自定义的EnumSchemaFilter支持多语言Resx资源 需将SpecificationDocumentSettings.EnableEnumSchemaFilter配置为false)
genOptions genOptions.SchemaFilter<SwaggerEnumSchemaFixer>();
.SchemaFilter<
SwaggerEnumSchemaFixer>(); // 枚举显示自身xml comment 而不是$ref原型引用
genOptions.UseInlineDefinitionsForEnums();
// 将程序集版本号与OpenApi版本号同步 // 将程序集版本号与OpenApi版本号同步
foreach (var doc in genOptions foreach (var doc in genOptions.SwaggerGeneratorOptions.SwaggerDocs) {
.SwaggerGeneratorOptions doc.Value.Version = FileVersionInfo
.SwaggerDocs) { .GetVersionInfo(Assembly.GetEntryAssembly()!.Location)
doc.Value.Version
= FileVersionInfo
.GetVersionInfo(
Assembly
.GetEntryAssembly()!
.Location)
.ProductVersion; .ProductVersion;
} }
}); });

View File

@ -12,8 +12,7 @@ public static class MethodInfoExtensions
{ {
return serviceProvider.GetService<IActionDescriptorCollectionProvider>() return serviceProvider.GetService<IActionDescriptorCollectionProvider>()
.ActionDescriptors.Items.FirstOrDefault(x => x.DisplayName!.StartsWith( // .ActionDescriptors.Items.FirstOrDefault(x => x.DisplayName!.StartsWith( //
$"{me.DeclaringType}.{me.Name}" $"{me.DeclaringType}.{me.Name}", StringComparison.Ordinal))
, StringComparison.Ordinal))
?.AttributeRouteInfo?.Template; ?.AttributeRouteInfo?.Template;
} }
} }

View File

@ -90,8 +90,8 @@ public static class ServiceCollectionExtensions
var sbLog = new StringBuilder(); var sbLog = new StringBuilder();
foreach (var type in optionsTypes) { foreach (var type in optionsTypes) {
var configureMethod = typeof(ConfigurableOptionsServiceCollectionExtensions).GetMethod( var configureMethod = typeof(ConfigurableOptionsServiceCollectionExtensions).GetMethod(
nameof(ConfigurableOptionsServiceCollectionExtensions.AddConfigurableOptions) nameof(ConfigurableOptionsServiceCollectionExtensions.AddConfigurableOptions), BindingFlags.Public | BindingFlags.Static
, BindingFlags.Public | BindingFlags.Static, [typeof(IServiceCollection)]); , [typeof(IServiceCollection)]);
_ = configureMethod!.MakeGenericMethod(type).Invoke(me, [me]); _ = configureMethod!.MakeGenericMethod(type).Invoke(me, [me]);
_ = sbLog.Append(CultureInfo.InvariantCulture, $" {type.Name}"); _ = sbLog.Append(CultureInfo.InvariantCulture, $" {type.Name}");
} }
@ -146,36 +146,32 @@ public static class ServiceCollectionExtensions
/// 添加 freeSql orm工具 /// 添加 freeSql orm工具
/// </summary> /// </summary>
public static IServiceCollection AddFreeSql( // public static IServiceCollection AddFreeSql( //
this IServiceCollection me, FreeSqlInitMethods initMethods = FreeSqlInitMethods.None this IServiceCollection me, FreeSqlInitMethods initMethods = FreeSqlInitMethods.None, Action<IFreeSql> freeSqlConfig = null)
, Action<IFreeSql> freeSqlConfig = null)
{ {
// // 非调试模式下禁止同步数据库 // // 非调试模式下禁止同步数据库
// #if !DEBUG // #if !DEBUG
// initOptions = FreeSqlInitOptions.None; // initOptions = FreeSqlInitOptions.None;
// #endif // #endif
var freeSql = new FreeSqlBuilder(App.GetOptions<DatabaseOptions>()).Build(initMethods); var dbOptions = App.GetOptions<DatabaseOptions>();
_ = me.AddSingleton(freeSql); var fSql = new FreeSqlBuilder(dbOptions).Build(initMethods);
_ = me.AddSingleton(fSql);
freeSql.Aop.AuditValue += SqlAuditor.DataAuditHandler; // Insert/Update自动值处理 fSql.Aop.AuditValue += SqlAuditor.DataAuditHandler; // Insert/Update自动值处理
var eventPublisher = App.GetService<IEventPublisher>(); var eventPublisher = App.GetService<IEventPublisher>();
#pragma warning disable VSTHRD110 #pragma warning disable VSTHRD110
// AOP事件发布异步 // AOP事件发布异步
freeSql.Aop.CommandBefore fSql.Aop.CommandBefore += (_, e) => eventPublisher.PublishAsync(new SqlCommandBeforeEvent(e)); // 增删查改,执行命令之前触发
+= (_, e) => eventPublisher.PublishAsync(new SqlCommandBeforeEvent(e)); // 增删查改,执行命令之前触发 fSql.Aop.CommandAfter += (_, e) => eventPublisher.PublishAsync(new SqlCommandAfterEvent(e)); // 增删查改,执行命令完成后触发
freeSql.Aop.CommandAfter
+= (_, e) => eventPublisher.PublishAsync(new SqlCommandAfterEvent(e)); // 增删查改,执行命令完成后触发
freeSql.Aop.SyncStructureBefore += (_, e) => fSql.Aop.SyncStructureBefore += (_, e) => eventPublisher.PublishAsync(new SyncStructureBeforeEvent(e)); // CodeFirst迁移执行之前触发
eventPublisher.PublishAsync(new SyncStructureBeforeEvent(e)); // CodeFirst迁移执行之前触发
freeSql.Aop.SyncStructureAfter += (_, e) => fSql.Aop.SyncStructureAfter += (_, e) => eventPublisher.PublishAsync(new SyncStructureAfterEvent(e)); // CodeFirst迁移执行完成触发
eventPublisher.PublishAsync(new SyncStructureAfterEvent(e)); // CodeFirst迁移执行完成触发
#pragma warning restore VSTHRD110 #pragma warning restore VSTHRD110
// 全局过滤器设置 // 全局过滤器设置
freeSqlConfig?.Invoke(freeSql); freeSqlConfig?.Invoke(fSql);
return me.AddScoped<UnitOfWorkManager>() // 注入工作单元管理器 return me.AddScoped<UnitOfWorkManager>() // 注入工作单元管理器
.AddFreeRepository(null, App.Assemblies.ToArray()) // 批量注入 Repository .AddFreeRepository(null, App.Assemblies.ToArray()) // 批量注入 Repository
@ -209,8 +205,7 @@ public static class ServiceCollectionExtensions
/// </summary> /// </summary>
public static IServiceCollection AddRedisCache(this IServiceCollection me) public static IServiceCollection AddRedisCache(this IServiceCollection me)
{ {
var redisOptions = App.GetOptions<RedisOptions>() var redisOptions = App.GetOptions<RedisOptions>().Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE);
.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE);
// IDistributedCache 分布式缓存通用接口 // IDistributedCache 分布式缓存通用接口
_ = me.AddStackExchangeRedisCache(options => { _ = me.AddStackExchangeRedisCache(options => {

View File

@ -64,8 +64,7 @@ public abstract class ApiResultHandler<T>
{ {
SetErrorCodeToHeader(context.HttpContext, ErrorCodes.InvalidInput); SetErrorCodeToHeader(context.HttpContext, ErrorCodes.InvalidInput);
return new JsonResult(RestfulResult(ErrorCodes.InvalidInput, metadata.Data return new JsonResult(RestfulResult(ErrorCodes.InvalidInput, metadata.Data, GetValidationResult(metadata.ValidationResult))) {
, GetValidationResult(metadata.ValidationResult))) {
StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL
}; };
} }

View File

@ -16,8 +16,7 @@ public sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logge
} }
// 将异常设置到HttpContext.Features中 以便中间件能获取到他 // 将异常设置到HttpContext.Features中 以便中间件能获取到他
context.HttpContext.Features.Set<IExceptionHandlerFeature>( context.HttpContext.Features.Set<IExceptionHandlerFeature>(new ExceptionHandlerFeature { Error = context.Exception });
new ExceptionHandlerFeature { Error = context.Exception });
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -13,8 +13,7 @@ public sealed class TransactionInterceptor(UnitOfWorkManager uowManager) : IAsyn
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{ {
// 跳过没有事务特性标记的方法 // 跳过没有事务特性标记的方法
if (context.HttpContext.GetControllerActionDescriptor().MethodInfo.GetCustomAttribute<TransactionAttribute>() == if (context.HttpContext.GetControllerActionDescriptor().MethodInfo.GetCustomAttribute<TransactionAttribute>() == null) {
null) {
_ = await next().ConfigureAwait(false); _ = await next().ConfigureAwait(false);
return; return;
} }

View File

@ -10,11 +10,9 @@ public sealed class RequestAuditMiddleware(
, IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions , IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions
, RequestLogger requestLogger) , RequestLogger requestLogger)
{ {
private readonly PathString _defaultRoutePrefix private readonly PathString _defaultRoutePrefix = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
private readonly PathString _healthCheckRoutePrefix private readonly PathString _healthCheckRoutePrefix = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/probe/health.check");
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/probe/health.check");
/// <summary> /// <summary>
/// 主函数 /// 主函数
@ -25,8 +23,7 @@ public sealed class RequestAuditMiddleware(
if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求 if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求
|| context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查 || context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查
|| context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS // is options 请求 || context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS // is options 请求
|| (context.Request.ContentType?.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) ?? || (context.Request.ContentType?.StartsWith("multipart/form-data", true, CultureInfo.InvariantCulture) ?? false) // 文件上传
false) // 文件上传
#pragma warning disable SA1009 #pragma warning disable SA1009
) { ) {
#pragma warning restore SA1009 #pragma warning restore SA1009
@ -58,8 +55,6 @@ public sealed class RequestAuditMiddleware(
.FirstOrDefault() .FirstOrDefault()
?.Enum<ErrorCodes>() ?? 0; ?.Enum<ErrorCodes>() ?? 0;
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode _ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode, exception).ConfigureAwait(false);
, exception)
.ConfigureAwait(false);
} }
} }

View File

@ -53,8 +53,8 @@ public sealed class SafetyShopHostMiddleware(RequestDelegate next)
/// </summary> /// </summary>
public async Task InvokeAsync(HttpContext context) public async Task InvokeAsync(HttpContext context)
{ {
if (Volatile.Read(ref _trafficOff) && if (Volatile.Read(ref _trafficOff) && !context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_RPOBE}") &&
!context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_RPOBE}")) { !context.Request.Path.StartsWithSegments($"/{Chars.FLG_PATH_API_METRICS}")) {
context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable; context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
return; return;
} }

View File

@ -4,7 +4,7 @@
<ProjectReference Include="../NetAdmin.Cache/NetAdmin.Cache.csproj"/> <ProjectReference Include="../NetAdmin.Cache/NetAdmin.Cache.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns2"/> <PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns3"/>
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.179"/> <PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.179"/>
<PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/> <PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/>
</ItemGroup> </ItemGroup>

View File

@ -29,9 +29,7 @@ public abstract class Startup : AppStartup
private static void ShowBanner() private static void ShowBanner()
{ {
AnsiConsole.WriteLine(); AnsiConsole.WriteLine();
var gridInfo = new Grid().AddColumn(new GridColumn().NoWrap().Width(50).PadRight(10)) var gridInfo = new Grid().AddColumn(new GridColumn().NoWrap().Width(50).PadRight(10)).AddColumn(new GridColumn().NoWrap()).Expand();
.AddColumn(new GridColumn().NoWrap())
.Expand();
foreach (var kv in ApplicationHelper.GetEnvironmentInfo().OrderBy(x => x.Key)) { foreach (var kv in ApplicationHelper.GetEnvironmentInfo().OrderBy(x => x.Key)) {
_ = gridInfo.AddRow(kv.Key, kv.Value.ToString()!.EscapeMarkup()); _ = gridInfo.AddRow(kv.Key, kv.Value.ToString()!.EscapeMarkup());
} }

View File

@ -38,10 +38,7 @@ public sealed class CollectionJsonTypeInfoResolver : DefaultJsonTypeInfoResolver
private static string GetMemberName(JsonPropertyInfo property) private static string GetMemberName(JsonPropertyInfo property)
{ {
return property.GetType() return property.GetType().GetRuntimeProperties().First(x => x.Name == "MemberName").GetValue(property) as string;
.GetRuntimeProperties()
.First(x => x.Name == "MemberName")
.GetValue(property) as string;
} }
/// <summary> /// <summary>
@ -49,10 +46,7 @@ public sealed class CollectionJsonTypeInfoResolver : DefaultJsonTypeInfoResolver
/// </summary> /// </summary>
private static PropertyInfo GetNewProperty(string memberName, object obj) private static PropertyInfo GetNewProperty(string memberName, object obj)
{ {
return obj.GetType() return obj.GetType().GetProperties().Where(x => x.Name == memberName).First(x => x.DeclaringType == x.ReflectedType);
.GetProperties()
.Where(x => x.Name == memberName)
.First(x => x.DeclaringType == x.ReflectedType);
} }
/// <summary> /// <summary>

View File

@ -17,15 +17,14 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
/// <summary> /// <summary>
/// 生成审计数据 /// 生成审计数据
/// </summary> /// </summary>
public async Task<CreateRequestLogReq> LogAsync(HttpContext context, long duration, string responseBody public async Task<CreateRequestLogReq> LogAsync(HttpContext context, long duration, string responseBody, ErrorCodes errorCode
, ErrorCodes errorCode, IExceptionHandlerFeature exception) , IExceptionHandlerFeature exception)
{ {
// 从请求头中读取用户信息 // 从请求头中读取用户信息
var associatedUser = GetAssociatedUser(context); var associatedUser = GetAssociatedUser(context);
var id = YitIdHelper.NextId(); var id = YitIdHelper.NextId();
var requestBody = Array.Exists( // var requestBody = Array.Exists( //
_textContentTypes _textContentTypes, x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
, x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
? await context.ReadBodyContentAsync().ConfigureAwait(false) ? await context.ReadBodyContentAsync().ConfigureAwait(false)
: string.Empty; : string.Empty;
var apiId = context.Request.Path.Value!.TrimStart('/'); var apiId = context.Request.Path.Value!.TrimStart('/');

View File

@ -29,10 +29,14 @@ public sealed class SwaggerEnumSchemaFixer : ISchemaFilter
foreach (var e in Enum.GetValues(context.Type).Cast<Enum>()) { foreach (var e in Enum.GetValues(context.Type).Cast<Enum>()) {
var value = Convert.ToInt64(e, CultureInfo.InvariantCulture); var value = Convert.ToInt64(e, CultureInfo.InvariantCulture);
schema.Enum.Add(new OpenApiLong(value)); schema.Enum.Add(new OpenApiLong(value));
var enumName = Enum.GetName(context.Type, e).ToLowerCamelCase();
if (enumName.Length <= 3) {
enumName = enumName.ToLowerInvariant();
}
_ = sb.Append(wrap) _ = sb.Append(wrap)
.Append( // .Append( //
CultureInfo.InvariantCulture CultureInfo.InvariantCulture, $"{enumName} = {value} ({e.ResDesc<Ln>()})");
, $"{Enum.GetName(context.Type, e).ToLowerCamelCase()} = {value} ({e.ResDesc<Ln>()})");
} }
schema.Description = sb.ToString(); schema.Description = sb.ToString();

View File

@ -13,8 +13,7 @@ public sealed record CaptchaOptions : OptionAbstraction
{ {
var rtn = new char[32]; var rtn = new char[32];
for (var i = 0; i != 32; i++) { for (var i = 0; i != 32; i++) {
rtn[i] = Chars.FLGL_VISIBLE_ASCIIS[ rtn[i] = Chars.FLGL_VISIBLE_ASCIIS[(int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLGL_VISIBLE_ASCIIS.Length)];
(int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLGL_VISIBLE_ASCIIS.Length)];
} }
SecretKey = new string(rtn); SecretKey = new string(rtn);

View File

@ -73,6 +73,7 @@ public static class Chars
public const string FLG_HTTP_METHOD_POST = "POST"; public const string FLG_HTTP_METHOD_POST = "POST";
public const string FLG_HTTP_METHOD_PUT = "PUT"; public const string FLG_HTTP_METHOD_PUT = "PUT";
public const string FLG_HTTP_METHOD_TRACE = "TRACE"; public const string FLG_HTTP_METHOD_TRACE = "TRACE";
public const string FLG_PATH_API_METRICS = "metrics";
public const string FLG_PATH_API_RPOBE = "api/probe"; public const string FLG_PATH_API_RPOBE = "api/probe";
public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd"; public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd";
@ -89,8 +90,7 @@ public static class Chars
public const string FLGL_HTTP_HEADER_VALUE_UA_PC public const string FLGL_HTTP_HEADER_VALUE_UA_PC
= "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"; = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
public const string FLGL_VISIBLE_ASCIIS public const string FLGL_VISIBLE_ASCIIS = """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
= """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$"; public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$";
public const string RGX_INVITE_CODE = """^\d{8}$"""; public const string RGX_INVITE_CODE = """^\d{8}$""";
@ -112,6 +112,5 @@ public static class Chars
public const string RGXL_EMAIL public const string RGXL_EMAIL
= """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$"""; = """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$""";
public const string RGXL_IP_V4 public const string RGXL_IP_V4 = @"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$";
= @"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$";
} }

View File

@ -23,7 +23,7 @@ public static class Numbers
public const int MAX_LIMIT_QUERY_PAGE_SIZE = 100; // 最大限制:分页查询页容量 public const int MAX_LIMIT_QUERY_PAGE_SIZE = 100; // 最大限制:分页查询页容量
public const int MAX_LIMIT_RETRY_CNT_REDIS_LOCK = 10; // 最大限制Redis锁重试次数 public const int MAX_LIMIT_RETRY_CNT_REDIS_LOCK = 10; // 最大限制Redis锁重试次数
public const int REQUEST_LOG_BUFF_SIZE = 10; // 请求日志缓冲区大小 public const int REQUEST_LOG_BUFF_SIZE = 10; // 请求日志缓冲区大小
public const int SCHEDULED_JOB_PARALLEL_NUM = 5; // 计划作业并发数
public const int SECS_CACHE_CHART = 300; // 秒:缓存时间-仪表 public const int SECS_CACHE_CHART = 300; // 秒:缓存时间-仪表
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认 public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码 public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码

View File

@ -10,8 +10,7 @@ public static class HttpRequestPartExtensions
/// <summary> /// <summary>
/// 设置日志 /// 设置日志
/// </summary> /// </summary>
public static HttpRequestPart SetLog<T>(this HttpRequestPart me, ILogger<T> logger public static HttpRequestPart SetLog<T>(this HttpRequestPart me, ILogger<T> logger, Func<string, string> bodyHandle = null)
, Func<string, string> bodyHandle = null)
{ {
return me.OnRequesting(RequestHandleAsync).OnResponsing(ResponseHandleAsync).OnException(ExceptionHandleAsync); return me.OnRequesting(RequestHandleAsync).OnResponsing(ResponseHandleAsync).OnException(ExceptionHandleAsync);

View File

@ -8,8 +8,7 @@ public static class HttpResponseMessageExtensions
/// <summary> /// <summary>
/// 记录日志 /// 记录日志
/// </summary> /// </summary>
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger, Func<string, string> bodyPreHandle = null)
, Func<string, string> bodyPreHandle = null)
{ {
logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}"); logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}");
} }
@ -30,10 +29,7 @@ public static class HttpResponseMessageExtensions
this HttpResponseMessage me, Func<string, string> bodyHandle = null) this HttpResponseMessage me, Func<string, string> bodyHandle = null)
{ {
var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false); var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false);
return new { return new { Header = me?.ToString(), RequestHeader = me?.RequestMessage?.Headers, Body = bodyHandle is null ? body : bodyHandle(body) }
Header = me?.ToString() .Json();
, RequestHeader = me?.RequestMessage?.Headers
, Body = bodyHandle is null ? body : bodyHandle(body)
}.Json();
} }
} }

View File

@ -1,3 +1,4 @@
using System.Numerics;
using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting;
@ -8,8 +9,80 @@ namespace NetAdmin.Infrastructure.Extensions;
/// </summary> /// </summary>
public static class StringExtensions public static class StringExtensions
{ {
private const string _CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static readonly Regex _regexIpV4 = new(Chars.RGXL_IP_V4); private static readonly Regex _regexIpV4 = new(Chars.RGXL_IP_V4);
/// <summary>
/// 将指定的输入字符串进行Base62解码
/// </summary>
/// <exception cref="ArgumentException">ArgumentException</exception>
public static string Base62Decode(this string me)
{
BigInteger result = 0;
foreach (var index in me.Select(c => _CHARACTERS.IndexOf(c))) {
if (index < 0) {
throw new ArgumentException("Invalid character in Base62 string.");
}
#pragma warning disable IDE0048, RCS1123, SA1407
result = result * 62 + index;
#pragma warning restore SA1407, RCS1123, IDE0048
}
// Convert BigInteger back to byte array and then to string
var bytes = result.ToByteArray();
// Handle the sign bit
if (bytes[^1] == 0) {
Array.Resize(ref bytes, bytes.Length - 1);
}
return Encoding.UTF8.GetString(bytes);
}
/// <summary>
/// 将指定的输入字符串进行Base62编码
/// </summary>
public static string Base62Encode(this string me)
{
// Convert string to byte array
var bytes = Encoding.UTF8.GetBytes(me);
// Convert byte array to BigInteger for easier processing
var bigInteger = new BigInteger(bytes);
if (bigInteger == 0) {
return _CHARACTERS[0].ToString();
}
var result = new StringBuilder();
while (bigInteger > 0) {
var remainder = (int)(bigInteger % 62);
bigInteger /= 62;
_ = result.Insert(0, _CHARACTERS[remainder]);
}
return result.ToString();
}
/// <summary>
/// 解码避免转义的Base64
/// </summary>
public static string Base64InUrlDecode(this string me)
{
return me.Replace("-", "+").Replace("_", "/");
}
/// <summary>
/// 编码避免转义的Base64
/// </summary>
public static string Base64InUrlEncode(this string me)
{
return me.Replace("+", "-").Replace("/", "_");
}
/// <summary> /// <summary>
/// 计算Crc32 /// 计算Crc32
/// </summary> /// </summary>
@ -21,12 +94,10 @@ public static class StringExtensions
/// <summary> /// <summary>
/// 执行C#代码 /// 执行C#代码
/// </summary> /// </summary>
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies, params string[] importNamespaces)
, params string[] importNamespaces)
{ {
// 使用 Roslyn 编译并执行代码 // 使用 Roslyn 编译并执行代码
return CSharpScript.EvaluateAsync<T>( return CSharpScript.EvaluateAsync<T>(me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
} }
/// <summary> /// <summary>

View File

@ -15,8 +15,7 @@ public static class GlobalStatic
/// <summary> /// <summary>
/// 产品版本 /// 产品版本
/// </summary> /// </summary>
public static readonly string ProductVersion public static readonly string ProductVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion;
= FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion;
private static long _latestLogTime; private static long _latestLogTime;
@ -34,14 +33,12 @@ public static class GlobalStatic
/// <summary> /// <summary>
/// 最后一次日志时间 /// 最后一次日志时间
/// </summary> /// </summary>
public static DateTime LatestLogTime => Volatile.Read(ref _latestLogTime).Time(); public static DateTime LatestLogTime => LogCounterOff ? DateTime.MinValue : Volatile.Read(ref _latestLogTime).Time();
/// <summary> /// <summary>
/// 日志记录器忽略的API编号 /// 日志记录器忽略的API编号
/// </summary> /// </summary>
public static string[] LoggerIgnoreApiIds => [ public static string[] LoggerIgnoreApiIds => ["api/adm/tools/query.es.log", "api/probe/health.check", "api/probe/is.system.safety.stopped"];
"api/adm/tools/query.es.log", "api/probe/health.check", "api/probe/is.system.safety.stopped"
];
/// <summary> /// <summary>
/// 系统内部密钥 /// 系统内部密钥
@ -88,6 +85,11 @@ public static class GlobalStatic
/// </summary> /// </summary>
public static JsonSerializerOptions JsonSerializerOptions { get; set; } public static JsonSerializerOptions JsonSerializerOptions { get; set; }
/// <summary>
/// 停止更新日志时间
/// </summary>
public static bool LogCounterOff { get; set; }
/// <summary> /// <summary>
/// 增加日志计数器 /// 增加日志计数器
/// </summary> /// </summary>

View File

@ -8,11 +8,11 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns4"/> <PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns4"/>
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns4"/> <PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns4"/>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.2"/> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.8"/>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.5.2-ns1"/> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.5.8-ns1"/>
<PackageReference Include="Furion.Pure.NS" Version="4.9.5.2-ns1"/> <PackageReference Include="Furion.Pure.NS" Version="4.9.5.8-ns1"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.10.0"/> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.11.0"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.7.24406.2"/> <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-rc.2.24474.3"/>
<PackageReference Include="Minio" Version="6.0.3"/> <PackageReference Include="Minio" Version="6.0.3"/>
<PackageReference Include="NSExt" Version="2.2.0"/> <PackageReference Include="NSExt" Version="2.2.0"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/> <PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/>

View File

@ -11,8 +11,7 @@ public static class ApplicationHelper
public static Dictionary<string, object> GetEnvironmentInfo() public static Dictionary<string, object> GetEnvironmentInfo()
{ {
var ret = typeof(Environment).GetProperties(BindingFlags.Public | BindingFlags.Static) var ret = typeof(Environment).GetProperties(BindingFlags.Public | BindingFlags.Static)
.Where(x => x.Name is not (nameof(Environment.StackTrace) .Where(x => x.Name is not (nameof(Environment.StackTrace) or nameof(Environment.NewLine)))
or nameof(Environment.NewLine)))
.ToDictionary(x => x.Name, x => x.GetValue(null)); .ToDictionary(x => x.Name, x => x.GetValue(null));
var vars = Environment.GetEnvironmentVariables(); var vars = Environment.GetEnvironmentVariables();

View File

@ -26,15 +26,13 @@ public static class CaptchaImageHelper
/// <returns> 背景图base64滑块图base64缺口坐标 </returns> /// <returns> 背景图base64滑块图base64缺口坐标 </returns>
#pragma warning disable SA1414 #pragma warning disable SA1414
public static async Task<(string BackgroundImage, string SliderImage, Point OffsetSaw)> CreateSawSliderImageAsync( public static async Task<(string BackgroundImage, string SliderImage, Point OffsetSaw)> CreateSawSliderImageAsync(
Assembly resAsm, string bgPath, string tempPath, (int, int) bgIndexScope, (int, int) tempIndexScope Assembly resAsm, string bgPath, string tempPath, (int, int) bgIndexScope, (int, int) tempIndexScope, Size sliderSize)
, Size sliderSize)
#pragma warning restore SA1414 #pragma warning restore SA1414
{ {
// 深色模板图 // 深色模板图
var templateIndex = new[] { tempIndexScope.Item1, tempIndexScope.Item2 }.Rand(); var templateIndex = new[] { tempIndexScope.Item1, tempIndexScope.Item2 }.Rand();
await using var bgStream = resAsm.GetManifestResourceStream( await using var bgStream = resAsm.GetManifestResourceStream($"{bgPath}.{new[] { bgIndexScope.Item1, bgIndexScope.Item2 }.Rand()}.jpg");
$"{bgPath}.{new[] { bgIndexScope.Item1, bgIndexScope.Item2 }.Rand()}.jpg");
await using var darkStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.dark.png"); await using var darkStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.dark.png");
await using var tranStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.transparent.png"); await using var tranStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.transparent.png");
@ -57,8 +55,7 @@ public static class CaptchaImageHelper
using var sliderBlockImage = new Image<Rgba32>(sliderSize.Width, backgroundImage.Height); using var sliderBlockImage = new Image<Rgba32>(sliderSize.Width, backgroundImage.Height);
// 随机生成拼图坐标 // 随机生成拼图坐标
var offsetRand = GeneratePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width var offsetRand = GeneratePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width, sliderSize.Height);
, sliderSize.Height);
// 根据深色模板图计算轮廓形状 // 根据深色模板图计算轮廓形状
var blockShape = CalcBlockShape(darkTemplateImage); var blockShape = CalcBlockShape(darkTemplateImage);
@ -84,16 +81,13 @@ public static class CaptchaImageHelper
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(offsetRand.X, offsetRand.Y), opacity)); backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(offsetRand.X, offsetRand.Y), opacity));
// 生成干扰图坐标 // 生成干扰图坐标
var interferencePoint = GenerateInterferencePoint(backgroundImage.Width, backgroundImage.Height var interferencePoint = GenerateInterferencePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width, sliderSize.Height
, sliderSize.Width, sliderSize.Height, offsetRand.X , offsetRand.X, offsetRand.Y);
, offsetRand.Y);
// 底图叠加深色干扰模板图 // 底图叠加深色干扰模板图
// ReSharper disable once AccessToDisposedClosure // ReSharper disable once AccessToDisposedClosure
backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y) backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y), opacity));
, opacity)); return (backgroundImage.ToBase64String(PngFormat.Instance), sliderBlockImage.ToBase64String(PngFormat.Instance), offsetRand);
return (backgroundImage.ToBase64String(PngFormat.Instance), sliderBlockImage.ToBase64String(PngFormat.Instance)
, offsetRand);
} }
private static int BuildPathList(Span<Rgba32> rowSpan, int temp, List<IPath> pathList, int y) private static int BuildPathList(Span<Rgba32> rowSpan, int temp, List<IPath> pathList, int y)
@ -133,8 +127,8 @@ public static class CaptchaImageHelper
/// <summary> /// <summary>
/// 随机生成干扰图坐标 /// 随机生成干扰图坐标
/// </summary> /// </summary>
private static Point GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth private static Point GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight, int blockX
, int templateHeight, int blockX, int blockY) , int blockY)
{ {
var x = var x =
@ -166,9 +160,7 @@ public static class CaptchaImageHelper
{ {
var widthDifference = originalWidth - templateWidth; var widthDifference = originalWidth - templateWidth;
var heightDifference = originalHeight - templateHeight; var heightDifference = originalHeight - templateHeight;
var x = widthDifference switch { var x = widthDifference switch { <= 0 => 5, _ => new[] { 0, originalWidth - templateWidth - 100 }.Rand() + 100 };
<= 0 => 5, _ => new[] { 0, originalWidth - templateWidth - 100 }.Rand() + 100
};
var y = heightDifference switch { <= 0 => 5, _ => new[] { 0, originalHeight - templateHeight - 5 }.Rand() + 5 }; var y = heightDifference switch { <= 0 => 5, _ => new[] { 0, originalHeight - templateHeight - 5 }.Rand() + 5 };

View File

@ -15,8 +15,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
{ {
var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr) var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr)
.UseGenerateCommandParameterWithLambda(true) .UseGenerateCommandParameterWithLambda(true)
.UseAutoSyncStructure( .UseAutoSyncStructure(initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
.Build(); .Build();
_ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步 _ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
return freeSql; return freeSql;
@ -90,8 +89,7 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
private void InsertSeedData(IFreeSql freeSql, IEnumerable<Type> entityTypes) private void InsertSeedData(IFreeSql freeSql, IEnumerable<Type> entityTypes)
{ {
foreach (var entityType in entityTypes) { foreach (var entityType in entityTypes) {
var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, databaseOptions.SeedDataRelativePath var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, databaseOptions.SeedDataRelativePath, $"{entityType.Name}.json");
, $"{entityType.Name}.json");
if (!File.Exists(file)) { if (!File.Exists(file)) {
continue; continue;
} }
@ -102,12 +100,8 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
fileContent, typeof(IEnumerable<>).MakeGenericType(entityType)); fileContent, typeof(IEnumerable<>).MakeGenericType(entityType));
// 如果表存在数据,跳过 // 如果表存在数据,跳过
var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes) var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes)?.MakeGenericMethod(entityType).Invoke(freeSql, null);
?.MakeGenericMethod(entityType) if (select?.GetType().GetMethod(nameof(ISelect<dynamic>.Any), 0, Type.EmptyTypes)?.Invoke(select, null) as bool? ?? true) {
.Invoke(freeSql, null);
if (select?.GetType()
.GetMethod(nameof(ISelect<dynamic>.Any), 0, Type.EmptyTypes)
?.Invoke(select, null) as bool? ?? true) {
continue; continue;
} }

View File

@ -1018,10 +1018,8 @@ public static class MimeTypeHelper
zmm application/vnd.handheld-entertainment+xml zmm application/vnd.handheld-entertainment+xml
"""; """;
private static readonly Dictionary<string, string> _mimeTypeDic = _MIME_TYPES_RAW_STRING private static readonly Dictionary<string, string> _mimeTypeDic = _MIME_TYPES_RAW_STRING.Split('\n', StringSplitOptions.RemoveEmptyEntries)
.Split( .ToDictionary( //
'\n', StringSplitOptions.RemoveEmptyEntries)
.ToDictionary(
x => x.Split(' ')[0].Trim() x => x.Split(' ')[0].Trim()
, x => x.Split(' ')[1].Trim()); , x => x.Split(' ')[1].Trim());

View File

@ -30,16 +30,15 @@ public sealed class RedisLocker : IAsyncDisposable
/// 获取锁 /// 获取锁
/// </summary> /// </summary>
/// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception> /// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception>
public static async Task<RedisLocker> GetLockerAsync(IDatabase redisDatabase, string lockerName public static async Task<RedisLocker> GetLockerAsync(IDatabase redisDatabase, string lockerName, TimeSpan lockerExpire, int retryCount
, TimeSpan lockerExpire, int retryCount, TimeSpan retryDelay) , TimeSpan retryDelay)
{ {
lockerName = $"{nameof(RedisLocker)}.{lockerName}"; lockerName = $"{nameof(RedisLocker)}.{lockerName}";
var setOk = false; var setOk = false;
for (var i = 0; i != retryCount; ++i) { for (var i = 0; i != retryCount; ++i) {
try { try {
setOk = await redisDatabase setOk = await redisDatabase
.StringSetAsync(lockerName, RedisValue.EmptyString, lockerExpire, When.NotExists .StringSetAsync(lockerName, RedisValue.EmptyString, lockerExpire, When.NotExists, CommandFlags.DemandMaster)
, CommandFlags.DemandMaster)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
catch (Exception ex) { catch (Exception ex) {
@ -60,8 +59,7 @@ public sealed class RedisLocker : IAsyncDisposable
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
try { try {
_ = await _redisDatabase.KeyDeleteAsync(_redisKey, CommandFlags.DemandMaster | CommandFlags.FireAndForget) _ = await _redisDatabase.KeyDeleteAsync(_redisKey, CommandFlags.DemandMaster | CommandFlags.FireAndForget).ConfigureAwait(false);
.ConfigureAwait(false);
} }
catch (Exception ex) { catch (Exception ex) {
LogHelper.Get<RedisLocker>().Error(ex.Message); LogHelper.Get<RedisLocker>().Error(ex.Message);

View File

@ -15,10 +15,7 @@ public sealed class UserAgentParser
, { "Opera.*?Version", "Opera" } , { "Opera.*?Version", "Opera" }
, { "Opera", "Opera" } , { "Opera", "Opera" }
, { "MSIE", "Internet Explorer" } , { "MSIE", "Internet Explorer" }
, { , { "Internet Explorer", "Internet Explorer" }
"Internet Explorer"
, "Internet Explorer"
}
, { "Trident.* rv", "Internet Explorer" } , { "Trident.* rv", "Internet Explorer" }
, { "Shiira", "Shiira" } , { "Shiira", "Shiira" }
, { "Firefox", "Firefox" } , { "Firefox", "Firefox" }
@ -73,10 +70,7 @@ public sealed class UserAgentParser
, { "benq", "BenQ" } , { "benq", "BenQ" }
, { "ipaq", "HP iPaq" } , { "ipaq", "HP iPaq" }
, { "mot-", "Motorola" } , { "mot-", "Motorola" }
, { , { "playstation portable", "PlayStation Portable" }
"playstation portable"
, "PlayStation Portable"
}
, { "playstation 3", "PlayStation 3" } , { "playstation 3", "PlayStation 3" }
, { "playstation vita", "PlayStation Vita" } , { "playstation vita", "PlayStation Vita" }
, { "hiptop", "Danger Hiptop" } , { "hiptop", "Danger Hiptop" }
@ -195,16 +189,10 @@ public sealed class UserAgentParser
, { "infoseek", "InfoSeek Robot 1.0" } , { "infoseek", "InfoSeek Robot 1.0" }
, { "lycos", "Lycos" } , { "lycos", "Lycos" }
, { "yandex", "YandexBot" } , { "yandex", "YandexBot" }
, { , { "mediapartners-google", "MediaPartners Google" }
"mediapartners-google"
, "MediaPartners Google"
}
, { "CRAZYWEBCRAWLER", "Crazy Webcrawler" } , { "CRAZYWEBCRAWLER", "Crazy Webcrawler" }
, { "adsbot-google", "AdsBot Google" } , { "adsbot-google", "AdsBot Google" }
, { , { "feedfetcher-google", "Feedfetcher Google" }
"feedfetcher-google"
, "Feedfetcher Google"
}
, { "curious george", "Curious George" } , { "curious george", "Curious George" }
, { "ia_archiver", "Alexa Crawler" } , { "ia_archiver", "Alexa Crawler" }
, { "MJ12bot", "Majestic-12" } , { "MJ12bot", "Majestic-12" }
@ -316,8 +304,7 @@ public sealed class UserAgentParser
private bool SetPlatform() private bool SetPlatform()
{ {
var kv = _platforms.FirstOrDefault(x => // var kv = _platforms.FirstOrDefault(x => //
Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}" Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}", RegexOptions.IgnoreCase));
, RegexOptions.IgnoreCase));
if (kv.Key == null) { if (kv.Key == null) {
Platform = "Unknown Platform"; Platform = "Unknown Platform";

View File

@ -17,8 +17,7 @@ public sealed class XmlCommentReader : ISingleton
public XmlCommentReader(IOptions<SpecificationDocumentSettingsOptions> specificationDocumentSettings) public XmlCommentReader(IOptions<SpecificationDocumentSettingsOptions> specificationDocumentSettings)
{ {
var xmlComments = specificationDocumentSettings.Value.XmlComments // var xmlComments = specificationDocumentSettings.Value.XmlComments //
?? App.GetConfig<SpecificationDocumentSettingsOptions>( ?? App.GetConfig<SpecificationDocumentSettingsOptions>(nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
.XmlComments; .XmlComments;
foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) { foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) {
var xmlDoc = new XmlDocument(); var xmlDoc = new XmlDocument();
@ -40,9 +39,7 @@ public sealed class XmlCommentReader : ISingleton
public string GetComments(MemberInfo memberInfo) public string GetComments(MemberInfo memberInfo)
{ {
var node = memberInfo switch { var node = memberInfo switch {
MethodInfo method => GetNodeByMethod(method) MethodInfo method => GetNodeByMethod(method), Type type => GetNodeByType(type), _ => throw new InvalidCastException()
, Type type => GetNodeByType(type)
, _ => throw new InvalidCastException()
}; };
if (node?.FirstChild?.Name != "inheritdoc") { if (node?.FirstChild?.Name != "inheritdoc") {
@ -60,9 +57,7 @@ public sealed class XmlCommentReader : ISingleton
return GetComments(methodFromBaseType); return GetComments(methodFromBaseType);
} }
var methodFromInterface = memberInfo.DeclaringType?.GetInterfaces() var methodFromInterface = memberInfo.DeclaringType?.GetInterfaces().Select(x => x.GetMethod(memberInfo.Name)).FirstOrDefault(x => x != null);
.Select(x => x.GetMethod(memberInfo.Name))
.FirstOrDefault(x => x != null);
return methodFromInterface == null ? null : GetComments(methodFromInterface); return methodFromInterface == null ? null : GetComments(methodFromInterface);
} }
@ -82,9 +77,7 @@ public sealed class XmlCommentReader : ISingleton
static string Replace(ParameterInfo parameterInfo) static string Replace(ParameterInfo parameterInfo)
{ {
return _regex.Replace(parameterInfo.ParameterType.ToString(), string.Empty) return _regex.Replace(parameterInfo.ParameterType.ToString(), string.Empty).Replace("[", "{").Replace("]", "}");
.Replace("[", "{")
.Replace("]", "}");
} }
} }

View File

@ -10,4 +10,10 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys;
public interface IDicContentModule : ICrudModule<CreateDicContentReq, QueryDicContentRsp // 创建类型 public interface IDicContentModule : ICrudModule<CreateDicContentReq, QueryDicContentRsp // 创建类型
, QueryDicContentReq, QueryDicContentRsp // 查询类型 , QueryDicContentReq, QueryDicContentRsp // 查询类型
, DelReq // 删除类型 , DelReq // 删除类型
>; >
{
/// <summary>
/// 启用/禁用字典内容
/// </summary>
Task<int> SetEnabledAsync(SetDicContentEnabledReq req);
}

View File

@ -67,7 +67,7 @@ public interface IDicModule
/// <summary> /// <summary>
/// 获取字典值 /// 获取字典值
/// </summary> /// </summary>
public Task<string> GetDicValueAsync(GetDicValueReq req); Task<string> GetDicValueAsync(GetDicValueReq req);
/// <summary> /// <summary>
/// 分页查询字典目录 /// 分页查询字典目录
@ -88,4 +88,9 @@ public interface IDicModule
/// 查询字典内容 /// 查询字典内容
/// </summary> /// </summary>
Task<IEnumerable<QueryDicContentRsp>> QueryContentAsync(QueryReq<QueryDicContentReq> req); Task<IEnumerable<QueryDicContentRsp>> QueryContentAsync(QueryReq<QueryDicContentReq> req);
/// <summary>
/// 启用/禁用字典内容
/// </summary>
Task<int> SetEnabledAsync(SetDicContentEnabledReq req);
} }

View File

@ -7,6 +7,11 @@ namespace NetAdmin.SysComponent.Application.Modules.Sys;
/// </summary> /// </summary>
public interface IToolsModule public interface IToolsModule
{ {
/// <summary>
/// Aes解密
/// </summary>
string AesDecode(AesDecodeReq req);
/// <summary> /// <summary>
/// 执行SQL语句 /// 执行SQL语句
/// </summary> /// </summary>

View File

@ -81,10 +81,7 @@ public sealed class ApiService(
public async Task<IEnumerable<QueryApiRsp>> QueryAsync(QueryReq<QueryApiReq> req) public async Task<IEnumerable<QueryApiRsp>> QueryAsync(QueryReq<QueryApiReq> req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter).ToTreeListAsync().ConfigureAwait(false);
.WhereDynamic(req.Filter)
.ToTreeListAsync()
.ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryApiRsp>>(); return ret.Adapt<IEnumerable<QueryApiRsp>>();
} }
@ -146,9 +143,7 @@ public sealed class ApiService(
Summary = xmlCommentReader.GetComments(x.MethodInfo) Summary = xmlCommentReader.GetComments(x.MethodInfo)
, Name = x.ActionName , Name = x.ActionName
, Id = id , Id = id
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>() , Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods.First()
.FirstOrDefault()
?.HttpMethods.First()
, PathCrc32 = id.Crc32() , PathCrc32 = id.Crc32()
}; };
}); });

View File

@ -63,15 +63,12 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
var server = connectionMultiplexer.GetServers()[0]; var server = connectionMultiplexer.GetServers()[0];
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database); var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
var keys = server.Keys(_redisInstance.Database, $"*{req.Keywords}*", Numbers.MAX_LIMIT_BULK_REQ) var keys = server.Keys(_redisInstance.Database, $"*{req.Keywords}*", Numbers.MAX_LIMIT_BULK_REQ).Take(Numbers.MAX_LIMIT_BULK_REQ).ToList();
.Take(Numbers.MAX_LIMIT_BULK_REQ)
.ToList();
#pragma warning restore VSTHRD103 #pragma warning restore VSTHRD103
var dic = new ConcurrentDictionary<string, (DateTime?, RedisType)>(); var dic = new ConcurrentDictionary<string, (DateTime?, RedisType)>();
await Parallel await Parallel.ForEachAsync(
.ForEachAsync(
keys keys
, async (key, _) => , async (key, _) =>
dic.TryAdd( dic.TryAdd(
@ -90,8 +87,7 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
var ret = new GetEntryRsp { var ret = new GetEntryRsp {
Type = await database.KeyTypeAsync(req.Key).ConfigureAwait(false) Type = await database.KeyTypeAsync(req.Key).ConfigureAwait(false)
, Key = req.Key , Key = req.Key
, ExpireTime = DateTime.Now + , ExpireTime = DateTime.Now + await database.KeyTimeToLiveAsync(req.Key).ConfigureAwait(false)
await database.KeyTimeToLiveAsync(req.Key).ConfigureAwait(false)
}; };
#pragma warning disable IDE0072 #pragma warning disable IDE0072
@ -101,10 +97,8 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
RedisType.String => await database.StringGetAsync(req.Key).ConfigureAwait(false) RedisType.String => await database.StringGetAsync(req.Key).ConfigureAwait(false)
, RedisType.List => string.Join(", ", await database.ListRangeAsync(req.Key).ConfigureAwait(false)) , RedisType.List => string.Join(", ", await database.ListRangeAsync(req.Key).ConfigureAwait(false))
, RedisType.Set => string.Join(", ", await database.SetMembersAsync(req.Key).ConfigureAwait(false)) , RedisType.Set => string.Join(", ", await database.SetMembersAsync(req.Key).ConfigureAwait(false))
, RedisType.SortedSet => , RedisType.SortedSet => string.Join(", ", await database.SortedSetRangeByRankAsync(req.Key).ConfigureAwait(false))
string.Join(", ", await database.SortedSetRangeByRankAsync(req.Key).ConfigureAwait(false)) , RedisType.Hash => string.Join(", ", await database.HashGetAllAsync(req.Key).ConfigureAwait(false))
, RedisType.Hash => string.Join(
", ", await database.HashGetAllAsync(req.Key).ConfigureAwait(false))
, _ => "Unsupported key type" , _ => "Unsupported key type"
}; };

View File

@ -21,17 +21,13 @@ public sealed class CaptchaService : ServiceBase<ICaptchaService>, ICaptchaServi
public async Task<GetCaptchaRsp> GetCaptchaImageAsync() public async Task<GetCaptchaRsp> GetCaptchaImageAsync()
{ {
var (backgroundImage, sliderImage, offsetSaw) = await CaptchaImageHelper.CreateSawSliderImageAsync( var (backgroundImage, sliderImage, offsetSaw) = await CaptchaImageHelper.CreateSawSliderImageAsync(
_entryAsm, $"{_entryAsmName}.Assets.Captcha.background", $"{_entryAsmName}.Assets.Captcha.template" _entryAsm, $"{_entryAsmName}.Assets.Captcha.background"
, (1, 101), (1, 7), new Size(50, 50)) , $"{_entryAsmName}.Assets.Captcha.template", (1, 101), (1, 7)
, new Size(50, 50))
.ConfigureAwait(false); .ConfigureAwait(false);
var id = $"{nameof(GetCaptchaImageAsync)}_{YitIdHelper.NextId()}"; var id = $"{nameof(GetCaptchaImageAsync)}_{YitIdHelper.NextId()}";
return new GetCaptchaRsp { return new GetCaptchaRsp { Id = id, BackgroundImage = backgroundImage, SliderImage = sliderImage, SawOffsetX = offsetSaw.X };
Id = id
, BackgroundImage = backgroundImage
, SliderImage = sliderImage
, SawOffsetX = offsetSaw.X
};
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -84,18 +84,14 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
public async Task<QueryConfigRsp> GetAsync(QueryConfigReq req) public async Task<QueryConfigRsp> GetAsync(QueryConfigReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryConfigReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryConfigReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryConfigRsp>(); return ret.Adapt<QueryConfigRsp>();
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryConfigRsp> GetLatestConfigAsync() public async Task<QueryConfigRsp> GetLatestConfigAsync()
{ {
var ret = await QueryAsync( var ret = await QueryAsync(new QueryReq<QueryConfigReq> { Count = 1, Filter = new QueryConfigReq { Enabled = true } }).ConfigureAwait(false);
new QueryReq<QueryConfigReq> { Count = 1, Filter = new QueryConfigReq { Enabled = true } })
.ConfigureAwait(false);
return ret.FirstOrDefault(); return ret.FirstOrDefault();
} }
@ -112,8 +108,7 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
.ToListAsync() .ToListAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return new PagedQueryRsp<QueryConfigRsp>(req.Page, req.PageSize, total return new PagedQueryRsp<QueryConfigRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryConfigRsp>>());
, list.Adapt<IEnumerable<QueryConfigRsp>>());
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -26,19 +26,13 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
var httpStatusCodes = Enum.GetNames<HttpStatusCode>().ToDictionary(x => x, GetHttpStatusCodeDicValue); var httpStatusCodes = Enum.GetNames<HttpStatusCode>().ToDictionary(x => x, GetHttpStatusCodeDicValue);
httpStatusCodes.Add( // httpStatusCodes.Add( //
nameof(ErrorCodes.Unhandled) nameof(ErrorCodes.Unhandled)
, [ , [Numbers.HTTP_STATUS_BIZ_FAIL.ToInvString(), nameof(ErrorCodes.Unhandled), nameof(Indicates.Danger).ToLowerInvariant()]);
Numbers.HTTP_STATUS_BIZ_FAIL.ToInvString(), nameof(ErrorCodes.Unhandled)
, nameof(Indicates.Danger).ToLowerInvariant()
]);
ret.Add($"{nameof(HttpStatusCode)}s", httpStatusCodes); ret.Add($"{nameof(HttpStatusCode)}s", httpStatusCodes);
return ret; return ret;
static string[] GetDicValue(Enum y) static string[] GetDicValue(Enum y)
{ {
var ret = new[] { var ret = new[] { Convert.ToInt64(y, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture), y.ResDesc<Ln>() };
Convert.ToInt64(y, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture)
, y.ResDesc<Ln>()
};
var indicate = y.GetAttributeOfType<IndicatorAttribute>()?.Indicate.ToLowerInvariant(); var indicate = y.GetAttributeOfType<IndicatorAttribute>()?.Indicate.ToLowerInvariant();
return indicate.NullOrEmpty() ? ret : [..ret, indicate]; return indicate.NullOrEmpty() ? ret : [..ret, indicate];
} }
@ -48,11 +42,8 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
var codeInt = Convert.ToInt64(Enum.Parse<HttpStatusCode>(name), CultureInfo.InvariantCulture); var codeInt = Convert.ToInt64(Enum.Parse<HttpStatusCode>(name), CultureInfo.InvariantCulture);
return [ return [
codeInt.ToString(CultureInfo.InvariantCulture), name codeInt.ToString(CultureInfo.InvariantCulture), name
, (codeInt switch { , (codeInt switch { >= 200 and < 300 => nameof(Indicates.Success), < 400 => nameof(Indicates.Warning), _ => nameof(Indicates.Danger) })
>= 200 and < 300 => nameof(Indicates.Success) .ToLowerInvariant()
, < 400 => nameof(Indicates.Warning)
, _ => nameof(Indicates.Danger)
}).ToLowerInvariant()
]; ];
} }
} }

View File

@ -74,9 +74,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>(); return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>();
#else #else
return await UpdateAsync(req, null).ConfigureAwait(false) > 0 return await UpdateAsync(req, null).ConfigureAwait(false) > 0 ? await GetAsync(new QueryDeptReq { Id = req.Id }).ConfigureAwait(false) : null;
? await GetAsync(new QueryDeptReq { Id = req.Id }).ConfigureAwait(false)
: null;
#endif #endif
} }
@ -102,9 +100,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
public async Task<QueryDeptRsp> GetAsync(QueryDeptReq req) public async Task<QueryDeptRsp> GetAsync(QueryDeptReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDeptReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryDeptReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryDeptRsp>(); return ret.Adapt<QueryDeptRsp>();
} }
@ -145,8 +141,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
.WhereDynamic(req.Filter) .WhereDynamic(req.Filter)
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) || , a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) || a.Summary.Contains(req.Keywords));
a.Summary.Contains(req.Keywords));
if (asTreeCte) { if (asTreeCte) {
ret = ret.AsTreeCte(); ret = ret.AsTreeCte();
} }

View File

@ -13,8 +13,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
private static readonly string _clientProjectPath = Path.Combine( // private static readonly string _clientProjectPath = Path.Combine( //
Environment.CurrentDirectory, "../../frontend/admin"); Environment.CurrentDirectory, "../../frontend/admin");
private static readonly string[] _projectDirs private static readonly string[] _projectDirs = Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../"));
= Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../"));
private static readonly Regex _regex = new(@"\.(\w)"); private static readonly Regex _regex = new(@"\.(\w)");
private static readonly Regex _regex2 = new("([a-zA-Z]+):"); private static readonly Regex _regex2 = new("([a-zA-Z]+):");
@ -26,6 +25,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
// 模块类型Sys、Adm、等 // 模块类型Sys、Adm、等
var moduleType = Enum.GetName(req.Type)!; var moduleType = Enum.GetName(req.Type)!;
var @namespace = req.Type.ToString();
// 模板层目录 // 模板层目录
var tplHostDir = GetDir("SysComponent.Host"); var tplHostDir = GetDir("SysComponent.Host");
@ -51,57 +51,57 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
var entityDir = Path.Combine(dataDir, "DbMaps", moduleType[..3]); var entityDir = Path.Combine(dataDir, "DbMaps", moduleType[..3]);
// 创建缺少的目录 // 创建缺少的目录
CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir, appServicesDependencyDir, dataDir, dtoDir
, appServicesDependencyDir, dataDir, dtoDir, entityDir); , entityDir);
// Controller // Controller
await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs") await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs")
, Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs")) , Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// CreateReq // CreateReq
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs") await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs")
, Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs")) , Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// QueryReq // QueryReq
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs") await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs")
, Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs")) , Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// QueryRsp // QueryRsp
await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs") await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs")
, Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs")) , Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// ICache // ICache
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs") await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs")
, Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs")) , Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// Cache // Cache
await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs") await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs"), Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs")
, Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs")) , @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// IModule // IModule
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs") await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs")
, Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs")) , Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// IService // IService
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs") await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs")
, Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs")) , Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// Service // Service
await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs") await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs")
, Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs")) , Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
// Entity // Entity
await WriteCodeFileAsync(req, Path.Combine(dataDir, "DbMaps", "Tpl", "Tpl_Example.cs") await WriteCodeFileAsync(req, Path.Combine(dataDir, "DbMaps", "Tpl", "Tpl_Example.cs")
, Path.Combine(entityDir, $"{moduleType[..3]}_{req.ModuleName}.cs")) , Path.Combine(entityDir, $"{moduleType[..3]}_{req.ModuleName}.cs"), @namespace)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
@ -109,12 +109,8 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
public async Task GenerateIconCodeAsync(GenerateIconCodeReq req) public async Task GenerateIconCodeAsync(GenerateIconCodeReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var tplSvg = await File.ReadAllTextAsync( var tplSvg = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue")).ConfigureAwait(false);
Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue")) var tplExport = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "export.js"))
.ConfigureAwait(false);
var tplExport = await File
.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl"
, "export.js"))
.ConfigureAwait(false); .ConfigureAwait(false);
var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty); var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty);
@ -130,9 +126,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
var indexJsFile = Path.Combine(dir, "index.js"); var indexJsFile = Path.Combine(dir, "index.js");
await File.AppendAllTextAsync( await File.AppendAllTextAsync(
indexJsFile indexJsFile, Environment.NewLine + tplExport.Replace("$iconName$", req.IconName).Replace(_REPLACE_TO_EMPTY, string.Empty))
, Environment.NewLine +
tplExport.Replace("$iconName$", req.IconName).Replace(_REPLACE_TO_EMPTY, string.Empty))
.ConfigureAwait(false); .ConfigureAwait(false);
// 修改iconSelect.js // 修改iconSelect.js
@ -152,10 +146,8 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
public async Task GenerateJsCodeAsync() public async Task GenerateJsCodeAsync()
{ {
// 模板文件 // 模板文件
var tplOuter = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "outer.js")) var tplOuter = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "outer.js")).ConfigureAwait(false);
.ConfigureAwait(false); var tplInner = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "inner.js")).ConfigureAwait(false);
var tplInner = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "inner.js"))
.ConfigureAwait(false);
foreach (var item in apiService.ReflectionList(false)) { foreach (var item in apiService.ReflectionList(false)) {
var dir = Path.Combine(_clientProjectPath, "src", "api", item.Namespace); var dir = Path.Combine(_clientProjectPath, "src", "api", item.Namespace);
@ -168,8 +160,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
var content = tplOuter.Replace("$controllerDesc$", item.Summary) var content = tplOuter.Replace("$controllerDesc$", item.Summary)
.Replace("$controllerPath$", item.Id) .Replace("$controllerPath$", item.Id)
.Replace( // .Replace( //
"$inner$" "$inner$", string.Join(Environment.NewLine + Environment.NewLine, Select(item)))
, string.Join(Environment.NewLine + Environment.NewLine, Select(item)))
.Replace(_REPLACE_TO_EMPTY, string.Empty); .Replace(_REPLACE_TO_EMPTY, string.Empty);
await File.WriteAllTextAsync(file, content).ConfigureAwait(false); await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
@ -180,9 +171,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
{ {
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary) return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
.Replace( // .Replace( //
"$actionName$" "$actionName$", _regex.Replace(x.Name, y => y.Groups[1].Value.ToUpperInvariant()))
, _regex.Replace(
x.Name, y => y.Groups[1].Value.ToUpperInvariant()))
.Replace("$actionPath$", x.Id) .Replace("$actionPath$", x.Id)
.Replace( // .Replace( //
"$actionMethod$", x.Method?.ToLowerInvariant()) "$actionMethod$", x.Method?.ToLowerInvariant())
@ -204,13 +193,13 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture)); return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture));
} }
private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile) private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile, string @namespace = "SysComponent")
{ {
var tplContent = await File.ReadAllTextAsync(tplFile).ConfigureAwait(false); var tplContent = await File.ReadAllTextAsync(tplFile).ConfigureAwait(false);
tplContent = tplContent.Replace("Tpl", Enum.GetName(req.Type)![..3]) tplContent = tplContent.Replace("Tpl", Enum.GetName(req.Type)![..3])
.Replace("示例", req.ModuleRemark) .Replace("示例", req.ModuleRemark)
.Replace("Example", req.ModuleName) .Replace("Example", req.ModuleName)
.Replace("NetAdmin.SysComponent", "SysComponent"); .Replace("NetAdmin.SysComponent", $"NetAdmin.{@namespace}");
await File.WriteAllTextAsync(writeFile, tplContent).ConfigureAwait(false); await File.WriteAllTextAsync(writeFile, tplContent).ConfigureAwait(false);
} }

View File

@ -40,8 +40,12 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req) public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
if (req.ParentId != 0 && if (req.ParentId != 0 && !await Rpo.Where(a => a.Id == req.ParentId)
!await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false)) { #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.AnyAsync()
.ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.); throw new NetAdminInvalidOperationException(Ln.);
} }
@ -62,8 +66,12 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
public async Task<int> EditAsync(EditDicCatalogReq req) public async Task<int> EditAsync(EditDicCatalogReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
return req.ParentId == 0 || return req.ParentId == 0 || await Rpo.Where(a => a.Id == req.ParentId)
await Rpo.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync().ConfigureAwait(false) #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.AnyAsync()
.ConfigureAwait(false)
? await UpdateAsync(req, null).ConfigureAwait(false) ? await UpdateAsync(req, null).ConfigureAwait(false)
: throw new NetAdminInvalidOperationException(Ln.); : throw new NetAdminInvalidOperationException(Ln.);
} }
@ -89,9 +97,7 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
public async Task<QueryDicCatalogRsp> GetAsync(QueryDicCatalogReq req) public async Task<QueryDicCatalogRsp> GetAsync(QueryDicCatalogReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDicCatalogReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryDicCatalogReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryDicCatalogRsp>(); return ret.Adapt<QueryDicCatalogRsp>();
} }
@ -108,8 +114,7 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
.ToListAsync() .ToListAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return new PagedQueryRsp<QueryDicCatalogRsp>(req.Page, req.PageSize, total return new PagedQueryRsp<QueryDicCatalogRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryDicCatalogRsp>>());
, list.Adapt<IEnumerable<QueryDicCatalogRsp>>());
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -42,7 +42,9 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
req.ThrowIfInvalid(); req.ThrowIfInvalid();
if (!await Rpo.Orm.Select<Sys_DicCatalog>() if (!await Rpo.Orm.Select<Sys_DicCatalog>()
.Where(a => a.Id == req.CatalogId) .Where(a => a.Id == req.CatalogId)
.ForUpdate() #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.AnyAsync() .AnyAsync()
.ConfigureAwait(false)) { .ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.); throw new NetAdminInvalidOperationException(Ln.);
@ -66,15 +68,16 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
req.ThrowIfInvalid(); req.ThrowIfInvalid();
if (!await Rpo.Orm.Select<Sys_DicCatalog>() if (!await Rpo.Orm.Select<Sys_DicCatalog>()
.Where(a => a.Id == req.CatalogId) .Where(a => a.Id == req.CatalogId)
.ForUpdate() #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.AnyAsync() .AnyAsync()
.ConfigureAwait(false)) { .ConfigureAwait(false)) {
throw new NetAdminInvalidOperationException(Ln.); throw new NetAdminInvalidOperationException(Ln.);
} }
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault() return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDicContentRsp>();
?.Adapt<QueryDicContentRsp>();
#else #else
return await UpdateAsync(req, null).ConfigureAwait(false) > 0 return await UpdateAsync(req, null).ConfigureAwait(false) > 0
? await GetAsync(new QueryDicContentReq { Id = req.Id }).ConfigureAwait(false) ? await GetAsync(new QueryDicContentReq { Id = req.Id }).ConfigureAwait(false)
@ -104,9 +107,7 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
public async Task<QueryDicContentRsp> GetAsync(QueryDicContentReq req) public async Task<QueryDicContentRsp> GetAsync(QueryDicContentReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryDicContentReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryDicContentReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryDicContentRsp>(); return ret.Adapt<QueryDicContentRsp>();
} }
@ -123,8 +124,7 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
.ToListAsync() .ToListAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return new PagedQueryRsp<QueryDicContentRsp>(req.Page, req.PageSize, total return new PagedQueryRsp<QueryDicContentRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryDicContentRsp>>());
, list.Adapt<IEnumerable<QueryDicContentRsp>>());
} }
/// <inheritdoc /> /// <inheritdoc />
@ -150,11 +150,19 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
#endif #endif
.Include(a => a.Catalog) .Include(a => a.Catalog)
.Where(a => a.Catalog.Code == catalogCode) .Where(a => a.Catalog.Code == catalogCode)
.Where(a => a.Enabled)
.ToListAsync() .ToListAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return ret.Adapt<List<QueryDicContentRsp>>(); return ret.Adapt<List<QueryDicContentRsp>>();
} }
/// <inheritdoc />
public Task<int> SetEnabledAsync(SetDicContentEnabledReq req)
{
req.ThrowIfInvalid();
return UpdateAsync(req, [nameof(Sys_DicContent.Enabled)]);
}
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req) private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter); var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);

View File

@ -136,4 +136,11 @@ public sealed class DicService(IDicCatalogService catalogService, IDicContentSer
req.ThrowIfInvalid(); req.ThrowIfInvalid();
return contentService.QueryAsync(req); return contentService.QueryAsync(req);
} }
/// <inheritdoc />
public Task<int> SetEnabledAsync(SetDicContentEnabledReq req)
{
req.ThrowIfInvalid();
return contentService.SetEnabledAsync(req);
}
} }

View File

@ -18,8 +18,7 @@ public sealed class FileService(IOptions<UploadOptions> uploadOptions, MinioHelp
} }
if (!uploadOptions.Value.ContentTypes.Contains(file.ContentType)) { if (!uploadOptions.Value.ContentTypes.Contains(file.ContentType)) {
throw new NetAdminInvalidOperationException( throw new NetAdminInvalidOperationException($"{Ln.允许的文件格式} {string.Join(",", uploadOptions.Value.ContentTypes)}");
$"{Ln.允许的文件格式} {string.Join(",", uploadOptions.Value.ContentTypes)}");
} }
if (file.Length > uploadOptions.Value.MaxSize) { if (file.Length > uploadOptions.Value.MaxSize) {

View File

@ -73,9 +73,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
public async Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req) public async Task<QueryJobRecordRsp> GetAsync(QueryJobRecordReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryJobRecordReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryJobRecordReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryJobRecordRsp>(); return ret.Adapt<QueryJobRecordRsp>();
} }
@ -88,16 +86,10 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif #endif
.GroupBy(a => new { .GroupBy(a => new { a.CreatedTime.Year, a.CreatedTime.Month, a.CreatedTime.Day, a.CreatedTime.Hour })
a.CreatedTime.Year
, a.CreatedTime.Month
, a.CreatedTime.Day
, a.CreatedTime.Hour
})
.ToListAsync(a => new GetBarChartRsp { .ToListAsync(a => new GetBarChartRsp {
Timestamp = new DateTime( Timestamp = new DateTime(a.Key.Year, a.Key.Month, a.Key.Day, a.Key.Hour, 0, 0
a.Key.Year, a.Key.Month, a.Key.Day, a.Key.Hour, 0 , DateTimeKind.Unspecified)
, 0, DateTimeKind.Unspecified)
, Value = a.Count() , Value = a.Count()
}) })
.ConfigureAwait(false); .ConfigureAwait(false);
@ -118,8 +110,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
.ToListAsync(a => new GetPieChartRsp { Value = a.Count(), Key = a.Key.ToString() }) .ToListAsync(a => new GetPieChartRsp { Value = a.Count(), Key = a.Key.ToString() })
#pragma warning restore CA1305 #pragma warning restore CA1305
.ConfigureAwait(false); .ConfigureAwait(false);
return ret.Select(x => x with { Key = Enum.Parse<HttpStatusCode>(x.Key).ToString() }) return ret.Select(x => x with { Key = Enum.Parse<HttpStatusCode>(x.Key).ToString() }).OrderByDescending(x => x.Value);
.OrderByDescending(x => x.Value);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -150,8 +141,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
.ToListAsync() .ToListAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return new PagedQueryRsp<QueryJobRecordRsp>(req.Page, req.PageSize, total return new PagedQueryRsp<QueryJobRecordRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryJobRecordRsp>>());
, list.Adapt<IEnumerable<QueryJobRecordRsp>>());
} }
/// <inheritdoc /> /// <inheritdoc />
@ -175,8 +165,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
.WhereDynamic(req.Filter) .WhereDynamic(req.Filter)
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) || , a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) || a.Job.JobName == req.Keywords);
a.Job.JobName == req.Keywords);
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) { switch (req.Order) {

View File

@ -112,9 +112,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
} }
] ]
}; };
var job var job = await QueryInternal(new QueryReq<QueryJobReq> { Count = 1, Filter = req, DynamicFilter = df, Order = Orders.None })
= await QueryInternal(
new QueryReq<QueryJobReq> { Count = 1, Filter = req, DynamicFilter = df, Order = Orders.None })
.ToOneAsync() .ToOneAsync()
.ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.); .ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.);
@ -160,16 +158,9 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var nextExecTime = GetNextExecTime(req.ExecutionCron); var nextExecTime = GetNextExecTime(req.ExecutionCron);
_ = await UpdateAsync( _ = await UpdateAsync( //
req with { req with { Status = JobStatues.Idle, NextExecTime = nextExecTime, NextTimeId = nextExecTime?.TimeUnixUtc() }
Status = JobStatues.Idle , [nameof(req.Status), nameof(req.NextExecTime), nameof(req.NextTimeId), nameof(req.LastDuration), nameof(req.LastStatusCode)])
, NextExecTime = nextExecTime
, NextTimeId = nextExecTime?.TimeUnixUtc()
}
, [
nameof(req.Status), nameof(req.NextExecTime), nameof(req.NextTimeId), nameof(req.LastDuration)
, nameof(req.LastStatusCode)
])
.ConfigureAwait(false); .ConfigureAwait(false);
} }
@ -177,9 +168,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
public async Task<QueryJobRsp> GetAsync(QueryJobReq req) public async Task<QueryJobRsp> GetAsync(QueryJobReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryJobReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryJobReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryJobRsp>(); return ret.Adapt<QueryJobRsp>();
} }
@ -209,10 +198,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif #endif
.Where(a => !Rpo.Orm.Select<Sys_JobRecord>() .Where(a => !Rpo.Orm.Select<Sys_JobRecord>().As("b").Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId).Any())
.As("b")
.Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId)
.Any())
.ToOneAsync(a => new { .ToOneAsync(a => new {
a.RequestUrl a.RequestUrl
, a.HttpMethod , a.HttpMethod
@ -317,16 +303,13 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
{ {
var ret1 = await UpdateAsync( // 运行中,运行时间超过超时设定;置为空闲状态 var ret1 = await UpdateAsync( // 运行中,运行时间超过超时设定;置为空闲状态
new Sys_Job { Status = JobStatues.Idle }, [nameof(Sys_Job.Status)], null new Sys_Job { Status = JobStatues.Idle }, [nameof(Sys_Job.Status)], null
, a => a.Status == JobStatues.Running && , a => a.Status == JobStatues.Running && a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB), null, true)
a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB)
, null, true)
.ConfigureAwait(false); .ConfigureAwait(false);
var ret2 = await UpdateAsync( // 空闲中,下次执行时间在当前时间减去超时时间以前;将下次执行时间调整到现在 var ret2 = await UpdateAsync( // 空闲中,下次执行时间在当前时间减去超时时间以前;将下次执行时间调整到现在
new Sys_Job { NextExecTime = DateTime.Now, NextTimeId = DateTime.Now.TimeUnixUtc() } new Sys_Job { NextExecTime = DateTime.Now, NextTimeId = DateTime.Now.TimeUnixUtc() }
, [nameof(Sys_Job.NextExecTime), nameof(Sys_Job.NextTimeId)], null , [nameof(Sys_Job.NextExecTime), nameof(Sys_Job.NextTimeId)], null
, a => a.Status == JobStatues.Idle && a.NextExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB) , a => a.Status == JobStatues.Idle && a.NextExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB), null, true)
, null, true)
.ConfigureAwait(false); .ConfigureAwait(false);
return ret1 + ret2; return ret1 + ret2;
} }
@ -340,9 +323,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
private static DateTime? GetNextExecTime(string cron) private static DateTime? GetNextExecTime(string cron)
{ {
return CronExpression.Parse(cron, CronFormat.IncludeSeconds) return CronExpression.Parse(cron, CronFormat.IncludeSeconds).GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local)?.ToLocalTime();
.GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local)
?.ToLocalTime();
} }
private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req) private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req)
@ -360,8 +341,7 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
ret = ret.WhereDynamicFilter(req.DynamicFilter) ret = ret.WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter) .WhereDynamic(req.Filter)
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) { switch (req.Order) {

View File

@ -72,9 +72,7 @@ public sealed class LoginLogService(BasicRepository<Sys_LoginLog, long> rpo) //
public async Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req) public async Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryLoginLogReq> { Filter = req, Order = Orders.None }) var ret = await QueryInternal(new QueryReq<QueryLoginLogReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt<QueryLoginLogRsp>(); return ret.Adapt<QueryLoginLogRsp>();
} }
@ -128,8 +126,7 @@ public sealed class LoginLogService(BasicRepository<Sys_LoginLog, long> rpo) //
if (req.Keywords?.Length > 0) { if (req.Keywords?.Length > 0) {
ret = req.Keywords.IsIpV4() ret = req.Keywords.IsIpV4()
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32()) ? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) || : ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) || a.LoginUserName == req.Keywords);
a.LoginUserName == req.Keywords);
} }
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault

Some files were not shown because too many files have changed in this diff Show More