diff --git a/assets/res/Fields.ln b/assets/res/Fields.ln
index b1a1b845..4e342191 100644
--- a/assets/res/Fields.ln
+++ b/assets/res/Fields.ln
@@ -134,6 +134,8 @@
重设密码
链接
错误
+随机延时结束时间不正确
+随机延时起始时间不正确
随机排序
项值
项名
diff --git a/build/code.quality.props b/build/code.quality.props
index dae8147d..e54f22a2 100644
--- a/build/code.quality.props
+++ b/build/code.quality.props
@@ -23,7 +23,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/package.json b/package.json
index 38b42dd4..5adb111b 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"devDependencies": {
"cz-git": "^1.9.3",
"commitizen": "^4.3.0",
- "prettier": "^3.3.2",
+ "prettier": "^3.3.3",
"standard-version": "^9.5.0"
},
"config": {
diff --git a/scripts/switcher.furion.json b/scripts/switcher.furion.json
index f149da53..8aaa8b08 100644
--- a/scripts/switcher.furion.json
+++ b/scripts/switcher.furion.json
@@ -9,7 +9,7 @@
"packages": [
{
"packageName": "Furion.Pure.NS",
- "version": "4.9.4-ns1"
+ "version": "4.9.4.6-ns4"
}
]
}
diff --git a/src/backend/NetAdmin.AdmServer.Host/Startup.cs b/src/backend/NetAdmin.AdmServer.Host/Startup.cs
index 67c16c86..96275b89 100644
--- a/src/backend/NetAdmin.AdmServer.Host/Startup.cs
+++ b/src/backend/NetAdmin.AdmServer.Host/Startup.cs
@@ -1,3 +1,4 @@
+using Microsoft.IdentityModel.Logging;
using NetAdmin.AdmServer.Host;
using NetAdmin.AdmServer.Host.Extensions;
using NetAdmin.Host.Extensions;
@@ -78,8 +79,9 @@ namespace NetAdmin.AdmServer.Host
public Task Execute(CommandContext context, CommandLineArgs settings)
#pragma warning restore ASA001
{
- Args = settings;
- _ = Serve.Run(RunOptions.Default.WithArgs(context.Remaining.Raw.ToArray()));
+ Args = settings;
+ IdentityModelEventSource.ShowPII = true;
+ _ = Serve.Run(RunOptions.Default.WithArgs(context.Remaining.Raw.ToArray()));
return Task.FromResult(0);
}
diff --git a/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs b/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs
index 88944ab3..eb60988c 100644
--- a/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs
+++ b/src/backend/NetAdmin.AdmServer.Tests/AllTests.cs
@@ -979,7 +979,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetBarChartAsync(QueryReq req)
+ public Task> GetBarChartAsync(QueryReq req)
{
return default;
}
@@ -1075,7 +1075,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetPieChartByApiSummaryAsync(QueryReq req)
+ public Task> GetPieChartByApiSummaryAsync(QueryReq req)
{
return default;
}
@@ -1083,7 +1083,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetPieChartByHttpStatusCodeAsync(QueryReq req)
+ public Task> GetPieChartByHttpStatusCodeAsync(QueryReq req)
{
return default;
}
@@ -1099,7 +1099,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetRecordBarChartAsync(QueryReq req)
+ public Task> GetRecordBarChartAsync(QueryReq req)
{
return default;
}
@@ -1107,8 +1107,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetRecordPieChartByHttpStatusCodeAsync(
- QueryReq req)
+ public Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req)
{
return default;
}
@@ -1116,7 +1115,7 @@ public class AllTests(WebApplicationFactory factory, ITestOutputHelper
///
[InlineData(default)]
[Theory]
- public Task> GetRecordPieChartByNameAsync(QueryReq req)
+ public Task> GetRecordPieChartByNameAsync(QueryReq req)
{
return default;
}
diff --git a/src/backend/NetAdmin.Application/Services/RepositoryService.cs b/src/backend/NetAdmin.Application/Services/RepositoryService.cs
index a5f35eb5..62763bae 100644
--- a/src/backend/NetAdmin.Application/Services/RepositoryService.cs
+++ b/src/backend/NetAdmin.Application/Services/RepositoryService.cs
@@ -30,6 +30,46 @@ public abstract class RepositoryService(BasicReposit
set => Rpo.DbContextOptions.EnableCascadeSave = value;
}
+ ///
+ /// 导出实体
+ ///
+ protected async Task ExportAsync( //
+ Func, ISelect> selector, QueryReq query, string fileName
+ , Expression> listExp = null)
+ where TQuery : DataAbstraction, new()
+ {
+ var select = selector(query)
+ #if DBTYPE_SQLSERVER
+ .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
+ #endif
+ .Take(Numbers.MAX_LIMIT_EXPORT);
+
+ object list = listExp == null
+ ? await select.ToListAsync().ConfigureAwait(false)
+ : await select.ToListAsync(listExp).ConfigureAwait(false);
+
+ var listTyped = list.Adapt>();
+ var stream = new MemoryStream();
+ var writer = new StreamWriter(stream);
+ var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
+ csv.WriteHeader();
+ await csv.NextRecordAsync().ConfigureAwait(false);
+
+ foreach (var item in listTyped) {
+ csv.WriteRecord(item);
+ await csv.NextRecordAsync().ConfigureAwait(false);
+ }
+
+ await csv.FlushAsync().ConfigureAwait(false);
+ _ = stream.Seek(0, SeekOrigin.Begin);
+
+ App.HttpContext.Response.Headers.ContentDisposition
+ = new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
+ FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
+ }.ToString();
+ return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
+ }
+
///
/// 更新实体
///
@@ -77,43 +117,6 @@ public abstract class RepositoryService(BasicReposit
}
#endif
- ///
- /// 导出实体
- ///
- protected async Task ExportAsync( //
- Func, ISelect> selector, QueryReq query, string fileName)
- where TQuery : DataAbstraction, new()
- {
- var data = await selector(query)
- #if DBTYPE_SQLSERVER
- .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
- #endif
- .Take(Numbers.MAX_LIMIT_EXPORT)
- .ToListAsync()
- .ConfigureAwait(false);
-
- var list = data.Adapt>();
- var stream = new MemoryStream();
- var writer = new StreamWriter(stream);
- var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
- csv.WriteHeader();
- await csv.NextRecordAsync().ConfigureAwait(false);
-
- foreach (var item in list) {
- csv.WriteRecord(item);
- await csv.NextRecordAsync().ConfigureAwait(false);
- }
-
- await csv.FlushAsync().ConfigureAwait(false);
- _ = stream.Seek(0, SeekOrigin.Begin);
-
- App.HttpContext.Response.Headers.ContentDisposition
- = new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
- FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
- }.ToString();
- return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
- }
-
private IUpdate BuildUpdate( //
TEntity entity //
, IEnumerable includeFields //
diff --git a/src/backend/NetAdmin.Cache/DistributedCache.cs b/src/backend/NetAdmin.Cache/DistributedCache.cs
index 14bbb27d..e4d7c510 100644
--- a/src/backend/NetAdmin.Cache/DistributedCache.cs
+++ b/src/backend/NetAdmin.Cache/DistributedCache.cs
@@ -70,7 +70,8 @@ public abstract class DistributedCache(IDistributedCache cache, TServi
, TimeSpan? slideLifeTime = null)
{
var cacheRead = await GetAsync(key).ConfigureAwait(false);
- if (cacheRead is not null) {
+ if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() !=
+ Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
return cacheRead;
}
diff --git a/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs b/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs
index a8415d56..c7dc47ad 100644
--- a/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs
+++ b/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs
@@ -7,6 +7,12 @@ namespace NetAdmin.Domain.Contexts;
///
public sealed record ContextUserToken : DataAbstraction
{
+ ///
+ /// 部门编号
+ ///
+ /// ReSharper disable once MemberCanBePrivate.Global
+ public long DeptId { get; init; }
+
///
/// 用户编号
///
@@ -39,6 +45,8 @@ public sealed record ContextUserToken : DataAbstraction
///
public static ContextUserToken Create(QueryUserRsp user)
{
- return new ContextUserToken { Id = user.Id, Token = user.Token, UserName = user.UserName };
+ return new ContextUserToken {
+ Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
+ };
}
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientIp.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientIp.cs
new file mode 100644
index 00000000..26739390
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientIp.cs
@@ -0,0 +1,12 @@
+namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
+
+///
+/// 创建者客户端IP字段接口
+///
+public interface IFieldCreatedClientIp
+{
+ ///
+ /// 创建者客户端IP
+ ///
+ int? CreatedClientIp { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientUserAgent.cs
similarity index 52%
rename from src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs
rename to src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientUserAgent.cs
index 1a8cb3c4..8c1b2f40 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClientUserAgent.cs
@@ -1,15 +1,10 @@
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
///
-/// 创建者客户端字段接口
+/// 创建者客户端用户代理字段接口
///
-public interface IFieldCreatedClient
+public interface IFieldCreatedClientUserAgent
{
- ///
- /// 创建者客户端IP
- ///
- int? CreatedClientIp { get; init; }
-
///
/// 创建者客户端用户代理
///
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientIp.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientIp.cs
new file mode 100644
index 00000000..a301488d
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientIp.cs
@@ -0,0 +1,12 @@
+namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
+
+///
+/// 修改客户端IP字段接口
+///
+public interface IFieldModifiedClientIp
+{
+ ///
+ /// 客户端IP
+ ///
+ int ModifiedClientIp { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientUserAgent.cs
similarity index 53%
rename from src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs
rename to src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientUserAgent.cs
index f95d2c25..74fb59dc 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClientUserAgent.cs
@@ -1,15 +1,10 @@
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
///
-/// 修改客户端字段接口
+/// 修改客户端用户代理字段接口
///
-public interface IFieldModifiedClient
+public interface IFieldModifiedClientUserAgent
{
- ///
- /// 客户端IP
- ///
- int ModifiedClientIp { get; init; }
-
///
/// 客户端用户代理
///
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs
index e538c007..e499e2af 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs
@@ -4,6 +4,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// Api接口表
///
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Api))]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(PathCrc32), nameof(PathCrc32), true)]
public record Sys_Api : ImmutableEntity, IFieldSummary
{
///
@@ -54,6 +55,14 @@ public record Sys_Api : ImmutableEntity, IFieldSummary
[JsonIgnore]
public virtual string ParentId { get; init; }
+ ///
+ /// 路径CRC32
+ ///
+ [Column]
+ [Ignore]
+ [JsonIgnore]
+ public int PathCrc32 { get; init; }
+
///
/// 角色集合
///
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs
index 64bdba5a..3524a734 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs
@@ -18,7 +18,7 @@ public record Sys_DicCatalog : VersionEntity
///
/// 字典编码
///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
[Ignore]
[JsonIgnore]
public virtual string Code { get; init; }
@@ -34,7 +34,7 @@ public record Sys_DicCatalog : VersionEntity
///
/// 字典名称
///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
[Ignore]
[JsonIgnore]
public virtual string Name { get; init; }
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs
index f38f8035..fdbf8b31 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs
@@ -4,8 +4,6 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// 字典内容表
///
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
-[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Value)}", $"{nameof(CatalogId)},{nameof(Value)}"
- , true)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
public record Sys_DicContent : VersionEntity
{
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Job.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Job.cs
index d3bfa988..3e467221 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Job.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Job.cs
@@ -79,6 +79,22 @@ public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
[JsonIgnore]
public virtual long? NextTimeId { get; init; }
+ ///
+ /// 随机延时起始值(毫秒)
+ ///
+ [Column]
+ [Ignore]
+ [JsonIgnore]
+ public virtual int? RandomDelayBegin { get; init; }
+
+ ///
+ /// 随机延时结束值(毫秒)
+ ///
+ [Column]
+ [Ignore]
+ [JsonIgnore]
+ public virtual int? RandomDelayEnd { get; init; }
+
///
/// 请求体
///
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs
index 49e38fec..a66ad4c6 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs
@@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// 计划作业执行记录表
///
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(JobId)}_{nameof(TimeId)}", $"{nameof(JobId)},{nameof(TimeId)}", true)]
-[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), nameof(CreatedTime), false)]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(JobId), nameof(JobId), false)]
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_JobRecord))]
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs
index b700a58f..faec5f61 100644
--- a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs
@@ -1,36 +1,38 @@
+using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
+
namespace NetAdmin.Domain.DbMaps.Sys;
///
/// 请求日志表
///
-[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(ApiId), nameof(ApiId), false)]
-[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), nameof(CreatedTime), false)]
-[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(UserId), nameof(UserId), false)]
-[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(ApiPathCrc32), nameof(ApiPathCrc32), false)]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
+[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLog))]
-public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldCreatedClient
+public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
{
///
/// 接口
///
[Ignore]
[JsonIgnore]
- [Navigate(nameof(ApiId))]
+ [Navigate(nameof(ApiPathCrc32), TempPrimary = nameof(Sys_Api.PathCrc32))]
public Sys_Api Api { get; init; }
///
- /// 接口编号
+ /// 接口路径CRC32
///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
+ [Column]
[Ignore]
[JsonIgnore]
- public virtual string ApiId { get; init; }
+ public virtual int ApiPathCrc32 { get; init; }
///
- [Column(Position = -1)]
+ [Column]
[Ignore]
[JsonIgnore]
- public int? CreatedClientIp { get; init; }
+ public virtual int? CreatedClientIp { get; init; }
///
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
@@ -38,161 +40,55 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldCreatedCli
[JsonIgnore]
public virtual DateTime CreatedTime { get; init; }
- ///
- #if DBTYPE_SQLSERVER
- [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)]
- #else
- [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
+ ///
+ /// 明细
+ ///
[Ignore]
[JsonIgnore]
- public virtual string CreatedUserAgent { get; init; }
+ [Navigate(nameof(Id))]
+ public Sys_RequestLogDetail Detail { get; init; }
///
- /// 执行耗时(微秒)
+ /// 执行耗时(毫秒)
///
[Column]
[Ignore]
[JsonIgnore]
- public virtual long Duration { get; init; }
+ public virtual int Duration { get; init; }
///
- /// 程序响应码
+ /// 请求方法
///
- [Column]
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_TINY_INT)]
[Ignore]
[JsonIgnore]
- public virtual ErrorCodes ErrorCode { get; init; }
-
- ///
- /// 异常信息
- ///
- #if DBTYPE_SQLSERVER
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
- #else
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
- [Ignore]
- [JsonIgnore]
- public virtual string Exception { get; init; }
+ public virtual HttpMethods HttpMethod { get; init; }
///
/// HTTP状态码
///
- [Column]
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_SMALL_INT)]
[Ignore]
[JsonIgnore]
public virtual int HttpStatusCode { get; init; }
///
- /// 请求方法
+ /// 拥有者
///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)]
[Ignore]
[JsonIgnore]
- public virtual string Method { get; init; }
+ [Navigate(nameof(OwnerId))]
+ public Sys_User Owner { get; init; }
- ///
- /// 请求内容
- ///
- #if DBTYPE_SQLSERVER
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
- #else
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
- [Ignore]
- [JsonIgnore]
- public virtual string RequestBody { get; init; }
-
- ///
- /// 请求content-type
- ///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
- [Ignore]
- [JsonIgnore]
- public virtual string RequestContentType { get; init; }
-
- ///
- /// 请求头信息
- ///
- #if DBTYPE_SQLSERVER
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
- #else
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
- [Ignore]
- [JsonIgnore]
- public virtual string RequestHeaders { get; init; }
-
- ///
- /// 请求地址
- ///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
- [Ignore]
- [JsonIgnore]
- public virtual string RequestUrl { get; init; }
-
- ///
- /// 响应内容
- ///
- #if DBTYPE_SQLSERVER
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
- #else
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
- [Ignore]
- [JsonIgnore]
- public virtual string ResponseBody { get; init; }
-
- ///
- /// 响应content-type
- ///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
- [Ignore]
- [JsonIgnore]
- public virtual string ResponseContentType { get; init; }
-
- ///
- /// 响应头
- ///
- #if DBTYPE_SQLSERVER
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
- #else
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
- #endif
- [Ignore]
- [JsonIgnore]
- public virtual string ResponseHeaders { get; init; }
-
- ///
- /// 服务器IP
- ///
+ ///
[Column]
[Ignore]
[JsonIgnore]
- public virtual int? ServerIp { get; init; }
+ public virtual long? OwnerDeptId { get; init; }
- ///
- /// 请求跟踪标识
- ///
- [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
- [Ignore]
- [JsonIgnore]
- public virtual string TraceId { get; init; }
-
- ///
- /// 用户
- ///
- [Ignore]
- [JsonIgnore]
- [Navigate(nameof(UserId))]
- public Sys_User User { get; init; }
-
- ///
- /// 用户编号
- ///
+ ///
[Column]
[Ignore]
[JsonIgnore]
- public virtual long? UserId { get; init; }
+ public virtual long? OwnerId { get; init; }
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
new file mode 100644
index 00000000..6183ec24
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
@@ -0,0 +1,132 @@
+namespace NetAdmin.Domain.DbMaps.Sys;
+
+///
+/// 请求日志明细表
+///
+[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLogDetail))]
+public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCreatedClientUserAgent
+{
+ ///
+ [Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
+ [Ignore]
+ [JsonIgnore]
+ public virtual DateTime CreatedTime { get; init; }
+
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)]
+ #else
+ [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string CreatedUserAgent { get; init; }
+
+ ///
+ /// 程序响应码
+ ///
+ [Column]
+ [Ignore]
+ [JsonIgnore]
+ public virtual ErrorCodes ErrorCode { get; init; }
+
+ ///
+ /// 异常信息
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
+ #else
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string Exception { get; init; }
+
+ ///
+ /// 请求内容
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
+ #else
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string RequestBody { get; init; }
+
+ ///
+ /// 请求content-type
+ ///
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
+ [Ignore]
+ [JsonIgnore]
+ public virtual string RequestContentType { get; init; }
+
+ ///
+ /// 请求头信息
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
+ #else
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string RequestHeaders { get; init; }
+
+ ///
+ /// 请求地址
+ ///
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
+ [Ignore]
+ [JsonIgnore]
+ public virtual string RequestUrl { get; init; }
+
+ ///
+ /// 响应内容
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
+ #else
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string ResponseBody { get; init; }
+
+ ///
+ /// 响应content-type
+ ///
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
+ [Ignore]
+ [JsonIgnore]
+ public virtual string ResponseContentType { get; init; }
+
+ ///
+ /// 响应头
+ ///
+ #if DBTYPE_SQLSERVER
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
+ #else
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
+ #endif
+ [Ignore]
+ [JsonIgnore]
+ public virtual string ResponseHeaders { get; init; }
+
+ ///
+ /// 服务器IP
+ ///
+ [Column]
+ [Ignore]
+ [JsonIgnore]
+ public virtual int? ServerIp { get; init; }
+
+ ///
+ /// 请求跟踪标识
+ ///
+ [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
+ [Ignore]
+ [JsonIgnore]
+ public virtual string TraceId { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/DynamicFilterInfo.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/DynamicFilterInfo.cs
index 607f2ed0..053e0d93 100644
--- a/src/backend/NetAdmin.Domain/Dto/Dependency/DynamicFilterInfo.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Dependency/DynamicFilterInfo.cs
@@ -37,6 +37,42 @@ public sealed record DynamicFilterInfo : DataAbstraction
///
public static implicit operator FreeSql.Internal.Model.DynamicFilterInfo(DynamicFilterInfo d)
{
- return d.Adapt();
+ var ret = d.Adapt();
+ ProcessDynamicFilter(ret);
+ return ret;
+ }
+
+ private static void ProcessDynamicFilter(FreeSql.Internal.Model.DynamicFilterInfo d)
+ {
+ if (d?.Filters != null) {
+ foreach (var filterInfo in d.Filters) {
+ ProcessDynamicFilter(filterInfo);
+ }
+ }
+
+ if (d?.Operator != DynamicFilterOperator.DateRange) {
+ return;
+ }
+
+ var values = ((JsonElement)d.Value).Deserialize();
+ if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
+ var result = values[0]
+ .ExecuteCSharpCodeAsync([typeof(DateTime).Assembly], nameof(System))
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+ values[0] = $"{result:yyyy-MM-dd HH:mm:ss}";
+ }
+
+ if (!DateTime.TryParse(values[1], CultureInfo.InvariantCulture, out _)) {
+ var result = values[1]
+ .ExecuteCSharpCodeAsync([typeof(DateTime).Assembly], nameof(System))
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+ values[1] = $"{result:yyyy-MM-dd HH:mm:ss}";
+ }
+
+ d.Value = values;
}
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Job/CreateJobReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Job/CreateJobReq.cs
index a736fabc..92a84e57 100644
--- a/src/backend/NetAdmin.Domain/Dto/Sys/Job/CreateJobReq.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/Job/CreateJobReq.cs
@@ -32,6 +32,14 @@ public record CreateJobReq : Sys_Job
///
public override long? NextTimeId { get; init; }
+ ///
+ [Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时起始时间不正确))]
+ public override int? RandomDelayBegin { get; init; }
+
+ ///
+ [Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时结束时间不正确))]
+ public override int? RandomDelayEnd { get; init; }
+
///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestBody { get; init; }
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Job/QueryJobRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Job/QueryJobRsp.cs
index b8026dd6..7372ab45 100644
--- a/src/backend/NetAdmin.Domain/Dto/Sys/Job/QueryJobRsp.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/Job/QueryJobRsp.cs
@@ -90,6 +90,14 @@ public record QueryJobRsp : Sys_Job
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? NextTimeId { get; init; }
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override int? RandomDelayBegin { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override int? RandomDelayEnd { get; init; }
+
///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string RequestBody { get; init; }
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs
index f0000cd3..18823b8c 100644
--- a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs
@@ -1,6 +1,12 @@
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
///
/// 请求:创建请求日志
///
-public sealed record CreateRequestLogReq : Sys_RequestLog;
\ No newline at end of file
+public sealed record CreateRequestLogReq : Sys_RequestLog
+{
+ ///
+ public new CreateRequestLogDetailReq Detail { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/ExportRequestLogRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/ExportRequestLogRsp.cs
index c7dcfd7f..9be1816c 100644
--- a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/ExportRequestLogRsp.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/ExportRequestLogRsp.cs
@@ -1,4 +1,7 @@
+using NetAdmin.Domain.Dto.Sys.Api;
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
using NetAdmin.Domain.Dto.Sys.User;
+using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
@@ -7,39 +10,51 @@ namespace NetAdmin.Domain.Dto.Sys.RequestLog;
///
public record ExportRequestLogRsp : QueryRequestLogRsp
{
+ ///
+ /// 接口路径
+ ///
+ [CsvIndex(2)]
+ [JsonInclude]
+ [Name(nameof(Ln.接口路径))]
+ public string ApiId => Api.Id;
+
///
[CsvIndex(6)]
[Ignore(false)]
[Name(nameof(Ln.客户端IP))]
public override string CreatedClientIp => base.CreatedClientIp;
+ ///
+ /// 用户名
+ ///
+ [CsvIndex(5)]
+ [JsonInclude]
+ [Name(nameof(Ln.用户名))]
+ public string UserName => Owner?.UserName;
+
///
[Ignore]
- public override string LoginName => base.LoginName;
+ public override QueryApiRsp Api { get; init; }
///
- [CsvIndex(7)]
- [Ignore(false)]
- [Name(nameof(Ln.操作系统))]
- public override string Os => base.Os;
+ [Ignore]
+ public override DateTime CreatedTime { get; init; }
///
- [CsvIndex(2)]
- [Ignore(false)]
- [Name(nameof(Ln.接口路径))]
- public override string ApiId { get; init; }
-
- ///
- [CsvIndex(8)]
- [Ignore(false)]
- [Name(nameof(Ln.用户代理))]
- public override string CreatedUserAgent { get; init; }
+ [Ignore]
+ public override QueryRequestLogDetailRsp Detail { get; init; }
///
[CsvIndex(4)]
[Ignore(false)]
[Name(nameof(Ln.执行耗时))]
- public override long Duration { get; init; }
+ public override int Duration { get; init; }
+
+ ///
+ [CsvIndex(3)]
+ [Ignore(false)]
+ [Name(nameof(Ln.请求方式))]
+ public override HttpMethods HttpMethod { get; init; }
///
[CsvIndex(1)]
@@ -54,32 +69,14 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
public override long Id { get; init; }
///
- [CsvIndex(3)]
- [Ignore(false)]
- [Name(nameof(Ln.请求方式))]
- public override string Method { get; init; }
-
- ///
- [CsvIndex(9)]
- [Ignore(false)]
- [Name(nameof(Ln.跟踪编号))]
- public override string TraceId { get; init; }
+ [Ignore]
+ public override QueryUserLiteRsp Owner { get; init; }
///
[Ignore]
- public override QueryUserRsp User { get; init; }
-
- ///
- /// 用户名
- ///
- [CsvIndex(5)]
- [Ignore(false)]
- [Name(nameof(Ln.用户名))]
- public string UserName { get; init; }
+ public override long? OwnerDeptId { get; init; }
///
- public override void Register(TypeAdapterConfig config)
- {
- _ = config.ForType().Map(d => d.UserName, s => s.User.UserName);
- }
+ [Ignore]
+ public override long? OwnerId { get; init; }
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs
index e112cc12..6978037e 100644
--- a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs
@@ -1,11 +1,14 @@
+using NetAdmin.Domain.Dto.Sys.Api;
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
using NetAdmin.Domain.Dto.Sys.User;
+using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
///
/// 响应:查询请求日志
///
-public record QueryRequestLogRsp : Sys_RequestLog, IRegister
+public record QueryRequestLogRsp : Sys_RequestLog
{
///
/// 创建者客户端IP
@@ -13,101 +16,39 @@ public record QueryRequestLogRsp : Sys_RequestLog, IRegister
[JsonInclude]
public new virtual string CreatedClientIp => base.CreatedClientIp?.ToIpV4();
- ///
- /// 登录名
- ///
- [JsonInclude]
- public virtual string LoginName => RequestBody?.ToObject()?.Account;
-
- ///
- /// 操作系统
- ///
- [JsonInclude]
- public virtual string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
-
- ///
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string ApiId { get; init; }
+ public new virtual QueryApiRsp Api { get; init; }
- ///
- /// 接口描述
- ///
- public string ApiSummary { get; init; }
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public override int ApiPathCrc32 { get; init; }
///
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; }
- ///
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string CreatedUserAgent { get; init; }
+ public new virtual QueryRequestLogDetailRsp Detail { get; init; }
///
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
- public override long Duration { get; init; }
+ public override int Duration { get; init; }
- ///
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
- public override ErrorCodes ErrorCode { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string Exception { get; init; }
+ public override HttpMethods HttpMethod { get; init; }
///
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override int HttpStatusCode { get; init; }
- ///
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string Method { get; init; }
+ public new virtual QueryUserLiteRsp Owner { get; init; }
- ///
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string RequestBody { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string RequestContentType { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string RequestHeaders { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string RequestUrl { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string ResponseBody { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string ResponseContentType { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string ResponseHeaders { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override int? ServerIp { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override string TraceId { get; init; }
-
- ///
- public new virtual QueryUserRsp User { get; init; }
-
- ///
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public override long? UserId { get; init; }
-
- ///
- public virtual void Register(TypeAdapterConfig config)
- {
- _ = config.ForType().Map(d => d.ApiSummary, s => s.Api.Summary);
- }
+ public override long? OwnerId { get; init; }
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/CreateRequestLogDetailReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/CreateRequestLogDetailReq.cs
new file mode 100644
index 00000000..dfe5c113
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/CreateRequestLogDetailReq.cs
@@ -0,0 +1,6 @@
+namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+
+///
+/// 请求:创建请求日志明细
+///
+public record CreateRequestLogDetailReq : Sys_RequestLogDetail;
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailReq.cs
new file mode 100644
index 00000000..6010cf48
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailReq.cs
@@ -0,0 +1,11 @@
+namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+
+///
+/// 请求:查询请求日志明细
+///
+public sealed record QueryRequestLogDetailReq : Sys_RequestLogDetail
+{
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public override long Id { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailRsp.cs
new file mode 100644
index 00000000..1b04be0e
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLogDetail/QueryRequestLogDetailRsp.cs
@@ -0,0 +1,73 @@
+using NetAdmin.Domain.Dto.Sys.User;
+
+namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+
+///
+/// 响应:查询请求日志明细
+///
+public sealed record QueryRequestLogDetailRsp : Sys_RequestLogDetail
+{
+ ///
+ /// 登录名
+ ///
+ [JsonInclude]
+ public string LoginName => RequestBody?.ToObject()?.Account;
+
+ ///
+ /// 操作系统
+ ///
+ [JsonInclude]
+ public string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string CreatedUserAgent { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public override ErrorCodes ErrorCode { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string Exception { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public override long Id { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string RequestBody { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string RequestContentType { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string RequestHeaders { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string RequestUrl { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string ResponseBody { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string ResponseContentType { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string ResponseHeaders { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override int? ServerIp { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string TraceId { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
new file mode 100644
index 00000000..13e5eff0
--- /dev/null
+++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
@@ -0,0 +1,15 @@
+namespace NetAdmin.Domain.Dto.Sys.User;
+
+///
+/// 响应:查询用户精简版
+///
+public record QueryUserLiteRsp : Sys_User
+{
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public override long Id { get; init; }
+
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public override string UserName { get; init; }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs b/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs
index a494807d..a320670f 100644
--- a/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs
+++ b/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs
@@ -11,20 +11,19 @@ public sealed record SqlCommandAfterEvent : SqlCommandBeforeEvent
public SqlCommandAfterEvent(CommandAfterEventArgs e) //
: base(e)
{
- ElapsedMicroseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000_000);
+ ElapsedMilliseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000);
EventId = nameof(SqlCommandAfterEvent);
}
///
- /// 耗时(单位:微秒)
+ /// 耗时(单位:毫秒)
///
/// de
- private long ElapsedMicroseconds { get; }
+ private long ElapsedMilliseconds { get; }
///
public override string ToString()
{
- return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id
- , Sql?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_SQL), ElapsedMicroseconds / 1000);
+ return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id, Sql, ElapsedMilliseconds);
}
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj b/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj
index 164b150a..89ba658b 100644
--- a/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj
+++ b/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs b/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs
index 4f1d8d04..334067f8 100644
--- a/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs
+++ b/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs
@@ -35,20 +35,15 @@ public abstract class WorkBase
///
protected UnitOfWorkManager UowManager { get; }
- ///
- /// 获取锁
- ///
- protected Task GetLockerAsync(string lockId)
- {
- return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
- , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
- , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
- }
-
///
/// 通用工作流
///
- protected abstract ValueTask WorkflowAsync(CancellationToken cancelToken);
+ protected abstract ValueTask WorkflowAsync( //
+
+ // ReSharper disable once UnusedParameter.Global
+ #pragma warning disable SA1114
+ CancellationToken cancelToken);
+ #pragma warning restore SA1114
///
/// 通用工作流
@@ -69,4 +64,14 @@ public abstract class WorkBase
await WorkflowAsync(cancelToken).ConfigureAwait(false);
}
+
+ ///
+ /// 获取锁
+ ///
+ private Task GetLockerAsync(string lockId)
+ {
+ return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
+ , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
+ , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
+ }
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs b/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs
index 3fba2bd5..b60ebc22 100644
--- a/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs
+++ b/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs
@@ -58,7 +58,7 @@ public sealed class RequestAuditMiddleware(
.FirstOrDefault()
?.Enum() ?? 0;
- _ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMicroseconds, responseBody, errorCode
+ _ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode
, exception)
.ConfigureAwait(false);
}
diff --git a/src/backend/NetAdmin.Host/NetAdmin.Host.csproj b/src/backend/NetAdmin.Host/NetAdmin.Host.csproj
index 59c35c58..938dfc6e 100644
--- a/src/backend/NetAdmin.Host/NetAdmin.Host.csproj
+++ b/src/backend/NetAdmin.Host/NetAdmin.Host.csproj
@@ -5,7 +5,7 @@
-
+
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Host/Utils/RequestLogger.cs b/src/backend/NetAdmin.Host/Utils/RequestLogger.cs
index 75f7d039..a60b3b28 100644
--- a/src/backend/NetAdmin.Host/Utils/RequestLogger.cs
+++ b/src/backend/NetAdmin.Host/Utils/RequestLogger.cs
@@ -1,6 +1,9 @@
using NetAdmin.Domain.Contexts;
using NetAdmin.Domain.Dto.Sys.RequestLog;
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
using NetAdmin.Domain.Events.Sys;
+using Yitter.IdGenerator;
+using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Host.Utils;
@@ -19,36 +22,39 @@ public sealed class RequestLogger(ILogger logger, IEventPublisher
{
// 从请求头中读取用户信息
var associatedUser = GetAssociatedUser(context);
- var auditData = new CreateRequestLogReq {
- Duration = duration
- , Method = context.Request.Method
- , RequestContentType = context.Request.ContentType
- , RequestBody = Array.Exists( //
- _textContentTypes
- , x => context.Request.ContentType?.Contains(
- x, StringComparison.OrdinalIgnoreCase) ?? false)
- ? (await context.ReadBodyContentAsync().ConfigureAwait(false))
- ?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
- : string.Empty
- , RequestUrl = context.Request.GetRequestUrlAddress()
- , ResponseBody
- = responseBody?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
- , ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
- , ApiId = context.Request.Path.Value?.TrimStart('/')
- , RequestHeaders = context.Request.Headers.Json()
- , ResponseContentType = context.Response.ContentType
- , ResponseHeaders = context.Response.Headers.Json()
- , HttpStatusCode = context.Response.StatusCode
- , ErrorCode = errorCode
- , Exception = exception?.Error.ToString()
- , UserId = associatedUser?.UserId
- , CreatedUserAgent = context.Request.Headers.UserAgent.ToString()
- , CreatedClientIp = context.GetRealIpAddress()
- ?.MapToIPv4()
- .ToString()
- .IpV4ToInt32()
- , TraceId = context.TraceIdentifier
- };
+ var id = YitIdHelper.NextId();
+ var requestBody = Array.Exists( //
+ _textContentTypes
+ , x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
+ ? await context.ReadBodyContentAsync().ConfigureAwait(false)
+ : string.Empty;
+ var auditData = new CreateRequestLogReq //
+ {
+ Detail = new CreateRequestLogDetailReq //
+ {
+ Id = id
+ , CreatedUserAgent = context.Request.Headers.UserAgent.ToString()
+ , ErrorCode = errorCode
+ , Exception = exception?.Error.ToString()
+ , RequestBody = requestBody
+ , RequestContentType = context.Request.ContentType
+ , RequestHeaders = context.Request.Headers.Json()
+ , RequestUrl = context.Request.GetRequestUrlAddress()
+ , ResponseBody = responseBody
+ , ResponseContentType = context.Response.ContentType
+ , ResponseHeaders = context.Response.Headers.Json()
+ , ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
+ , TraceId = context.TraceIdentifier
+ }
+ , Duration = (int)duration
+ , HttpMethod = Enum.Parse(context.Request.Method, true)
+ , ApiPathCrc32 = context.Request.Path.Value!.TrimStart('/').Crc32()
+ , HttpStatusCode = context.Response.StatusCode
+ , CreatedClientIp = context.GetRealIpAddress()?.MapToIPv4().ToString().IpV4ToInt32()
+ , OwnerId = associatedUser?.UserId
+ , OwnerDeptId = associatedUser?.DeptId
+ , Id = id
+ };
// 打印日志
logger.Info(auditData);
@@ -59,7 +65,7 @@ public sealed class RequestLogger(ILogger logger, IEventPublisher
return auditData;
}
- private (long UserId, string UserName)? GetAssociatedUser(HttpContext context)
+ private (long UserId, long DeptId, string UserName)? GetAssociatedUser(HttpContext context)
{
var token = context.Request.Headers.Authorization.FirstOrDefault();
if (token == null) {
@@ -69,7 +75,7 @@ public sealed class RequestLogger(ILogger logger, IEventPublisher
ContextUserToken userToken = null;
try {
var jsonWebToken
- = JWTEncryption.ReadJwtToken(token.TrimStart($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} "));
+ = JWTEncryption.ReadJwtToken(token.TrimPrefix($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} "));
var claim = jsonWebToken?.Claims.FirstOrDefault(y => y.Type == nameof(ContextUserToken));
userToken = claim?.Value.ToObject();
}
@@ -77,6 +83,6 @@ public sealed class RequestLogger(ILogger logger, IEventPublisher
logger.Warn($"{Ln.读取用户令牌出错}: {ex}");
}
- return userToken == null ? null : (userToken.Id, userToken.UserName);
+ return userToken == null ? null : (userToken.Id, userToken.DeptId, userToken.UserName);
}
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs b/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs
index 383342a5..b67c4b94 100644
--- a/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs
+++ b/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs
@@ -104,10 +104,10 @@ public sealed class SqlAuditor : ISingleton
case nameof(IFieldCreatedUser.CreatedUserName):
SetCreatedUserName(e, userInfo);
break;
- case nameof(IFieldCreatedClient.CreatedClientIp):
+ case nameof(IFieldCreatedClientIp.CreatedClientIp):
SetCreatedClientIp(e);
break;
- case nameof(IFieldCreatedClient.CreatedUserAgent):
+ case nameof(IFieldCreatedClientUserAgent.CreatedUserAgent):
SetCreatedUserAgent(e);
break;
default:
diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
index d2850dd3..4fde6e5e 100644
--- a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
+++ b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs
@@ -29,6 +29,7 @@ public static class Chars
public const string FLG_DB_FIELD_TYPE_NVARCHAR_MAX = "nvarchar(max)";
public const string FLG_DB_FIELD_TYPE_SMALL_INT = "smallint";
public const string FLG_DB_FIELD_TYPE_TEXT = "text";
+ public const string FLG_DB_FIELD_TYPE_TINY_INT = "tinyint";
public const string FLG_DB_FIELD_TYPE_VARCHAR = "varchar";
public const string FLG_DB_FIELD_TYPE_VARCHAR_1022 = "varchar(1022)";
public const string FLG_DB_FIELD_TYPE_VARCHAR_127 = "varchar(127)";
@@ -54,6 +55,7 @@ public static class Chars
public const string FLG_HTTP_HEADER_KEY_USER_AGENT = "User-Agent";
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN_HEADER_KEY = "X-Authorization";
+ public const string FLG_HTTP_HEADER_KEY_X_CACHE_CONTROL = "X-Cache-Control";
public const string FLG_HTTP_HEADER_KEY_X_FORWARDED_FOR = "X-Forwarded-For";
public const string FLG_HTTP_HEADER_KEY_X_REAL_IP = "X-Real-IP";
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_JSON = "application/json";
@@ -61,6 +63,7 @@ public static class Chars
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_URLENCODED = "application/x-www-form-urlencoded";
public const string FLG_HTTP_HEADER_VALUE_ATTACHMENT = "attachment";
public const string FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA = "Bearer";
+ public const string FLG_HTTP_HEADER_VALUE_NO_CACHE = "no-cache";
public const string FLG_HTTP_METHOD_CONNECT = "CONNECT";
public const string FLG_HTTP_METHOD_DELETE = "DELETE";
public const string FLG_HTTP_METHOD_GET = "GET";
diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs b/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs
index 3f7ce98a..bf4118aa 100644
--- a/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs
+++ b/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs
@@ -30,5 +30,6 @@ public static class Numbers
public const int SECS_RED_LOCK_EXPIRY = 30; // 秒:RedLock-锁过期时间,假如持有锁的进程挂掉,最多在此时间内锁将被释放(如持有锁的进程正常,此值不会生效)
public const int SECS_RED_LOCK_RETRY = 1; // 秒:RedLock-锁等待时间内,多久尝试获取一次
public const int SECS_RED_LOCK_WAIT = 10; // 秒:RedLock-锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
+ public const int SECS_TIMEOUT_HTTP_CLIENT = 15; // 秒:超时时间-默认HTTP客户端
public const int SECS_TIMEOUT_JOB = 600; // 秒:超时时间-作业
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs
index 0158b75d..560dca9c 100644
--- a/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs
+++ b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs
@@ -10,8 +10,7 @@ public static class HttpRequestMessageExtensions
///
public static async Task LogAsync(this HttpRequestMessage me, ILogger logger)
{
- logger.Info(
- $"HTTP Request {(await me.BuildJsonAsync().ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
+ logger.Info($"HTTP Request {await me.BuildJsonAsync().ConfigureAwait(false)}");
return me;
}
diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs
index cacbf0bc..4b31e1e4 100644
--- a/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs
+++ b/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs
@@ -11,8 +11,7 @@ public static class HttpResponseMessageExtensions
public static async Task LogAsync(this HttpResponseMessage me, ILogger logger
, Func bodyPreHandle = null)
{
- logger.Info($"HTTP Response {(await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false))?.Sub(
- 0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
+ logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}");
}
///
@@ -21,8 +20,7 @@ public static class HttpResponseMessageExtensions
public static async Task LogExceptionAsync(this HttpResponseMessage me, string errors, ILogger logger
, Func bodyHandle = null)
{
- logger.Warn(
- $"{errors}: {(await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
+ logger.Warn($"{errors}: {await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false)}");
}
///
diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs
index 7da0d83d..27f6e836 100644
--- a/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs
+++ b/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs
@@ -1,3 +1,6 @@
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+
namespace NetAdmin.Infrastructure.Extensions;
///
@@ -5,8 +8,24 @@ namespace NetAdmin.Infrastructure.Extensions;
///
public static class StringExtensions
{
- private static readonly Regex _regex = new("Options$");
- private static readonly Regex _regex2 = new("Async$");
+ ///
+ /// 计算Crc32
+ ///
+ public static int Crc32(this string me)
+ {
+ return BitConverter.ToInt32(System.IO.Hashing.Crc32.Hash(Encoding.UTF8.GetBytes(me)));
+ }
+
+ ///
+ /// 执行C#代码
+ ///
+ public static Task ExecuteCSharpCodeAsync(this string me, Assembly[] assemblies
+ , params string[] importNamespaces)
+ {
+ // 使用 Roslyn 编译并执行代码
+ return CSharpScript.EvaluateAsync(
+ me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
+ }
///
/// object -> json
@@ -31,7 +50,7 @@ public static class StringExtensions
public static string TrimEndAsync(this string me)
#pragma warning restore VSTHRD200, ASA002, RCS1047
{
- return _regex2.Replace(me, string.Empty);
+ return TrimSuffix(me, "Async");
}
///
@@ -39,14 +58,22 @@ public static class StringExtensions
///
public static string TrimEndOptions(this string me)
{
- return _regex.Replace(me, string.Empty);
+ return TrimSuffix(me, "Options");
}
///
/// 去掉前部字符串
///
- public static string TrimStart(this string me, string clearStr)
+ public static string TrimPrefix(this string me, string clearStr)
{
return Regex.Replace(me, $"^{clearStr}", string.Empty);
}
+
+ ///
+ /// 去掉尾部字符串
+ ///
+ public static string TrimSuffix(this string me, string clearStr)
+ {
+ return Regex.Replace(me, $"{clearStr}$", string.Empty);
+ }
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs b/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs
index b6b84253..360c80eb 100644
--- a/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs
+++ b/src/backend/NetAdmin.Infrastructure/GlobalStatic.cs
@@ -24,11 +24,6 @@ public static class GlobalStatic
#endif
;
- ///
- /// 日志保存跳过的API编号
- ///
- public static string[] LogSavingSkipApiIds => ["api/probe/health.check", "api/adm/device.log/create"];
-
///
/// 系统内部密钥
///
diff --git a/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj
index 5a816980..a3cfa2b6 100644
--- a/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj
+++ b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj
@@ -8,9 +8,10 @@
-
-
-
+
+
+
+
diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs
index 0cddc190..28672120 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs
@@ -42,17 +42,17 @@ public interface IJobModule : ICrudModule
/// 获取作业记录条形图数据
///
- Task> GetRecordBarChartAsync(QueryReq req);
+ Task> GetRecordBarChartAsync(QueryReq req);
///
/// 状态码分组作业记录饼图数据
///
- Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req);
+ Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req);
///
/// 名称分组作业记录饼图数据
///
- Task> GetRecordPieChartByNameAsync(QueryReq req);
+ Task> GetRecordPieChartByNameAsync(QueryReq req);
///
/// 分页查询作业记录
diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogDetailModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogDetailModule.cs
new file mode 100644
index 00000000..9599d737
--- /dev/null
+++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogDetailModule.cs
@@ -0,0 +1,13 @@
+using NetAdmin.Application.Modules;
+using NetAdmin.Domain.Dto.Dependency;
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+
+namespace NetAdmin.SysComponent.Application.Modules.Sys;
+
+///
+/// 请求日志明细模块
+///
+public interface IRequestLogDetailModule : ICrudModule;
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs
index 392c8357..5c38652f 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs
@@ -16,15 +16,15 @@ public interface IRequestLogModule : ICrudModule
/// 获取条形图数据
///
- Task> GetBarChartAsync(QueryReq req);
+ Task> GetBarChartAsync(QueryReq req);
///
/// 描述分组饼图数据
///
- Task> GetPieChartByApiSummaryAsync(QueryReq req);
+ Task> GetPieChartByApiSummaryAsync(QueryReq req);
///
/// 状态码分组饼图数据
///
- Task> GetPieChartByHttpStatusCodeAsync(QueryReq req);
+ Task> GetPieChartByHttpStatusCodeAsync(QueryReq req);
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs
index 39ab4d4b..46b08e4c 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs
@@ -108,13 +108,16 @@ public sealed class ApiService(
QueryApiRsp SelectQueryApiRsp(IGrouping group)
{
var first = group.First()!;
+
+ var id = Regex.Replace( //
+ first.AttributeRouteInfo!.Template!, $"/{first.ActionName}$", string.Empty);
return new QueryApiRsp {
- Summary = xmlCommentReader.GetComments(group.Key)
- , Name = first.ControllerName
- , Id = Regex.Replace( //
- first.AttributeRouteInfo!.Template!, $"/{first.ActionName}$", string.Empty)
+ Summary = xmlCommentReader.GetComments(group.Key)
+ , Name = first.ControllerName
+ , Id = id
, Children = GetChildren(group)
, Namespace = regex.Match(group.Key.Namespace!).Groups[1].Value.ToLowerInvariant()
+ , PathCrc32 = id.Crc32()
};
}
}
@@ -136,19 +139,25 @@ public sealed class ApiService(
private IEnumerable GetChildren(IEnumerable actionDescriptors)
{
return actionDescriptors //
- .Select(x => new QueryApiRsp {
- Summary = xmlCommentReader.GetComments(x.MethodInfo)
- , Name = x.ActionName
- , Id = x.AttributeRouteInfo!.Template
- , Method = x.ActionConstraints?.OfType()
- .FirstOrDefault()
- ?.HttpMethods.First()
- });
+ .Select(x => {
+ var id = x.AttributeRouteInfo!.Template;
+ return new QueryApiRsp {
+ Summary = xmlCommentReader.GetComments(x.MethodInfo)
+ , Name = x.ActionName
+ , Id = id
+ , Method = x.ActionConstraints?.OfType()
+ .FirstOrDefault()
+ ?.HttpMethods.First()
+ , PathCrc32 = id.Crc32()
+ };
+ });
}
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs
index cae388f0..bbd2afc3 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs
@@ -142,6 +142,8 @@ public sealed class ConfigService(BasicRepository rpo) //
.WhereDynamicFilter(req.DynamicFilter)
.WhereIf( //
req.Filter?.Enabled.HasValue ?? false, a => a.Enabled == req.Filter.Enabled.Value);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IJobRecordService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IJobRecordService.cs
index ef70438d..bdfa9b26 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IJobRecordService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IJobRecordService.cs
@@ -14,15 +14,15 @@ public interface IJobRecordService : IService, IJobRecordModule
///
/// 获取条形图数据
///
- Task> GetBarChartAsync(QueryReq req);
+ Task> GetBarChartAsync(QueryReq req);
///
/// 状态码分组饼图数据
///
- Task> GetPieChartByHttpStatusCodeAsync(QueryReq req);
+ Task> GetPieChartByHttpStatusCodeAsync(QueryReq req);
///
/// 名称分组饼图数据
///
- Task> GetPieChartByNameAsync(QueryReq req);
+ Task> GetPieChartByNameAsync(QueryReq req);
}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogDetailService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogDetailService.cs
new file mode 100644
index 00000000..384ab585
--- /dev/null
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogDetailService.cs
@@ -0,0 +1,9 @@
+using NetAdmin.Application.Services;
+using NetAdmin.SysComponent.Application.Modules.Sys;
+
+namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency;
+
+///
+/// 请求日志明细服务
+///
+public interface IRequestLogDetailService : IService, IRequestLogDetailModule;
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs
index e555761b..d34b80f6 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs
@@ -149,6 +149,7 @@ public sealed class DeptService(BasicRepository rpo) //
ret = ret.AsTreeCte();
}
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs
index 603e05b0..ad9eb54c 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs
@@ -175,6 +175,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase
await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
}
+ // ReSharper disable once SeparateLocalFunctionsWithJumpStatement
IEnumerable Select(QueryApiRsp item)
{
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs
index 70eb0217..19a35e4e 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs
@@ -128,6 +128,8 @@ public sealed class DicCatalogService(BasicRepository rpo)
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs
index 3400386d..9b811636 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs
@@ -155,6 +155,8 @@ public sealed class DicContentService(BasicRepository rpo)
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs
index fc1ddcb0..f374a91c 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobRecordService.cs
@@ -80,7 +80,7 @@ public sealed class JobRecordService(BasicRepository rpo) /
}
///
- public async Task> GetBarChartAsync(QueryReq req)
+ public async Task> GetBarChartAsync(QueryReq req)
{
req.ThrowIfInvalid();
@@ -105,8 +105,7 @@ public sealed class JobRecordService(BasicRepository rpo) /
}
///
- public async Task> GetPieChartByHttpStatusCodeAsync(
- QueryReq req)
+ public async Task> GetPieChartByHttpStatusCodeAsync(QueryReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req with { Order = Orders.None })
@@ -124,7 +123,7 @@ public sealed class JobRecordService(BasicRepository rpo) /
}
///
- public async Task> GetPieChartByNameAsync(QueryReq req)
+ public async Task> GetPieChartByNameAsync(QueryReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req with { Order = Orders.None })
@@ -178,6 +177,8 @@ public sealed class JobRecordService(BasicRepository rpo) /
req.Keywords?.Length > 0
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) ||
a.Job.JobName == req.Keywords);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs
index f292dba3..bc0b716f 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs
@@ -77,11 +77,13 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer
.Set(a => a.JobName == req.JobName)
.SetIf(req.RequestHeaders == null, a => a.RequestHeader, null)
.SetIf(req.RequestHeaders != null, a => a.RequestHeader, req.RequestHeaders.Json())
- .Set(a => a.RequestBody == req.RequestBody)
- .Set(a => a.RequestUrl == req.RequestUrl)
- .Set(a => a.UserId == req.UserId)
- .Set(a => a.Summary == req.Summary)
- .Where(a => a.Id == req.Id);
+ .Set(a => a.RequestBody == req.RequestBody)
+ .Set(a => a.RequestUrl == req.RequestUrl)
+ .Set(a => a.RandomDelayBegin == req.RandomDelayBegin)
+ .Set(a => a.RandomDelayEnd == req.RandomDelayEnd)
+ .Set(a => a.UserId == req.UserId)
+ .Set(a => a.Summary == req.Summary)
+ .Where(a => a.Id == req.Id);
#if DBTYPE_SQLSERVER
return (await update.ExecuteUpdatedAsync().ConfigureAwait(false)).FirstOrDefault()?.Adapt();
@@ -236,22 +238,21 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer
}
///
- public Task> GetRecordBarChartAsync(QueryReq req)
+ public Task> GetRecordBarChartAsync(QueryReq req)
{
req.ThrowIfInvalid();
return jobRecordService.GetBarChartAsync(req);
}
///
- public Task> GetRecordPieChartByHttpStatusCodeAsync(
- QueryReq req)
+ public Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req)
{
req.ThrowIfInvalid();
return jobRecordService.GetPieChartByHttpStatusCodeAsync(req);
}
///
- public Task> GetRecordPieChartByNameAsync(QueryReq req)
+ public Task> GetRecordPieChartByNameAsync(QueryReq req)
{
req.ThrowIfInvalid();
return jobRecordService.GetPieChartByNameAsync(req);
@@ -335,6 +336,8 @@ public sealed class JobService(BasicRepository rpo, IJobRecordSer
.WhereIf( //
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs
new file mode 100644
index 00000000..30382365
--- /dev/null
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogDetailService.cs
@@ -0,0 +1,131 @@
+using NetAdmin.Application.Repositories;
+using NetAdmin.Application.Services;
+using NetAdmin.Domain.Dto.Dependency;
+using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
+using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
+
+namespace NetAdmin.SysComponent.Application.Services.Sys;
+
+///
+public sealed class RequestLogDetailService(BasicRepository rpo) //
+ : RepositoryService(rpo), IRequestLogDetailService
+{
+ ///
+ public async Task BulkDeleteAsync(BulkReq req)
+ {
+ req.ThrowIfInvalid();
+ var ret = 0;
+
+ // ReSharper disable once LoopCanBeConvertedToQuery
+ foreach (var item in req.Items) {
+ ret += await DeleteAsync(item).ConfigureAwait(false);
+ }
+
+ return ret;
+ }
+
+ ///
+ public Task CountAsync(QueryReq req)
+ {
+ req.ThrowIfInvalid();
+ return QueryInternal(req)
+ #if DBTYPE_SQLSERVER
+ .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
+ #endif
+ .CountAsync();
+ }
+
+ ///
+ public async Task CreateAsync(CreateRequestLogDetailReq req)
+ {
+ req.ThrowIfInvalid();
+ var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
+ return ret.Adapt();
+ }
+
+ ///
+ public Task DeleteAsync(DelReq req)
+ {
+ req.ThrowIfInvalid();
+ return Rpo.DeleteAsync(a => a.Id == req.Id);
+ }
+
+ ///
+ public Task ExistAsync(QueryReq req)
+ {
+ req.ThrowIfInvalid();
+ return QueryInternal(req)
+ #if DBTYPE_SQLSERVER
+ .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
+ #endif
+ .AnyAsync();
+ }
+
+ ///
+ public Task ExportAsync(QueryReq req)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public async Task GetAsync(QueryRequestLogDetailReq req)
+ {
+ req.ThrowIfInvalid();
+ var ret = await QueryInternal(new QueryReq { Filter = req })
+ .ToOneAsync()
+ .ConfigureAwait(false);
+ return ret.Adapt();
+ }
+
+ ///
+ public async Task> PagedQueryAsync(
+ PagedQueryReq req)
+ {
+ req.ThrowIfInvalid();
+ var list = await QueryInternal(req)
+ .Page(req.Page, req.PageSize)
+ #if DBTYPE_SQLSERVER
+ .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
+ #endif
+ .Count(out var total)
+ .ToListAsync()
+ .ConfigureAwait(false);
+
+ return new PagedQueryRsp(req.Page, req.PageSize, total
+ , list.Adapt>());
+ }
+
+ ///
+ public async Task> QueryAsync(QueryReq req)
+ {
+ req.ThrowIfInvalid();
+ var ret = await QueryInternal(req)
+ #if DBTYPE_SQLSERVER
+ .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
+ #endif
+ .Take(req.Count)
+ .ToListAsync()
+ .ConfigureAwait(false);
+ return ret.Adapt>();
+ }
+
+ private ISelect QueryInternal(QueryReq req)
+ {
+ var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
+ switch (req.Order) {
+ case Orders.None:
+ return ret;
+ case Orders.Random:
+ return ret.OrderByRandom();
+ }
+
+ ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
+ if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
+ ret = ret.OrderByDescending(a => a.Id);
+ }
+
+ return ret;
+ }
+}
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs
index 52298824..1c323dab 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs
@@ -8,7 +8,9 @@ using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys;
///
-public sealed class RequestLogService(BasicRepository rpo) //
+public sealed class RequestLogService(
+ BasicRepository rpo
+ , RequestLogDetailService requestLogDetailService) //
: RepositoryService(rpo), IRequestLogService
{
private static readonly Regex _regex = new(Chars.RGXL_IP_V4);
@@ -43,6 +45,7 @@ public sealed class RequestLogService(BasicRepository rpo)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
+ _ = await requestLogDetailService.CreateAsync(req.Detail).ConfigureAwait(false);
return ret.Adapt();
}
@@ -68,7 +71,17 @@ public sealed class RequestLogService(BasicRepository rpo)
public Task ExportAsync(QueryReq req)
{
req.ThrowIfInvalid();
- return ExportAsync(QueryInternal, req, Ln.请求日志导出);
+ return ExportAsync( //
+ QueryInternal, req, Ln.请求日志导出, a => new {
+ a.Id
+ , Api = new { a.Api.Id }
+ , a.CreatedClientIp
+ , a.CreatedTime
+ , a.Duration
+ , a.HttpMethod
+ , a.HttpStatusCode
+ , Owner = new { a.Owner.UserName }
+ });
}
///
@@ -76,17 +89,18 @@ public sealed class RequestLogService(BasicRepository rpo)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq { Filter = req })
+ .Include(a => a.Detail)
.ToOneAsync()
.ConfigureAwait(false);
return ret.Adapt();
}
///
- public async Task> GetBarChartAsync(QueryReq req)
+ public async Task> GetBarChartAsync(QueryReq req)
{
req.ThrowIfInvalid();
- var ret = await QueryInternal(req with { Order = Orders.None })
+ var ret = await QueryInternal(req with { Order = Orders.None }, false)
#if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
@@ -107,7 +121,7 @@ public sealed class RequestLogService(BasicRepository rpo)
}
///
- public async Task> GetPieChartByApiSummaryAsync(QueryReq req)
+ public async Task> GetPieChartByApiSummaryAsync(QueryReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req with { Order = Orders.None })
@@ -121,11 +135,10 @@ public sealed class RequestLogService(BasicRepository rpo)
}
///
- public async Task> GetPieChartByHttpStatusCodeAsync(
- QueryReq req)
+ public async Task> GetPieChartByHttpStatusCodeAsync(QueryReq req)
{
req.ThrowIfInvalid();
- var ret = await QueryInternal(req with { Order = Orders.None })
+ var ret = await QueryInternal(req with { Order = Orders.None }, false)
#if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
@@ -148,42 +161,40 @@ public sealed class RequestLogService(BasicRepository rpo)
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.Count(out var total);
- object list = req.DynamicFilter?.Filters?.Exists(
- x => nameof(QueryRequestLogReq.ApiId).Equals(x.Field, StringComparison.OrdinalIgnoreCase) &&
- Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Equals( //
- x.Value.ToString(), StringComparison.OrdinalIgnoreCase)) ?? false
- ? await select.ToListAsync(a => new {
- a.ApiId
- , ApiSummary = a.Api.Summary
- , a.CreatedClientIp
- , a.CreatedTime
- , a.Duration
- , a.Method
- , a.CreatedUserAgent
- , a.HttpStatusCode
- , a.Id
- , a.UserId
- , a.User
- , a.RequestBody
- })
- .ConfigureAwait(false)
- : await select.ToListAsync(a => new {
- a.ApiId
- , ApiSummary = a.Api.Summary
- , a.CreatedClientIp
- , a.CreatedTime
- , a.Duration
- , a.Method
- , a.CreatedUserAgent
- , a.HttpStatusCode
- , a.Id
- , a.UserId
- , a.User
- })
- .ConfigureAwait(false);
+
+ object ret
+ = req.DynamicFilter?.Filters?.Exists(
+ x => nameof(QueryRequestLogReq.ApiPathCrc32).Equals(x.Field, StringComparison.OrdinalIgnoreCase) &&
+ x.Value.ToString().Int32() == Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Crc32()) ?? false
+ ? await select.Include(a => a.Detail)
+ .ToListAsync(a => new {
+ Api = new { a.Api.Summary, a.Api.Id }
+ , Owner = new { a.Owner.Id, a.Owner.UserName }
+ , a.CreatedClientIp
+ , a.CreatedTime
+ , a.Duration
+ , a.HttpMethod
+ , a.HttpStatusCode
+ , a.Id
+ , a.ApiPathCrc32
+ , Detail = new { a.Detail.RequestBody, a.Detail.CreatedUserAgent }
+ })
+ .ConfigureAwait(false)
+ : await select.ToListAsync(a => new {
+ Api = new { a.Api.Summary, a.Api.Id }
+ , Owner = new { a.Owner.Id, a.Owner.UserName }
+ , a.CreatedClientIp
+ , a.CreatedTime
+ , a.Duration
+ , a.HttpMethod
+ , a.HttpStatusCode
+ , a.Id
+ , a.ApiPathCrc32
+ })
+ .ConfigureAwait(false);
return new PagedQueryRsp(req.Page, req.PageSize, total
- , list.Adapt>());
+ , ret.Adapt>());
}
///
@@ -202,7 +213,17 @@ public sealed class RequestLogService(BasicRepository rpo)
private ISelect QueryInternal(QueryReq req)
{
- var ret = Rpo.Select.Include(a => a.Api).Include(a => a.User).WhereDynamicFilter(req.DynamicFilter);
+ return QueryInternal(req, true);
+ }
+
+ private ISelect QueryInternal(QueryReq req, bool include)
+ {
+ var ret = Rpo.Select;
+ if (include) {
+ ret = ret.Include(a => a.Api).Include(a => a.Owner);
+ }
+
+ ret = ret.WhereDynamicFilter(req.DynamicFilter);
if (req.Filter?.Id is not 0) {
ret = ret.WhereDynamic(req.Filter);
}
@@ -210,10 +231,11 @@ public sealed class RequestLogService(BasicRepository rpo)
if (req.Keywords?.Length > 0) {
ret = _regex.IsMatch(req.Keywords)
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
- : ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.UserId == req.Keywords.Int64Try(0) ||
- a.User.UserName == req.Keywords || a.RequestBody.Contains(req.Keywords));
+ : ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) ||
+ a.Owner.UserName == req.Keywords);
}
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs
index 6393414f..9e62cc66 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs
@@ -161,6 +161,8 @@ public sealed class RoleService(BasicRepository rpo) //
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) ||
a.Summary.Contains(req.Keywords));
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs
index e100ed10..608fb4c6 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgDeptService.cs
@@ -111,6 +111,8 @@ public sealed class SiteMsgDeptService(BasicRepository rp
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs
index 76e04cd3..8ec8c46a 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgFlagService.cs
@@ -119,6 +119,8 @@ public sealed class SiteMsgFlagService(BasicRepository rp
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs
index 428540a6..7b3fc382 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgRoleService.cs
@@ -111,6 +111,8 @@ public sealed class SiteMsgRoleService(BasicRepository rp
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs
index 02de7190..ab75dac6 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgService.cs
@@ -301,6 +301,8 @@ public sealed class SiteMsgService(
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.Title.Contains(req.Keywords) ||
a.Summary.Contains(req.Keywords));
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs
index 24041f22..52344dfa 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/SiteMsgUserService.cs
@@ -111,6 +111,8 @@ public sealed class SiteMsgUserService(BasicRepository rp
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs
index 5201054b..c73a3bd3 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs
@@ -490,6 +490,8 @@ public sealed class UserService(
, a => a.Id == req.Keywords.Int64Try(0) || a.UserName == req.Keywords ||
a.Mobile == req.Keywords ||
a.Email == req.Keywords || a.Summary.Contains(req.Keywords));
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs
index 8e228d0b..44c41fb4 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs
@@ -198,6 +198,8 @@ public sealed class VerifyCodeService(BasicRepository rpo,
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs
index 487f4750..6621c27a 100644
--- a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs
+++ b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs
@@ -113,6 +113,8 @@ public sealed class ExampleService(BasicRepository rpo) //
private ISelect QueryInternal(QueryReq req)
{
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
+
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
case Orders.None:
return ret;
diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogDetailCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogDetailCache.cs
new file mode 100644
index 00000000..95d93d38
--- /dev/null
+++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogDetailCache.cs
@@ -0,0 +1,10 @@
+using NetAdmin.Cache;
+using NetAdmin.SysComponent.Application.Modules.Sys;
+using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
+
+namespace NetAdmin.SysComponent.Cache.Sys.Dependency;
+
+///
+/// 请求日志明细缓存
+///
+public interface IRequestLogDetailCache : ICache, IRequestLogDetailModule;
\ No newline at end of file
diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs
index 5dce66ea..83a16870 100644
--- a/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs
+++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs
@@ -81,8 +81,8 @@ public sealed class DicCache(IDistributedCache cache, IDicService service) //
public Task GetDicValueAsync(GetDicValueReq req)
{
#if !DEBUG
- return GetOrCreateAsync( //
- GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
+ return GetOrCreateAsync( //
+ GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
, () => Service.GetDicValueAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
#else
return Service.GetDicValueAsync(req);
diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs
index b0ec4393..179bebdc 100644
--- a/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs
+++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs
@@ -85,11 +85,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
}
///
- public Task> GetRecordBarChartAsync(QueryReq req)
+ public Task> GetRecordBarChartAsync(QueryReq req)
{
#if !DEBUG
- return GetOrCreateAsync( //
- GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
+ return GetOrCreateAsync( //
+ GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
, () => Service.GetRecordBarChartAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
#else
return Service.GetRecordBarChartAsync(req);
@@ -97,12 +97,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
}
///
- public Task> GetRecordPieChartByHttpStatusCodeAsync(
- QueryReq req)
+ public Task> GetRecordPieChartByHttpStatusCodeAsync(QueryReq req)
{
#if !DEBUG
- return GetOrCreateAsync( //
- GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
+ return GetOrCreateAsync( //
+ GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
, () => Service.GetRecordPieChartByHttpStatusCodeAsync(req)
, TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
#else
@@ -111,11 +110,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
}
///
- public Task> GetRecordPieChartByNameAsync(QueryReq req)
+ public Task> GetRecordPieChartByNameAsync(QueryReq