mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-20 05:02:50 +08:00
feat: ✨ 框架代码同步 (#158)
[skip ci] Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
parent
60ec6ea2c1
commit
1a28e8d5a6
@ -134,6 +134,8 @@
|
||||
重设密码
|
||||
链接
|
||||
错误
|
||||
随机延时结束时间不正确
|
||||
随机延时起始时间不正确
|
||||
随机排序
|
||||
项值
|
||||
项名
|
||||
|
@ -23,7 +23,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.28.0.94264">
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.29.0.95321">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -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": {
|
||||
|
@ -9,7 +9,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"packageName": "Furion.Pure.NS",
|
||||
"version": "4.9.4-ns1"
|
||||
"version": "4.9.4.6-ns4"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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<int> 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);
|
||||
}
|
||||
|
||||
|
@ -979,7 +979,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1075,7 +1075,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1083,7 +1083,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1099,7 +1099,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1107,8 +1107,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1116,7 +1115,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
@ -30,6 +30,46 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
||||
set => Rpo.DbContextOptions.EnableCascadeSave = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出实体
|
||||
/// </summary>
|
||||
protected async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
||||
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName
|
||||
, Expression<Func<TEntity, object>> 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<List<TExport>>();
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
csv.WriteHeader<TExport>();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新实体
|
||||
/// </summary>
|
||||
@ -77,43 +117,6 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 导出实体
|
||||
/// </summary>
|
||||
protected async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
||||
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> 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<List<TExport>>();
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
csv.WriteHeader<TExport>();
|
||||
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<TEntity> BuildUpdate( //
|
||||
TEntity entity //
|
||||
, IEnumerable<string> includeFields //
|
||||
|
@ -70,7 +70,8 @@ public abstract class DistributedCache<TService>(IDistributedCache cache, TServi
|
||||
, TimeSpan? slideLifeTime = null)
|
||||
{
|
||||
var cacheRead = await GetAsync<T>(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;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,12 @@ namespace NetAdmin.Domain.Contexts;
|
||||
/// </summary>
|
||||
public sealed record ContextUserToken : DataAbstraction
|
||||
{
|
||||
/// <summary>
|
||||
/// 部门编号
|
||||
/// </summary>
|
||||
/// ReSharper disable once MemberCanBePrivate.Global
|
||||
public long DeptId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户编号
|
||||
/// </summary>
|
||||
@ -39,6 +45,8 @@ public sealed record ContextUserToken : DataAbstraction
|
||||
/// </summary>
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端IP字段接口
|
||||
/// </summary>
|
||||
public interface IFieldCreatedClientIp
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
/// </summary>
|
||||
int? CreatedClientIp { get; init; }
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端字段接口
|
||||
/// 创建者客户端用户代理字段接口
|
||||
/// </summary>
|
||||
public interface IFieldCreatedClient
|
||||
public interface IFieldCreatedClientUserAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
/// </summary>
|
||||
int? CreatedClientIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端用户代理
|
||||
/// </summary>
|
@ -0,0 +1,12 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 修改客户端IP字段接口
|
||||
/// </summary>
|
||||
public interface IFieldModifiedClientIp
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端IP
|
||||
/// </summary>
|
||||
int ModifiedClientIp { get; init; }
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 修改客户端字段接口
|
||||
/// 修改客户端用户代理字段接口
|
||||
/// </summary>
|
||||
public interface IFieldModifiedClient
|
||||
public interface IFieldModifiedClientUserAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端IP
|
||||
/// </summary>
|
||||
int ModifiedClientIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端用户代理
|
||||
/// </summary>
|
@ -4,6 +4,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// Api接口表
|
||||
/// </summary>
|
||||
[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<string>, IFieldSummary
|
||||
{
|
||||
/// <summary>
|
||||
@ -54,6 +55,14 @@ public record Sys_Api : ImmutableEntity<string>, IFieldSummary
|
||||
[JsonIgnore]
|
||||
public virtual string ParentId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 路径CRC32
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public int PathCrc32 { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色集合
|
||||
/// </summary>
|
||||
|
@ -18,7 +18,7 @@ public record Sys_DicCatalog : VersionEntity
|
||||
/// <summary>
|
||||
/// 字典编码
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// 字典名称
|
||||
/// </summary>
|
||||
[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; }
|
||||
|
@ -4,8 +4,6 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// 字典内容表
|
||||
/// </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(Value)}", $"{nameof(CatalogId)},{nameof(Value)}"
|
||||
, true)]
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
|
||||
public record Sys_DicContent : VersionEntity
|
||||
{
|
||||
|
@ -79,6 +79,22 @@ public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
|
||||
[JsonIgnore]
|
||||
public virtual long? NextTimeId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 随机延时起始值(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 随机延时结束值(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求体
|
||||
/// </summary>
|
||||
|
@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// 计划作业执行记录表
|
||||
/// </summary>
|
||||
[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))]
|
||||
|
@ -1,36 +1,38 @@
|
||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||
|
||||
namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志表
|
||||
/// </summary>
|
||||
[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
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
[Navigate(nameof(ApiId))]
|
||||
[Navigate(nameof(ApiPathCrc32), TempPrimary = nameof(Sys_Api.PathCrc32))]
|
||||
public Sys_Api Api { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 接口编号
|
||||
/// 接口路径CRC32
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ApiId { get; init; }
|
||||
public virtual int ApiPathCrc32 { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Column(Position = -1)]
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public int? CreatedClientIp { get; init; }
|
||||
public virtual int? CreatedClientIp { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
#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
|
||||
/// <summary>
|
||||
/// 明细
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string CreatedUserAgent { get; init; }
|
||||
[Navigate(nameof(Id))]
|
||||
public Sys_RequestLogDetail Detail { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行耗时(微秒)
|
||||
/// 执行耗时(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual long Duration { get; init; }
|
||||
public virtual int Duration { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序响应码
|
||||
/// 请求方法
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_TINY_INT)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常信息
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP状态码
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_SMALL_INT)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int HttpStatusCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求方法
|
||||
/// 拥有者
|
||||
/// </summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求内容
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头信息
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求地址
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应内容
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应头
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务器IP
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? ServerIp { get; init; }
|
||||
public virtual long? OwnerDeptId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求跟踪标识
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string TraceId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
[Navigate(nameof(UserId))]
|
||||
public Sys_User User { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户编号
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual long? UserId { get; init; }
|
||||
public virtual long? OwnerId { get; init; }
|
||||
}
|
132
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
Normal file
132
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
Normal file
@ -0,0 +1,132 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细表
|
||||
/// </summary>
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLogDetail))]
|
||||
public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCreatedClientUserAgent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序响应码
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常信息
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求内容
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头信息
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求地址
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应内容
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应头
|
||||
/// </summary>
|
||||
#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; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务器IP
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? ServerIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求跟踪标识
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string TraceId { get; init; }
|
||||
}
|
@ -37,6 +37,42 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
||||
/// </summary>
|
||||
public static implicit operator FreeSql.Internal.Model.DynamicFilterInfo(DynamicFilterInfo d)
|
||||
{
|
||||
return d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>();
|
||||
var ret = d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>();
|
||||
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<string[]>();
|
||||
if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
|
||||
var result = values[0]
|
||||
.ExecuteCSharpCodeAsync<DateTime>([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<DateTime>([typeof(DateTime).Assembly], nameof(System))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
values[1] = $"{result:yyyy-MM-dd HH:mm:ss}";
|
||||
}
|
||||
|
||||
d.Value = values;
|
||||
}
|
||||
}
|
@ -32,6 +32,14 @@ public record CreateJobReq : Sys_Job
|
||||
/// <inheritdoc />
|
||||
public override long? NextTimeId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时起始时间不正确))]
|
||||
public override int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时结束时间不正确))]
|
||||
public override int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_Job.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
@ -90,6 +90,14 @@ public record QueryJobRsp : Sys_Job
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override long? NextTimeId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_Job.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
@ -1,6 +1,12 @@
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:创建请求日志
|
||||
/// </summary>
|
||||
public sealed record CreateRequestLogReq : Sys_RequestLog;
|
||||
public sealed record CreateRequestLogReq : Sys_RequestLog
|
||||
{
|
||||
/// <inheritdoc cref="Sys_RequestLog.Detail" />
|
||||
public new CreateRequestLogDetailReq Detail { get; init; }
|
||||
}
|
@ -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;
|
||||
/// </summary>
|
||||
public record ExportRequestLogRsp : QueryRequestLogRsp
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口路径
|
||||
/// </summary>
|
||||
[CsvIndex(2)]
|
||||
[JsonInclude]
|
||||
[Name(nameof(Ln.接口路径))]
|
||||
public string ApiId => Api.Id;
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(6)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.客户端IP))]
|
||||
public override string CreatedClientIp => base.CreatedClientIp;
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[CsvIndex(5)]
|
||||
[JsonInclude]
|
||||
[Name(nameof(Ln.用户名))]
|
||||
public string UserName => Owner?.UserName;
|
||||
|
||||
/// <inheritdoc />
|
||||
[Ignore]
|
||||
public override string LoginName => base.LoginName;
|
||||
public override QueryApiRsp Api { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(7)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.操作系统))]
|
||||
public override string Os => base.Os;
|
||||
[Ignore]
|
||||
public override DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(2)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.接口路径))]
|
||||
public override string ApiId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(8)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.用户代理))]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
[Ignore]
|
||||
public override QueryRequestLogDetailRsp Detail { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(4)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.执行耗时))]
|
||||
public override long Duration { get; init; }
|
||||
public override int Duration { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(3)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.请求方式))]
|
||||
public override HttpMethods HttpMethod { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(1)]
|
||||
@ -54,32 +69,14 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(3)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.请求方式))]
|
||||
public override string Method { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(9)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.跟踪编号))]
|
||||
public override string TraceId { get; init; }
|
||||
[Ignore]
|
||||
public override QueryUserLiteRsp Owner { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Ignore]
|
||||
public override QueryUserRsp User { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[CsvIndex(5)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.用户名))]
|
||||
public string UserName { get; init; }
|
||||
public override long? OwnerDeptId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Register(TypeAdapterConfig config)
|
||||
{
|
||||
_ = config.ForType<Sys_RequestLog, ExportRequestLogRsp>().Map(d => d.UserName, s => s.User.UserName);
|
||||
}
|
||||
[Ignore]
|
||||
public override long? OwnerId { get; init; }
|
||||
}
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询请求日志
|
||||
/// </summary>
|
||||
public record QueryRequestLogRsp : Sys_RequestLog, IRegister
|
||||
public record QueryRequestLogRsp : Sys_RequestLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
@ -13,101 +16,39 @@ public record QueryRequestLogRsp : Sys_RequestLog, IRegister
|
||||
[JsonInclude]
|
||||
public new virtual string CreatedClientIp => base.CreatedClientIp?.ToIpV4();
|
||||
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public virtual string LoginName => RequestBody?.ToObject<LoginByPwdReq>()?.Account;
|
||||
|
||||
/// <summary>
|
||||
/// 操作系统
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public virtual string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ApiId" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Api" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ApiId { get; init; }
|
||||
public new virtual QueryApiRsp Api { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 接口描述
|
||||
/// </summary>
|
||||
public string ApiSummary { get; init; }
|
||||
/// <inheritdoc cref="Sys_RequestLog.ApiPathCrc32" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override int ApiPathCrc32 { get; init; }
|
||||
|
||||
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.CreatedUserAgent" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Detail" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
public new virtual QueryRequestLogDetailRsp Detail { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Duration" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Duration { get; init; }
|
||||
public override int Duration { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ErrorCode" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.HttpMethod" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Exception" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Exception { get; init; }
|
||||
public override HttpMethods HttpMethod { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.HttpStatusCode" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override int HttpStatusCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Method" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Owner" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Method { get; init; }
|
||||
public new virtual QueryUserLiteRsp Owner { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestBody" />
|
||||
/// <inheritdoc cref="IFieldOwner.OwnerId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestUrl" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestUrl { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ServerIp" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? ServerIp { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.TraceId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string TraceId { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.User" />
|
||||
public new virtual QueryUserRsp User { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.UserId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override long? UserId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Register(TypeAdapterConfig config)
|
||||
{
|
||||
_ = config.ForType<Sys_RequestLog, QueryRequestLogRsp>().Map(d => d.ApiSummary, s => s.Api.Summary);
|
||||
}
|
||||
public override long? OwnerId { get; init; }
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:创建请求日志明细
|
||||
/// </summary>
|
||||
public record CreateRequestLogDetailReq : Sys_RequestLogDetail;
|
@ -0,0 +1,11 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:查询请求日志明细
|
||||
/// </summary>
|
||||
public sealed record QueryRequestLogDetailReq : Sys_RequestLogDetail
|
||||
{
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
using NetAdmin.Domain.Dto.Sys.User;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询请求日志明细
|
||||
/// </summary>
|
||||
public sealed record QueryRequestLogDetailRsp : Sys_RequestLogDetail
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public string LoginName => RequestBody?.ToObject<LoginByPwdReq>()?.Account;
|
||||
|
||||
/// <summary>
|
||||
/// 操作系统
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
|
||||
|
||||
/// <inheritdoc cref="IFieldCreatedClientUserAgent.CreatedUserAgent" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ErrorCode" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.Exception" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Exception { get; init; }
|
||||
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestUrl" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestUrl { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ServerIp" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? ServerIp { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.TraceId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string TraceId { get; init; }
|
||||
}
|
15
src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
Normal file
15
src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.User;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询用户精简版
|
||||
/// </summary>
|
||||
public record QueryUserLiteRsp : Sys_User
|
||||
{
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_User.UserName" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string UserName { get; init; }
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 耗时(单位:微秒)
|
||||
/// 耗时(单位:毫秒)
|
||||
/// </summary>
|
||||
/// de
|
||||
private long ElapsedMicroseconds { get; }
|
||||
private long ElapsedMilliseconds { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
<ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CronExpressionDescriptor" Version="2.34.0"/>
|
||||
<PackageReference Include="CronExpressionDescriptor" Version="2.36.0"/>
|
||||
<PackageReference Include="Cronos" Version="0.8.4"/>
|
||||
<PackageReference Include="CsvHelper.NS" Version="33.0.2-ns2"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.6.24328.4"/>
|
||||
|
@ -35,20 +35,15 @@ public abstract class WorkBase<TLogger>
|
||||
/// </summary>
|
||||
protected UnitOfWorkManager UowManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取锁
|
||||
/// </summary>
|
||||
protected Task<IRedLock> 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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用工作流
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// 通用工作流
|
||||
@ -69,4 +64,14 @@ public abstract class WorkBase<TLogger>
|
||||
|
||||
await WorkflowAsync(cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取锁
|
||||
/// </summary>
|
||||
private Task<IRedLock> 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));
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ public sealed class RequestAuditMiddleware(
|
||||
.FirstOrDefault()
|
||||
?.Enum<ErrorCodes>() ?? 0;
|
||||
|
||||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMicroseconds, responseBody, errorCode
|
||||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode
|
||||
, exception)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns2"/>
|
||||
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.161"/>
|
||||
<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"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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<RequestLogger> 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<HttpMethods>(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<RequestLogger> 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<RequestLogger> 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<ContextUserToken>();
|
||||
}
|
||||
@ -77,6 +83,6 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
||||
logger.Warn($"{Ln.读取用户令牌出错}: {ex}");
|
||||
}
|
||||
|
||||
return userToken == null ? null : (userToken.Id, userToken.UserName);
|
||||
return userToken == null ? null : (userToken.Id, userToken.DeptId, userToken.UserName);
|
||||
}
|
||||
}
|
@ -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:
|
||||
|
@ -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";
|
||||
|
@ -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; // 秒:超时时间-作业
|
||||
}
|
@ -10,8 +10,7 @@ public static class HttpRequestMessageExtensions
|
||||
/// </summary>
|
||||
public static async Task<HttpRequestMessage> LogAsync<T>(this HttpRequestMessage me, ILogger<T> 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;
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,7 @@ public static class HttpResponseMessageExtensions
|
||||
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger
|
||||
, Func<string, string> 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)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -21,8 +20,7 @@ public static class HttpResponseMessageExtensions
|
||||
public static async Task LogExceptionAsync<T>(this HttpResponseMessage me, string errors, ILogger<T> logger
|
||||
, Func<string, string> 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)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,3 +1,6 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
|
||||
namespace NetAdmin.Infrastructure.Extensions;
|
||||
|
||||
/// <summary>
|
||||
@ -5,8 +8,24 @@ namespace NetAdmin.Infrastructure.Extensions;
|
||||
/// </summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
private static readonly Regex _regex = new("Options$");
|
||||
private static readonly Regex _regex2 = new("Async$");
|
||||
/// <summary>
|
||||
/// 计算Crc32
|
||||
/// </summary>
|
||||
public static int Crc32(this string me)
|
||||
{
|
||||
return BitConverter.ToInt32(System.IO.Hashing.Crc32.Hash(Encoding.UTF8.GetBytes(me)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行C#代码
|
||||
/// </summary>
|
||||
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies
|
||||
, params string[] importNamespaces)
|
||||
{
|
||||
// 使用 Roslyn 编译并执行代码
|
||||
return CSharpScript.EvaluateAsync<T>(
|
||||
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -39,14 +58,22 @@ public static class StringExtensions
|
||||
/// </summary>
|
||||
public static string TrimEndOptions(this string me)
|
||||
{
|
||||
return _regex.Replace(me, string.Empty);
|
||||
return TrimSuffix(me, "Options");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去掉前部字符串
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去掉尾部字符串
|
||||
/// </summary>
|
||||
public static string TrimSuffix(this string me, string clearStr)
|
||||
{
|
||||
return Regex.Replace(me, $"{clearStr}$", string.Empty);
|
||||
}
|
||||
}
|
@ -24,11 +24,6 @@ public static class GlobalStatic
|
||||
#endif
|
||||
;
|
||||
|
||||
/// <summary>
|
||||
/// 日志保存跳过的API编号
|
||||
/// </summary>
|
||||
public static string[] LogSavingSkipApiIds => ["api/probe/health.check", "api/adm/device.log/create"];
|
||||
|
||||
/// <summary>
|
||||
/// 系统内部密钥
|
||||
/// </summary>
|
||||
|
@ -8,9 +8,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-preview20260627-ns1"/>
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-preview20260627-ns1"/>
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4"/>
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4-ns1"/>
|
||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.4-ns1"/>
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4.6"/>
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4.6-ns4"/>
|
||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.4.6-ns4"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.10.0"/>
|
||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||
<PackageReference Include="NSExt" Version="2.2.0"/>
|
||||
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
||||
|
@ -42,17 +42,17 @@ public interface IJobModule : ICrudModule<CreateJobReq, QueryJobRsp // 创建类
|
||||
/// <summary>
|
||||
/// 获取作业记录条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组作业记录饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 名称分组作业记录饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询作业记录
|
||||
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细模块
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailModule : ICrudModule<CreateRequestLogDetailReq, QueryRequestLogDetailRsp // 创建类型
|
||||
, QueryRequestLogDetailReq, QueryRequestLogDetailRsp // 查询类型
|
||||
, DelReq // 删除类型
|
||||
>;
|
@ -16,15 +16,15 @@ public interface IRequestLogModule : ICrudModule<CreateRequestLogReq, QueryReque
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 描述分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req);
|
||||
}
|
@ -108,13 +108,16 @@ public sealed class ApiService(
|
||||
QueryApiRsp SelectQueryApiRsp(IGrouping<TypeInfo, ControllerActionDescriptor> 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<QueryApiRsp> GetChildren(IEnumerable<ControllerActionDescriptor> actionDescriptors)
|
||||
{
|
||||
return actionDescriptors //
|
||||
.Select(x => new QueryApiRsp {
|
||||
Summary = xmlCommentReader.GetComments(x.MethodInfo)
|
||||
, Name = x.ActionName
|
||||
, Id = x.AttributeRouteInfo!.Template
|
||||
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>()
|
||||
.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<HttpMethodActionConstraint>()
|
||||
.FirstOrDefault()
|
||||
?.HttpMethods.First()
|
||||
, PathCrc32 = id.Crc32()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private ISelect<Sys_Api> QueryInternal(QueryReq<QueryApiReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -142,6 +142,8 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> 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;
|
||||
|
@ -14,15 +14,15 @@ public interface IJobRecordService : IService, IJobRecordModule
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 名称分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using NetAdmin.Application.Services;
|
||||
using NetAdmin.SysComponent.Application.Modules.Sys;
|
||||
|
||||
namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细服务
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailService : IService, IRequestLogDetailModule;
|
@ -149,6 +149,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
|
||||
ret = ret.AsTreeCte();
|
||||
}
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -175,6 +175,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
||||
await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// ReSharper disable once SeparateLocalFunctionsWithJumpStatement
|
||||
IEnumerable<string> Select(QueryApiRsp item)
|
||||
{
|
||||
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
|
||||
|
@ -128,6 +128,8 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
||||
private ISelect<Sys_DicCatalog> QueryInternal(QueryReq<QueryDicCatalogReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -155,6 +155,8 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
||||
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -80,7 +80,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
|
||||
@ -105,8 +105,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -124,7 +123,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -178,6 +177,8 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> 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;
|
||||
|
@ -77,11 +77,13 @@ public sealed class JobService(BasicRepository<Sys_Job, long> 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<QueryJobRsp>();
|
||||
@ -236,22 +238,21 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetBarChartAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetPieChartByNameAsync(req);
|
||||
@ -335,6 +336,8 @@ public sealed class JobService(BasicRepository<Sys_Job, long> 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;
|
||||
|
@ -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;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogDetailService" />
|
||||
public sealed class RequestLogDetailService(BasicRepository<Sys_RequestLogDetail, long> rpo) //
|
||||
: RepositoryService<Sys_RequestLogDetail, long, IRequestLogDetailService>(rpo), IRequestLogDetailService
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = 0;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var item in req.Items) {
|
||||
ret += await DeleteAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return QueryInternal(req)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.CountAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<QueryRequestLogDetailRsp> CreateAsync(CreateRequestLogDetailReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogDetailRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> DeleteAsync(DelReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return Rpo.DeleteAsync(a => a.Id == req.Id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> ExistAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return QueryInternal(req)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.AnyAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<QueryRequestLogDetailRsp> GetAsync(QueryRequestLogDetailReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(new QueryReq<QueryRequestLogDetailReq> { Filter = req })
|
||||
.ToOneAsync()
|
||||
.ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogDetailRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<PagedQueryRsp<QueryRequestLogDetailRsp>> PagedQueryAsync(
|
||||
PagedQueryReq<QueryRequestLogDetailReq> 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<QueryRequestLogDetailRsp>(req.Page, req.PageSize, total
|
||||
, list.Adapt<IEnumerable<QueryRequestLogDetailRsp>>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<QueryRequestLogDetailRsp>> QueryAsync(QueryReq<QueryRequestLogDetailReq> 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<IEnumerable<QueryRequestLogDetailRsp>>();
|
||||
}
|
||||
|
||||
private ISelect<Sys_RequestLogDetail> QueryInternal(QueryReq<QueryRequestLogDetailReq> 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;
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogService" />
|
||||
public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo) //
|
||||
public sealed class RequestLogService(
|
||||
BasicRepository<Sys_RequestLog, long> rpo
|
||||
, RequestLogDetailService requestLogDetailService) //
|
||||
: RepositoryService<Sys_RequestLog, long, IRequestLogService>(rpo), IRequestLogService
|
||||
{
|
||||
private static readonly Regex _regex = new(Chars.RGXL_IP_V4);
|
||||
@ -43,6 +45,7 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||
_ = await requestLogDetailService.CreateAsync(req.Detail).ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogRsp>();
|
||||
}
|
||||
|
||||
@ -68,7 +71,17 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return ExportAsync<QueryRequestLogReq, ExportRequestLogRsp>(QueryInternal, req, Ln.请求日志导出);
|
||||
return ExportAsync<QueryRequestLogReq, ExportRequestLogRsp>( //
|
||||
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 }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -76,17 +89,18 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(new QueryReq<QueryRequestLogReq> { Filter = req })
|
||||
.Include(a => a.Detail)
|
||||
.ToOneAsync()
|
||||
.ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> 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<Sys_RequestLog, long> rpo)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -121,11 +135,10 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> 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<Sys_RequestLog, long> 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<QueryRequestLogRsp>(req.Page, req.PageSize, total
|
||||
, list.Adapt<IEnumerable<QueryRequestLogRsp>>());
|
||||
, ret.Adapt<IEnumerable<QueryRequestLogRsp>>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -202,7 +213,17 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
|
||||
private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.Include(a => a.Api).Include(a => a.User).WhereDynamicFilter(req.DynamicFilter);
|
||||
return QueryInternal(req, true);
|
||||
}
|
||||
|
||||
private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> 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<Sys_RequestLog, long> 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;
|
||||
|
@ -161,6 +161,8 @@ public sealed class RoleService(BasicRepository<Sys_Role, long> 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;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgDeptService(BasicRepository<Sys_SiteMsgDept, long> rp
|
||||
private ISelect<Sys_SiteMsgDept> QueryInternal(QueryReq<QuerySiteMsgDeptReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -119,6 +119,8 @@ public sealed class SiteMsgFlagService(BasicRepository<Sys_SiteMsgFlag, long> rp
|
||||
private ISelect<Sys_SiteMsgFlag> QueryInternal(QueryReq<QuerySiteMsgFlagReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgRoleService(BasicRepository<Sys_SiteMsgRole, long> rp
|
||||
private ISelect<Sys_SiteMsgRole> QueryInternal(QueryReq<QuerySiteMsgRoleReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -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;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgUserService(BasicRepository<Sys_SiteMsgUser, long> rp
|
||||
private ISelect<Sys_SiteMsgUser> QueryInternal(QueryReq<QuerySiteMsgUserReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -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;
|
||||
|
@ -198,6 +198,8 @@ public sealed class VerifyCodeService(BasicRepository<Sys_VerifyCode, long> rpo,
|
||||
private ISelect<Sys_VerifyCode> QueryInternal(QueryReq<QueryVerifyCodeReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -113,6 +113,8 @@ public sealed class ExampleService(BasicRepository<Tpl_Example, long> rpo) //
|
||||
private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细缓存
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailCache : ICache<IDistributedCache, IRequestLogDetailService>, IRequestLogDetailModule;
|
@ -81,8 +81,8 @@ public sealed class DicCache(IDistributedCache cache, IDicService service) //
|
||||
public Task<string> 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);
|
||||
|
@ -85,11 +85,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> 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)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> 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)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetRecordPieChartByNameAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetRecordPieChartByNameAsync(req);
|
||||
|
@ -18,9 +18,22 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
#if !DEBUG
|
||||
public async Task<long> CountAsync(QueryReq<QueryRequestLogReq> req)
|
||||
#else
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogReq> req)
|
||||
#endif
|
||||
{
|
||||
#if !DEBUG
|
||||
var ret = await GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, async () => (long?)await Service.CountAsync(req).ConfigureAwait(false)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT))
|
||||
.ConfigureAwait(false);
|
||||
return ret ?? 0;
|
||||
#else
|
||||
return Service.CountAsync(req);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -54,11 +67,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetBarChartAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetBarChartAsync(req);
|
||||
@ -66,11 +79,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetPieChartByApiSummaryAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetPieChartByApiSummaryAsync(req);
|
||||
@ -78,11 +91,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetPieChartByHttpStatusCodeAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetPieChartByHttpStatusCodeAsync(req);
|
||||
|
@ -0,0 +1,66 @@
|
||||
using NetAdmin.Cache;
|
||||
using NetAdmin.Domain.Dto.Dependency;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||
|
||||
namespace NetAdmin.SysComponent.Cache.Sys;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogDetailCache" />
|
||||
public sealed class RequestLogDetailCache(IDistributedCache cache, IRequestLogDetailService service)
|
||||
: DistributedCache<IRequestLogDetailService>(cache, service), IScoped, IRequestLogDetailCache
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||
{
|
||||
return Service.BulkDeleteAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.CountAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<QueryRequestLogDetailRsp> CreateAsync(CreateRequestLogDetailReq req)
|
||||
{
|
||||
return Service.CreateAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> DeleteAsync(DelReq req)
|
||||
{
|
||||
return Service.DeleteAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> ExistAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.ExistAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.ExportAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<QueryRequestLogDetailRsp> GetAsync(QueryRequestLogDetailReq req)
|
||||
{
|
||||
return Service.GetAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<PagedQueryRsp<QueryRequestLogDetailRsp>> PagedQueryAsync(PagedQueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.PagedQueryAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IEnumerable<QueryRequestLogDetailRsp>> QueryAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.QueryAsync(req);
|
||||
}
|
||||
}
|
@ -99,8 +99,8 @@ public sealed class UserCache(IDistributedCache cache, IUserService service, IVe
|
||||
public Task<IEnumerable<QueryUserRsp>> QueryAsync(QueryReq<QueryUserReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.QueryAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
|
||||
#else
|
||||
return Service.QueryAsync(req);
|
||||
|
@ -119,7 +119,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 获取作业记录条形图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordBarChartAsync(req);
|
||||
}
|
||||
@ -127,8 +127,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 状态码分组作业记录饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
@ -136,7 +135,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 名称分组作业记录饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordPieChartByNameAsync(req);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetBarChartAsync(req);
|
||||
}
|
||||
@ -90,7 +90,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 描述分组饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetPieChartByApiSummaryAsync(req);
|
||||
}
|
||||
@ -98,7 +98,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
|
@ -66,7 +66,18 @@ public sealed class ScheduledJob : WorkBase<ScheduledJob>, IJob
|
||||
}
|
||||
|
||||
var request = BuildRequest(job);
|
||||
var sw = new Stopwatch();
|
||||
|
||||
// 随机延时
|
||||
if (job.RandomDelayBegin is > 0 && job.RandomDelayEnd is > 0) {
|
||||
var (start, end) = (job.RandomDelayBegin.Value, job.RandomDelayEnd.Value);
|
||||
if (start > end) {
|
||||
(start, end) = (end, start);
|
||||
}
|
||||
|
||||
await Task.Delay(new[] { start, end }.Rand(), CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var rsp = await request.SendAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
if (rsp.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden) {
|
||||
|
@ -18,13 +18,6 @@ public sealed class OperationLogger : IEventSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳过指定的请求
|
||||
if (Array.Exists( //
|
||||
GlobalStatic.LogSavingSkipApiIds
|
||||
, x => x.Equals(operationEvent.Data.ApiId, StringComparison.OrdinalIgnoreCase))) {
|
||||
return;
|
||||
}
|
||||
|
||||
operationEvent.Data.TruncateStrings();
|
||||
_ = await App.GetService<IRequestLogService>().CreateAsync(operationEvent.Data).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -11,14 +11,14 @@
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"ace-builds": "^1.35.2",
|
||||
"aieditor": "^1.0.12",
|
||||
"aieditor": "^1.0.13",
|
||||
"axios": "^1.7.2",
|
||||
"clipboard": "^2.0.11",
|
||||
"core-js": "^3.37.1",
|
||||
"cropperjs": "^1.6.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"echarts": "^5.5.1",
|
||||
"element-plus": "^2.7.6",
|
||||
"element-plus": "^2.7.7",
|
||||
"json-bigint": "^1.0.0",
|
||||
"json5-to-table": "^0.1.8",
|
||||
"markdown-it": "^14.1.0",
|
||||
@ -38,11 +38,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-organize-attributes": "^1.0.0",
|
||||
"sass": "^1.77.6",
|
||||
"terser": "^5.31.1",
|
||||
"vite": "^5.3.3"
|
||||
"sass": "^1.77.8",
|
||||
"terser": "^5.31.3",
|
||||
"vite": "^5.3.4"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<el-table-column v-bind="$attrs">
|
||||
<template #default="{ row }">
|
||||
<div @click="click($TOOL.getNestedProperty(row, $attrs.prop))" class="avatar">
|
||||
<div
|
||||
:style="{ display: $TOOL.getNestedProperty(row, $attrs.prop) ? 'flex' : 'none' }"
|
||||
@click="click($TOOL.getNestedProperty(row, $attrs.prop))"
|
||||
class="avatar">
|
||||
<el-avatar v-if="$TOOL.getNestedProperty(row, $attrs.nestProp)" :src="getAvatar(row, $attrs.nestProp)" size="small"></el-avatar>
|
||||
<div>
|
||||
<p>{{ $TOOL.getNestedProperty(row, $attrs.nestProp) }}</p>
|
||||
|
@ -94,7 +94,7 @@ export default {
|
||||
return {
|
||||
dateShortCuts: [
|
||||
{
|
||||
text: this.$t('今天'),
|
||||
text: this.$t('今日'),
|
||||
value: () => {
|
||||
const start = new Date()
|
||||
start.setHours(0, 0, 0, 0)
|
||||
@ -102,7 +102,7 @@ export default {
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$t('昨天'),
|
||||
text: this.$t('昨日'),
|
||||
value: () => {
|
||||
const start = new Date()
|
||||
start.setHours(0, 0, 0, 0)
|
||||
@ -111,7 +111,17 @@ export default {
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$t('最近三天'),
|
||||
text: this.$t('后退一日'),
|
||||
value: () => {
|
||||
try {
|
||||
const start = new Date(new Date(this.form.dy.createdTime[0]) - 3600 * 1000 * 24)
|
||||
const end = new Date(new Date(this.form.dy.createdTime[1]) - 3600 * 1000 * 24)
|
||||
return [start, end]
|
||||
} catch {}
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$t('最近三日'),
|
||||
value: () => {
|
||||
const start = new Date()
|
||||
start.setHours(0, 0, 0, 0)
|
||||
@ -342,6 +352,16 @@ export default {
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$t('后退一时'),
|
||||
value: () => {
|
||||
try {
|
||||
const start = new Date(new Date(this.form.dy.createdTime[0]) - 3600 * 1000)
|
||||
const end = new Date(new Date(this.form.dy.createdTime[1]) - 3600 * 1000)
|
||||
return [start, end]
|
||||
} catch {}
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$t('昨日此时'),
|
||||
value: () => {
|
||||
|
@ -349,9 +349,9 @@ export default {
|
||||
两次输入密码不一致: 'The two passwords entered are inconsistent',
|
||||
必须提供当前登录用户密码才能进行更改: 'You must provide the current login user password to change',
|
||||
设置密码: 'Set password',
|
||||
今天: 'Today',
|
||||
昨天: 'Yesterday',
|
||||
最近三天: 'Last 3 days',
|
||||
今日: 'Today',
|
||||
昨日: 'Yesterday',
|
||||
最近三日: 'Last 3 days',
|
||||
最近一周: 'Last week',
|
||||
最近一月: 'Last month',
|
||||
最近三月: 'Last 3 months',
|
||||
@ -484,4 +484,6 @@ export default {
|
||||
'访问趋势(Today)': 'Access trend (Today)',
|
||||
'作业分布(Today)': 'Job distribution (Today)',
|
||||
'作业趋势(Today)': 'Job trend (Today)',
|
||||
后退一时: 'Back an hour',
|
||||
后退一日: 'Back a day',
|
||||
}
|
@ -348,9 +348,9 @@ export default {
|
||||
两次输入密码不一致: '两次输入密码不一致',
|
||||
必须提供当前登录用户密码才能进行更改: '必须提供当前登录用户密码才能进行更改',
|
||||
设置密码: '设置密码',
|
||||
今天: '今天',
|
||||
昨天: '昨天',
|
||||
最近三天: '最近三天',
|
||||
今日: '今日',
|
||||
昨日: '昨日',
|
||||
最近三日: '最近三日',
|
||||
最近一周: '最近一周',
|
||||
最近一月: '最近一月',
|
||||
最近三月: '最近三月',
|
||||
@ -481,4 +481,6 @@ export default {
|
||||
'访问趋势(Today)': '访问趋势(Today)',
|
||||
'作业分布(Today)': '作业分布(Today)',
|
||||
'作业趋势(Today)': '作业趋势(Today)',
|
||||
后退一时: '后退一时',
|
||||
后退一日: '后退一日',
|
||||
}
|
@ -505,6 +505,10 @@ textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h100p {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
@ -527,4 +531,24 @@ textarea {
|
||||
|
||||
.font-monospace {
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
|
||||
}
|
||||
|
||||
.trace-log {
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
margin: 2rem 0;
|
||||
border-bottom: var(--el-color-primary) 1px dashed;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.w15 {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.keywords-highlight {
|
||||
background-color: yellow;
|
||||
color: var(--el-color-black);
|
||||
}
|
@ -251,6 +251,15 @@ tool.groupSeparator = function (num) {
|
||||
tool.unicodeDecode = function (str) {
|
||||
return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, grp) => String.fromCharCode(parseInt(grp, 16)))
|
||||
}
|
||||
// 高亮关键词
|
||||
tool.highLightKeywords = function (str) {
|
||||
console.error(str)
|
||||
var ret = str
|
||||
.replace(new RegExp('(Body)', 'gi'), '<span class=keywords-highlight>$1</span>')
|
||||
.replace(new RegExp('(http://cloud_code_adm_api.*?),', 'gi'), '<span class=keywords-highlight>$1</span>')
|
||||
console.error(ret)
|
||||
return ret
|
||||
}
|
||||
// 属性排序
|
||||
tool.sortProperties = function (obj) {
|
||||
const sortedKeys = Object.keys(obj).sort()
|
||||
|
@ -6,16 +6,13 @@
|
||||
file: 'sys_job',
|
||||
name: 'getRecordBarChart',
|
||||
label: '今日',
|
||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
|
||||
},
|
||||
{
|
||||
file: 'sys_job',
|
||||
name: 'getRecordBarChart',
|
||||
label: '昨日',
|
||||
value: [
|
||||
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
|
||||
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
|
||||
],
|
||||
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
|
||||
},
|
||||
]"
|
||||
height="20rem"></chart-bar>
|
||||
|
@ -6,16 +6,13 @@
|
||||
file: 'sys_log',
|
||||
name: 'getBarChart',
|
||||
label: '今日',
|
||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
|
||||
},
|
||||
{
|
||||
file: 'sys_log',
|
||||
name: 'getBarChart',
|
||||
label: '昨日',
|
||||
value: [
|
||||
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
|
||||
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
|
||||
],
|
||||
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
|
||||
},
|
||||
]"
|
||||
height="20rem"></chart-bar>
|
||||
|
@ -113,25 +113,23 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
})
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
filters: [
|
||||
{
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ export default {
|
||||
form: {
|
||||
enabled: true,
|
||||
},
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
|
@ -124,25 +124,23 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
})
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
filters: [
|
||||
{
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ export default {
|
||||
},
|
||||
//表单数据
|
||||
form: { enabled: true, sort: 100 },
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
|
@ -64,11 +64,7 @@ export default {
|
||||
saveDialog,
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
data: [],
|
||||
@ -81,6 +77,7 @@ export default {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -89,7 +86,7 @@ export default {
|
||||
// 获取字典目录
|
||||
async getData() {
|
||||
this.loading = true
|
||||
const res = await this.$API.sys_dic.queryCatalog.post()
|
||||
const res = await this.$API.sys_dic.queryCatalog.post({ prop: 'name', order: 'ascending' })
|
||||
this.loading = false
|
||||
this.data = res.data
|
||||
|
||||
|
@ -87,11 +87,7 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
@ -101,6 +97,7 @@ export default {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ export default {
|
||||
return {
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
|
@ -24,7 +24,7 @@ export default {
|
||||
return {
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
|
@ -181,6 +181,12 @@
|
||||
icon: 'el-icon-video-play',
|
||||
click: execute,
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-document-copy',
|
||||
confirm: true,
|
||||
title: '复制作业',
|
||||
click: copyJob,
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-delete',
|
||||
confirm: true,
|
||||
@ -191,7 +197,7 @@
|
||||
)
|
||||
"
|
||||
:vue="this"
|
||||
width="200" />
|
||||
width="220" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
@ -224,25 +230,23 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords || this.$route.query.keywords) {
|
||||
this.query.keywords = this.keywords || this.$route.query.keywords
|
||||
}
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
})
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
filters: [
|
||||
{
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords || this.$route.query.keywords,
|
||||
},
|
||||
selection: [],
|
||||
timer: null,
|
||||
@ -250,6 +254,19 @@ export default {
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async copyJob(row) {
|
||||
let loading = this.$loading()
|
||||
try {
|
||||
const res = await this.$API.sys_job.create.post(Object.assign({}, row, { id: 0, jobName: row.jobName + '-copy' }))
|
||||
if (res.data) {
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} else {
|
||||
this.$message.error(this.$t('操作失败'))
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
} catch {}
|
||||
loading?.close()
|
||||
},
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
|
@ -58,6 +58,22 @@
|
||||
<el-form-item :label="$t('请求的网络地址')" prop="requestUrl">
|
||||
<el-input v-model="form.requestUrl" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('随机延时')">
|
||||
<div class="flex gap05">
|
||||
<el-input
|
||||
v-model="form.randomDelayBegin"
|
||||
:placeholder="$t('起始值(毫秒)')"
|
||||
class="w15"
|
||||
clearable
|
||||
oninput="value=value.replace(/[^0-9]/g,'')" />
|
||||
<el-input
|
||||
v-model="form.randomDelayEnd"
|
||||
:placeholder="$t('结束值(毫秒)')"
|
||||
class="w15"
|
||||
clearable
|
||||
oninput="value=value.replace(/[^0-9]/g,'')" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="mode === 'view'" :label="$t('作业状态')" prop="status">
|
||||
<el-input v-model="form.status" clearable />
|
||||
</el-form-item>
|
||||
@ -127,7 +143,7 @@ export default {
|
||||
requestHeader: `{ "Content-Type": "application/json" }`,
|
||||
requestBody: '{}',
|
||||
},
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
|
@ -54,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
"
|
||||
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime', 'jobId']"
|
||||
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime', 'jobId', 'responseBody']"
|
||||
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
||||
:export-api="$API.sys_job.exportRecord"
|
||||
:params="query"
|
||||
@ -153,9 +153,6 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
if (this.statusCodes) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
logic: 'or',
|
||||
@ -184,6 +181,7 @@ export default {
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -51,7 +51,7 @@ export default {
|
||||
return {
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
loading: true,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {},
|
||||
|
@ -47,7 +47,6 @@
|
||||
:params="query"
|
||||
:query-api="$API.sys_log.pagedQuery"
|
||||
:vue="this"
|
||||
@row-click="rowClick"
|
||||
ref="table"
|
||||
remote-filter
|
||||
remote-sort
|
||||
@ -60,14 +59,23 @@
|
||||
{{ row.httpStatusCode === 200 ? '成功' : '失败' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('登录名')" prop="loginName" width="150" />
|
||||
<el-table-column :label="$t('登录名')" prop="detail.loginName" width="150" />
|
||||
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
||||
<template #default="{ row }">
|
||||
<na-ip :ip="row.createdClientIp"></na-ip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
|
||||
<el-table-column :label="$t('用户代理')" prop="createdUserAgent" show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('操作系统')" align="center" prop="detail.os" width="150" />
|
||||
<el-table-column :label="$t('用户代理')" prop="detail.createdUserAgent" show-overflow-tooltip sortable="custom" />
|
||||
<na-col-operation
|
||||
:buttons="[
|
||||
{
|
||||
icon: 'el-icon-view',
|
||||
click: rowClick,
|
||||
},
|
||||
]"
|
||||
:vue="this"
|
||||
width="70" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
@ -84,13 +92,10 @@ export default {
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'apiId',
|
||||
field: 'apiPathCrc32',
|
||||
operator: 'eq',
|
||||
value: 'api/sys/user/login.by.pwd',
|
||||
value: '1290209789',
|
||||
})
|
||||
},
|
||||
data() {
|
||||
@ -110,6 +115,7 @@ export default {
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
keywords: this.keywords,
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
@ -124,11 +130,11 @@ export default {
|
||||
},
|
||||
//搜索
|
||||
onSearch(form) {
|
||||
if (this.query.dynamicFilter.filters.findIndex((x) => x.field === 'apiId') < 0) {
|
||||
if (this.query.dynamicFilter.filters.findIndex((x) => x.field === 'apiPathCrc32') < 0) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'apiId',
|
||||
field: 'apiPathCrc32',
|
||||
operator: 'eq',
|
||||
value: 'api/sys/user/login.by.pwd',
|
||||
value: '1290209789',
|
||||
})
|
||||
}
|
||||
if (Array.isArray(form.dy.createdTime)) {
|
||||
@ -174,7 +180,7 @@ export default {
|
||||
type: 'root',
|
||||
})
|
||||
}
|
||||
this.$refs.search.form.dy.apiId = 'api/sys/user/login.by.pwd'
|
||||
this.$refs.search.form.dy['apiPathCrc32'] = '1290209789'
|
||||
this.$refs.search.form.dy.createdTime = [
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user