mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-23 14:42:51 +08:00
feat: ✨ 登录日志独立存储 (#161)
请求日志自动分表 [skip ci] Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
parent
e1bea2ec31
commit
faaf5aa0fc
@ -98,6 +98,8 @@
|
|||||||
电子邮箱
|
电子邮箱
|
||||||
男
|
男
|
||||||
登录
|
登录
|
||||||
|
登录名
|
||||||
|
登录日志导出
|
||||||
硕士
|
硕士
|
||||||
示例导出
|
示例导出
|
||||||
离异
|
离异
|
||||||
@ -123,6 +125,7 @@
|
|||||||
请求日志导出
|
请求日志导出
|
||||||
调试
|
调试
|
||||||
跟踪
|
跟踪
|
||||||
|
跟踪标识
|
||||||
跟踪编号
|
跟踪编号
|
||||||
身份证
|
身份证
|
||||||
运行
|
运行
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.29.0.95321">
|
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.30.0.95878">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -823,11 +823,14 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[InlineData(default)]
|
[InlineData(default)]
|
||||||
[Theory]
|
[Theory]
|
||||||
public async Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
|
public Task<IEnumerable<GetEntryRsp>> GetAllEntriesAsync(GetAllEntriesReq req)
|
||||||
{
|
{
|
||||||
var rsp = await PostAsync("/api/sys/cache/get.all.entries"
|
var rsp = PostAsync("/api/sys/cache/get.all.entries", JsonContent.Create(new GetAllEntriesReq()))
|
||||||
, JsonContent.Create(new PagedQueryReq<GetAllEntriesReq>()))
|
.ConfigureAwait(true)
|
||||||
.ConfigureAwait(true);
|
.GetAwaiter()
|
||||||
|
#pragma warning disable xUnit1031
|
||||||
|
.GetResult();
|
||||||
|
#pragma warning restore xUnit1031
|
||||||
Assert.Equal(HttpStatusCode.OK, rsp.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, rsp.StatusCode);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
@ -1029,6 +1032,12 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[Fact]
|
[Fact]
|
||||||
public IDictionary<string, Dictionary<string, string[]>> GetEnums()
|
public IDictionary<string, Dictionary<string, string[]>> GetEnums()
|
||||||
|
@ -12,19 +12,39 @@ public abstract class RedLockerService<TEntity, TPrimary, TLogger>(
|
|||||||
where TEntity : EntityBase<TPrimary> //
|
where TEntity : EntityBase<TPrimary> //
|
||||||
where TPrimary : IEquatable<TPrimary>
|
where TPrimary : IEquatable<TPrimary>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取锁
|
||||||
|
/// </summary>
|
||||||
|
protected Task<IRedLock> GetLockerAsync(string lockName)
|
||||||
|
{
|
||||||
|
return GetLockerAsync(lockName, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
|
||||||
|
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY_INTERVAL));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取锁
|
/// 获取锁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception>
|
/// <exception cref="NetAdminGetLockerException">NetAdminGetLockerException</exception>
|
||||||
protected async Task<IRedLock> GetLockerAsync(string lockName)
|
protected async Task<IRedLock> GetLockerAsync(string lockName, TimeSpan waitTime, TimeSpan retryInterval)
|
||||||
{
|
{
|
||||||
// 加锁
|
// 加锁
|
||||||
var redLock = await redLocker.RedLockFactory.CreateLockAsync( //
|
var lockTask = waitTime == default || retryInterval == default
|
||||||
lockName, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
|
? redLocker.RedLockFactory.CreateLockAsync(lockName, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY))
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
|
: redLocker.RedLockFactory.CreateLockAsync( //
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY))
|
lockName, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY), waitTime, retryInterval);
|
||||||
.ConfigureAwait(false);
|
var redLock = await lockTask.ConfigureAwait(false);
|
||||||
|
|
||||||
return redLock.IsAcquired ? redLock : throw new NetAdminGetLockerException();
|
return redLock.IsAcquired ? redLock : throw new NetAdminGetLockerException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取锁
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 不重试,失败直接抛出异常
|
||||||
|
/// </remarks>
|
||||||
|
protected Task<IRedLock> GetLockerOnceAsync(string lockName)
|
||||||
|
{
|
||||||
|
return GetLockerAsync(lockName, default, default);
|
||||||
|
}
|
||||||
}
|
}
|
@ -49,4 +49,14 @@ public sealed record ContextUserToken : DataAbstraction
|
|||||||
Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
|
Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从 Json Web Token 创建上下文用户
|
||||||
|
/// </summary>
|
||||||
|
public static ContextUserToken Create(string jwt)
|
||||||
|
{
|
||||||
|
var claim = JWTEncryption.ReadJwtToken(jwt.TrimPrefix($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} "))
|
||||||
|
?.Claims.FirstOrDefault(x => x.Type == nameof(ContextUserToken));
|
||||||
|
return claim?.Value.ToObject<ContextUserToken>();
|
||||||
|
}
|
||||||
}
|
}
|
@ -61,7 +61,7 @@ public record Sys_Api : ImmutableEntity<string>, IFieldSummary
|
|||||||
[Column]
|
[Column]
|
||||||
[CsvIgnore]
|
[CsvIgnore]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public int PathCrc32 { get; init; }
|
public virtual int PathCrc32 { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色集合
|
/// 角色集合
|
||||||
|
150
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs
Normal file
150
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
namespace NetAdmin.Domain.DbMaps.Sys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录日志表
|
||||||
|
/// </summary>
|
||||||
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
|
||||||
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||||
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
||||||
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_LoginLog))]
|
||||||
|
public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
||||||
|
, IFieldCreatedClientUserAgent
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual int? CreatedClientIp { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
|
||||||
|
[CsvIgnore]
|
||||||
|
[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
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string CreatedUserAgent { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行耗时(毫秒)
|
||||||
|
/// </summary>
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual int Duration { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 程序响应码
|
||||||
|
/// </summary>
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual ErrorCodes ErrorCode { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTTP状态码
|
||||||
|
/// </summary>
|
||||||
|
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_SMALL_INT)]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual int HttpStatusCode { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录用户名
|
||||||
|
/// </summary>
|
||||||
|
[Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string LoginUserName { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拥有者
|
||||||
|
/// </summary>
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
[Navigate(nameof(OwnerId))]
|
||||||
|
public Sys_User Owner { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual long? OwnerDeptId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual long? OwnerId { 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
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string RequestBody { 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
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string RequestHeaders { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求地址
|
||||||
|
/// </summary>
|
||||||
|
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||||
|
[CsvIgnore]
|
||||||
|
[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
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string ResponseBody { 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
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual string ResponseHeaders { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务器IP
|
||||||
|
/// </summary>
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual int? ServerIp { get; init; }
|
||||||
|
}
|
@ -9,7 +9,9 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", 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(OwnerId), nameof(OwnerId), false)]
|
||||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLog))]
|
[Table( //
|
||||||
|
Name = $"{Chars.FLG_DB_TABLE_NAME_PREFIX}{nameof(Sys_RequestLog)}_{{yyyyMMdd}}"
|
||||||
|
, AsTable = $"{nameof(CreatedTime)}=2024-1-1(1 day)")]
|
||||||
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -91,4 +93,12 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFi
|
|||||||
[CsvIgnore]
|
[CsvIgnore]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual long? OwnerId { get; init; }
|
public virtual long? OwnerId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求跟踪标识
|
||||||
|
/// </summary>
|
||||||
|
[Column]
|
||||||
|
[CsvIgnore]
|
||||||
|
[JsonIgnore]
|
||||||
|
public virtual Guid TraceId { get; init; }
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
|||||||
/// 请求日志明细表
|
/// 请求日志明细表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLogDetail))]
|
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLogDetail))]
|
||||||
|
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
|
||||||
public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCreatedClientUserAgent
|
public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCreatedClientUserAgent
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -121,12 +122,4 @@ public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCrea
|
|||||||
[CsvIgnore]
|
[CsvIgnore]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual int? ServerIp { get; init; }
|
public virtual int? ServerIp { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 请求跟踪标识
|
|
||||||
/// </summary>
|
|
||||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
|
||||||
[CsvIgnore]
|
|
||||||
[JsonIgnore]
|
|
||||||
public virtual string TraceId { get; init; }
|
|
||||||
}
|
}
|
@ -50,10 +50,14 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d?.Operator != DynamicFilterOperator.DateRange) {
|
if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) }
|
||||||
return;
|
.Contains(d?.Field, StringComparer.OrdinalIgnoreCase)) {
|
||||||
|
var val = d!.Value?.ToString();
|
||||||
|
if (val?.IsIpV4() == true) {
|
||||||
|
d.Value = val.IpV4ToInt32();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (d?.Operator == DynamicFilterOperator.DateRange) {
|
||||||
var values = ((JsonElement)d.Value).Deserialize<string[]>();
|
var values = ((JsonElement)d.Value).Deserialize<string[]>();
|
||||||
if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
|
if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
|
||||||
var result = values[0]
|
var result = values[0]
|
||||||
@ -75,4 +79,5 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
|||||||
|
|
||||||
d.Value = values;
|
d.Value = values;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -10,26 +10,26 @@ public record ExportApiRsp : QueryApiRsp
|
|||||||
public override IEnumerable<QueryApiRsp> Children { get; init; }
|
public override IEnumerable<QueryApiRsp> Children { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.接口路径))]
|
[CsvName(nameof(Ln.接口路径))]
|
||||||
public override string Id { get; init; }
|
public override string Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.请求方式))]
|
[CsvName(nameof(Ln.请求方式))]
|
||||||
public override string Method { get; init; }
|
public override string Method { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.接口名称))]
|
[CsvName(nameof(Ln.接口名称))]
|
||||||
public override string Name { get; init; }
|
public override string Name { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.接口描述))]
|
[CsvName(nameof(Ln.接口描述))]
|
||||||
public override string Summary { get; init; }
|
public override string Summary { get; init; }
|
||||||
}
|
}
|
@ -27,6 +27,10 @@ public record QueryApiRsp : Sys_Api
|
|||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override string ParentId { get; init; }
|
public override string ParentId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_Api.PathCrc32" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override int PathCrc32 { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IFieldSummary.Summary" />
|
/// <inheritdoc cref="IFieldSummary.Summary" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override string Summary { get; init; }
|
public override string Summary { get; init; }
|
||||||
|
@ -6,7 +6,7 @@ namespace NetAdmin.Domain.Dto.Sys.Cache;
|
|||||||
public sealed record GetAllEntriesReq : DataAbstraction
|
public sealed record GetAllEntriesReq : DataAbstraction
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据库索引号
|
/// 关键词
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int DbIndex { get; init; }
|
public string Keywords { get; init; }
|
||||||
}
|
}
|
@ -1,55 +0,0 @@
|
|||||||
namespace NetAdmin.Domain.Dto.Sys.Cache;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 响应:获取所有缓存项
|
|
||||||
/// </summary>
|
|
||||||
public sealed record GetAllEntriesRsp : DataAbstraction
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="GetAllEntriesRsp" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public GetAllEntriesRsp() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="GetAllEntriesRsp" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public GetAllEntriesRsp(long absExp, string key, long sldExp, string data)
|
|
||||||
{
|
|
||||||
AbsExp = absExp;
|
|
||||||
Key = key;
|
|
||||||
SldExp = sldExp;
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 绝对过期时间
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? AbsExpTime => AbsExp == -1 ? null : DateTime.FromBinary(AbsExp).ToLocalTime();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 滑动过期时间
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? SldExpTime => SldExp == -1 ? null : DateTime.FromBinary(SldExp).ToLocalTime();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 绝对过期时间
|
|
||||||
/// </summary>
|
|
||||||
[JsonInclude]
|
|
||||||
public long AbsExp { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 缓存值
|
|
||||||
/// </summary>
|
|
||||||
public string Data { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 缓存键
|
|
||||||
/// </summary>
|
|
||||||
public string Key { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 滑动过期时间
|
|
||||||
/// </summary>
|
|
||||||
[JsonInclude]
|
|
||||||
public long SldExp { get; init; }
|
|
||||||
}
|
|
12
src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetEntriesReq.cs
Normal file
12
src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetEntriesReq.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求:获取缓存项
|
||||||
|
/// </summary>
|
||||||
|
public sealed record GetEntriesReq : DataAbstraction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存键
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; init; }
|
||||||
|
}
|
34
src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetEntryRsp.cs
Normal file
34
src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetEntryRsp.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应:获取所有缓存项
|
||||||
|
/// </summary>
|
||||||
|
public sealed record GetEntryRsp : DataAbstraction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GetEntryRsp" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public GetEntryRsp() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存值
|
||||||
|
/// </summary>
|
||||||
|
public string Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 过期时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ExpireTime { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存键
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据类型
|
||||||
|
/// </summary>
|
||||||
|
public RedisType Type { get; init; }
|
||||||
|
}
|
@ -9,20 +9,20 @@ namespace NetAdmin.Domain.Dto.Sys.Config;
|
|||||||
public record ExportConfigRsp : QueryConfigRsp, IRegister
|
public record ExportConfigRsp : QueryConfigRsp, IRegister
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.是否启用))]
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
public override bool Enabled { get; init; }
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.人工审核))]
|
[CsvName(nameof(Ln.人工审核))]
|
||||||
public override bool UserRegisterConfirm { get; init; }
|
public override bool UserRegisterConfirm { get; init; }
|
||||||
|
|
||||||
@ -33,8 +33,8 @@ public record ExportConfigRsp : QueryConfigRsp, IRegister
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认部门
|
/// 默认部门
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.默认部门))]
|
[CsvName(nameof(Ln.默认部门))]
|
||||||
public string UserRegisterDeptName { get; init; }
|
public string UserRegisterDeptName { get; init; }
|
||||||
|
|
||||||
@ -45,8 +45,8 @@ public record ExportConfigRsp : QueryConfigRsp, IRegister
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认角色
|
/// 默认角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.默认角色))]
|
[CsvName(nameof(Ln.默认角色))]
|
||||||
public string UserRegisterRoleName { get; init; }
|
public string UserRegisterRoleName { get; init; }
|
||||||
|
|
||||||
|
@ -10,38 +10,38 @@ public record ExportDeptRsp : QueryDeptRsp
|
|||||||
public override IEnumerable<QueryDeptRsp> Children { get; init; }
|
public override IEnumerable<QueryDeptRsp> Children { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.是否启用))]
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
public override bool Enabled { get; init; }
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.部门名称))]
|
[CsvName(nameof(Ln.部门名称))]
|
||||||
public override string Name { get; init; }
|
public override string Name { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.排序))]
|
[CsvName(nameof(Ln.排序))]
|
||||||
public override long Sort { get; init; }
|
public override long Sort { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.备注))]
|
[CsvName(nameof(Ln.备注))]
|
||||||
public override string Summary { get; init; }
|
public override string Summary { get; init; }
|
||||||
}
|
}
|
@ -6,20 +6,20 @@ namespace NetAdmin.Domain.Dto.Sys.Dic.Content;
|
|||||||
public record ExportDicContentRsp : QueryDicContentRsp
|
public record ExportDicContentRsp : QueryDicContentRsp
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.项名))]
|
[CsvName(nameof(Ln.项名))]
|
||||||
public override string Key { get; init; }
|
public override string Key { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.项值))]
|
[CsvName(nameof(Ln.项值))]
|
||||||
public override string Value { get; init; }
|
public override string Value { get; init; }
|
||||||
}
|
}
|
@ -10,68 +10,68 @@ namespace NetAdmin.Domain.Dto.Sys.Job;
|
|||||||
public record ExportJobRsp : QueryJobRsp
|
public record ExportJobRsp : QueryJobRsp
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.上次执行状态))]
|
[CsvName(nameof(Ln.上次执行状态))]
|
||||||
public override string LastStatusCode => base.LastStatusCode;
|
public override string LastStatusCode => base.LastStatusCode;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(10)]
|
[CsvIndex(10)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(9)]
|
[CsvIndex(9)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.是否启用))]
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
public override bool Enabled { get; init; }
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.执行计划))]
|
[CsvName(nameof(Ln.执行计划))]
|
||||||
public override string ExecutionCron { get; init; }
|
public override string ExecutionCron { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.请求方式))]
|
[CsvName(nameof(Ln.请求方式))]
|
||||||
public override HttpMethods HttpMethod { get; init; }
|
public override HttpMethods HttpMethod { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.作业名称))]
|
[CsvName(nameof(Ln.作业名称))]
|
||||||
public override string JobName { get; init; }
|
public override string JobName { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(7)]
|
[CsvIndex(7)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.上次执行耗时))]
|
[CsvName(nameof(Ln.上次执行耗时))]
|
||||||
public override long? LastDuration { get; init; }
|
public override long? LastDuration { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.上次执行时间))]
|
[CsvName(nameof(Ln.上次执行时间))]
|
||||||
public override DateTime? LastExecTime { get; init; }
|
public override DateTime? LastExecTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(8)]
|
[CsvIndex(8)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.下次执行时间))]
|
[CsvName(nameof(Ln.下次执行时间))]
|
||||||
public override DateTime? NextExecTime { get; init; }
|
public override DateTime? NextExecTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.作业状态))]
|
[CsvName(nameof(Ln.作业状态))]
|
||||||
public override JobStatues Status { get; init; }
|
public override JobStatues Status { get; init; }
|
||||||
|
|
||||||
|
@ -8,26 +8,26 @@ namespace NetAdmin.Domain.Dto.Sys.JobRecord;
|
|||||||
public record ExportJobRecordRsp : QueryJobRecordRsp, IRegister
|
public record ExportJobRecordRsp : QueryJobRecordRsp, IRegister
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.响应状态码))]
|
[CsvName(nameof(Ln.响应状态码))]
|
||||||
public override string HttpStatusCode => base.HttpStatusCode;
|
public override string HttpStatusCode => base.HttpStatusCode;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.执行耗时))]
|
[CsvName(nameof(Ln.执行耗时))]
|
||||||
public override long Duration { get; init; }
|
public override long Duration { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
@ -38,14 +38,14 @@ public record ExportJobRecordRsp : QueryJobRecordRsp, IRegister
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作业名称
|
/// 作业名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.作业名称))]
|
[CsvName(nameof(Ln.作业名称))]
|
||||||
public string JobName { get; set; }
|
public string JobName { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.响应体))]
|
[CsvName(nameof(Ln.响应体))]
|
||||||
public override string ResponseBody { get; init; }
|
public override string ResponseBody { get; init; }
|
||||||
|
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
using NetAdmin.Domain.Contexts;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.User;
|
||||||
|
|
||||||
|
namespace NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求:创建登录日志
|
||||||
|
/// </summary>
|
||||||
|
public record CreateLoginLogReq : Sys_LoginLog, IRegister
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Register(TypeAdapterConfig config)
|
||||||
|
{
|
||||||
|
_ = config.ForType<CreateRequestLogReq, CreateLoginLogReq>().MapWith(x => Convert(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CreateLoginLogReq Convert(CreateRequestLogReq s)
|
||||||
|
{
|
||||||
|
var body = s.Detail.ResponseBody.ToObject<RestfulInfo<LoginRsp>>();
|
||||||
|
ContextUserToken userToken = null;
|
||||||
|
if (body.Data?.AccessToken != null) {
|
||||||
|
try {
|
||||||
|
userToken = ContextUserToken.Create(body.Data.AccessToken);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CreateLoginLogReq {
|
||||||
|
Id = s.Id
|
||||||
|
, CreatedClientIp = s.CreatedClientIp
|
||||||
|
, CreatedTime = s.CreatedTime
|
||||||
|
, Duration = s.Duration
|
||||||
|
, HttpStatusCode = s.HttpStatusCode
|
||||||
|
, ErrorCode = s.Detail.ErrorCode
|
||||||
|
, RequestBody = s.Detail.RequestBody
|
||||||
|
, RequestHeaders = s.Detail.RequestHeaders
|
||||||
|
, RequestUrl = s.Detail.RequestUrl
|
||||||
|
, ResponseBody = s.Detail.ResponseBody
|
||||||
|
, ResponseHeaders = s.Detail.ResponseHeaders
|
||||||
|
, ServerIp = s.Detail.ServerIp
|
||||||
|
, CreatedUserAgent = s.Detail.CreatedUserAgent
|
||||||
|
, OwnerId = userToken?.Id
|
||||||
|
, OwnerDeptId = userToken?.DeptId
|
||||||
|
, LoginUserName = s.Detail.RequestBody?.ToObject<LoginByPwdReq>()?.Account
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
using NetAdmin.Domain.Dto.Sys.User;
|
||||||
|
|
||||||
|
namespace NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应:导出登录日志
|
||||||
|
/// </summary>
|
||||||
|
public sealed record ExportLoginLogRsp : QueryLoginLogRsp
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.客户端IP))]
|
||||||
|
public override string CreatedClientIp => base.CreatedClientIp;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.操作系统))]
|
||||||
|
public override string Os => base.Os;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvIndex(6)]
|
||||||
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.用户代理))]
|
||||||
|
public override string CreatedUserAgent { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.响应状态码))]
|
||||||
|
public override int HttpStatusCode { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
|
public override long Id { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIgnore(false)]
|
||||||
|
[CsvIndex(2)]
|
||||||
|
[CsvName(nameof(Ln.登录名))]
|
||||||
|
public override string LoginUserName { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[CsvIgnore]
|
||||||
|
public override QueryUserRsp Owner { get; init; }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求:查询登录日志
|
||||||
|
/// </summary>
|
||||||
|
public sealed record QueryLoginLogReq : Sys_LoginLog
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override long Id { get; init; }
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
using NetAdmin.Domain.Dto.Sys.User;
|
||||||
|
|
||||||
|
namespace NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应:查询登录日志
|
||||||
|
/// </summary>
|
||||||
|
public record QueryLoginLogRsp : Sys_LoginLog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建者客户端IP
|
||||||
|
/// </summary>
|
||||||
|
[JsonInclude]
|
||||||
|
public new virtual string CreatedClientIp => base.CreatedClientIp?.ToIpV4();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作系统
|
||||||
|
/// </summary>
|
||||||
|
[JsonInclude]
|
||||||
|
public virtual string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFieldCreatedClientUserAgent.CreatedUserAgent" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string CreatedUserAgent { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.Duration" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override int Duration { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.ErrorCode" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override ErrorCodes ErrorCode { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.HttpStatusCode" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override int HttpStatusCode { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override long Id { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.LoginUserName" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string LoginUserName { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.Owner" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public new virtual QueryUserRsp Owner { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.RequestBody" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string RequestBody { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.RequestHeaders" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string RequestHeaders { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.RequestUrl" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string RequestUrl { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.ResponseBody" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string ResponseBody { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.ResponseHeaders" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override string ResponseHeaders { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_LoginLog.ServerIp" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public override int? ServerIp { get; init; }
|
||||||
|
}
|
@ -14,13 +14,13 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
|||||||
/// 接口路径
|
/// 接口路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
[CsvName(nameof(Ln.接口路径))]
|
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
|
[CsvName(nameof(Ln.接口路径))]
|
||||||
public string ApiId => Api.Id;
|
public string ApiId => Api.Id;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.客户端IP))]
|
[CsvName(nameof(Ln.客户端IP))]
|
||||||
public override string CreatedClientIp => base.CreatedClientIp;
|
public override string CreatedClientIp => base.CreatedClientIp;
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
|||||||
/// 用户名
|
/// 用户名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
[CsvName(nameof(Ln.用户名))]
|
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
|
[CsvName(nameof(Ln.用户名))]
|
||||||
public string UserName => Owner?.UserName;
|
public string UserName => Owner?.UserName;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -37,7 +37,9 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
|||||||
public override QueryApiRsp Api { get; init; }
|
public override QueryApiRsp Api { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore]
|
[CsvIgnore(false)]
|
||||||
|
[CsvIndex(8)]
|
||||||
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -45,38 +47,36 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
|||||||
public override QueryRequestLogDetailRsp Detail { get; init; }
|
public override QueryRequestLogDetailRsp Detail { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.执行耗时))]
|
[CsvName(nameof(Ln.执行耗时))]
|
||||||
public override int Duration { get; init; }
|
public override int Duration { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.请求方式))]
|
[CsvName(nameof(Ln.请求方式))]
|
||||||
public override HttpMethods HttpMethod { get; init; }
|
public override HttpMethods HttpMethod { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.响应状态码))]
|
[CsvName(nameof(Ln.响应状态码))]
|
||||||
public override int HttpStatusCode { get; init; }
|
public override int HttpStatusCode { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore]
|
[CsvIgnore]
|
||||||
public override QueryUserLiteRsp Owner { get; init; }
|
public override QueryUserRsp Owner { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore]
|
[CsvIndex(7)]
|
||||||
public override long? OwnerDeptId { get; init; }
|
[CsvIgnore(false)]
|
||||||
|
[CsvName(nameof(Ln.跟踪标识))]
|
||||||
/// <inheritdoc />
|
public override Guid TraceId { get; init; }
|
||||||
[CsvIgnore]
|
|
||||||
public override long? OwnerId { get; init; }
|
|
||||||
}
|
}
|
@ -3,4 +3,9 @@ namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 请求:查询请求日志
|
/// 请求:查询请求日志
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record QueryRequestLogReq : Sys_RequestLog;
|
public sealed record QueryRequestLogReq : Sys_RequestLog
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
}
|
@ -46,9 +46,13 @@ public record QueryRequestLogRsp : Sys_RequestLog
|
|||||||
|
|
||||||
/// <inheritdoc cref="Sys_RequestLog.Owner" />
|
/// <inheritdoc cref="Sys_RequestLog.Owner" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public new virtual QueryUserLiteRsp Owner { get; init; }
|
public new virtual QueryUserRsp Owner { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IFieldOwner.OwnerId" />
|
/// <inheritdoc cref="IFieldOwner.OwnerId" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override long? OwnerId { get; init; }
|
public override long? OwnerId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Sys_RequestLog.TraceId" />
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public override Guid TraceId { get; init; }
|
||||||
}
|
}
|
@ -66,8 +66,4 @@ public sealed record QueryRequestLogDetailRsp : Sys_RequestLogDetail
|
|||||||
/// <inheritdoc cref="Sys_RequestLogDetail.ServerIp" />
|
/// <inheritdoc cref="Sys_RequestLogDetail.ServerIp" />
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public override int? ServerIp { get; init; }
|
public override int? ServerIp { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_RequestLogDetail.TraceId" />
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
||||||
public override string TraceId { get; init; }
|
|
||||||
}
|
}
|
@ -8,50 +8,50 @@ namespace NetAdmin.Domain.Dto.Sys.Role;
|
|||||||
public sealed record ExportRoleRsp : QueryRoleRsp
|
public sealed record ExportRoleRsp : QueryRoleRsp
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(7)]
|
[CsvIndex(7)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.数据范围))]
|
[CsvName(nameof(Ln.数据范围))]
|
||||||
public override DataScopes DataScope { get; init; }
|
public override DataScopes DataScope { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.显示仪表板))]
|
[CsvName(nameof(Ln.显示仪表板))]
|
||||||
public override bool DisplayDashboard { get; init; }
|
public override bool DisplayDashboard { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.是否启用))]
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
public override bool Enabled { get; init; }
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.无限权限))]
|
[CsvName(nameof(Ln.无限权限))]
|
||||||
public override bool IgnorePermissionControl { get; init; }
|
public override bool IgnorePermissionControl { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.角色名称))]
|
[CsvName(nameof(Ln.角色名称))]
|
||||||
public override string Name { get; init; }
|
public override string Name { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.排序))]
|
[CsvName(nameof(Ln.排序))]
|
||||||
public override long Sort { get; init; }
|
public override long Sort { get; init; }
|
||||||
}
|
}
|
@ -11,14 +11,14 @@ namespace NetAdmin.Domain.Dto.Sys.SiteMsg;
|
|||||||
public record ExportSiteMsgRsp : QuerySiteMsgRsp
|
public record ExportSiteMsgRsp : QuerySiteMsgRsp
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(5)]
|
[CsvIndex(5)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.用户名))]
|
[CsvName(nameof(Ln.用户名))]
|
||||||
public override string CreatedUserName { get; init; }
|
public override string CreatedUserName { get; init; }
|
||||||
|
|
||||||
@ -27,14 +27,14 @@ public record ExportSiteMsgRsp : QuerySiteMsgRsp
|
|||||||
public override IEnumerable<QueryDeptRsp> Depts { get; init; }
|
public override IEnumerable<QueryDeptRsp> Depts { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.消息类型))]
|
[CsvName(nameof(Ln.消息类型))]
|
||||||
public override SiteMsgTypes MsgType { get; init; }
|
public override SiteMsgTypes MsgType { get; init; }
|
||||||
|
|
||||||
@ -43,14 +43,14 @@ public record ExportSiteMsgRsp : QuerySiteMsgRsp
|
|||||||
public override IEnumerable<QueryRoleRsp> Roles { get; init; }
|
public override IEnumerable<QueryRoleRsp> Roles { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(4)]
|
[CsvIndex(4)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.消息摘要))]
|
[CsvName(nameof(Ln.消息摘要))]
|
||||||
public override string Summary { get; init; }
|
public override string Summary { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.消息主题))]
|
[CsvName(nameof(Ln.消息主题))]
|
||||||
public override string Title { get; init; }
|
public override string Title { get; init; }
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ namespace NetAdmin.Domain.Dto.Sys.User;
|
|||||||
public record ExportUserRsp : QueryUserRsp
|
public record ExportUserRsp : QueryUserRsp
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(7)]
|
[CsvIndex(7)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.创建时间))]
|
[CsvName(nameof(Ln.创建时间))]
|
||||||
public override DateTime CreatedTime { get; init; }
|
public override DateTime CreatedTime { get; init; }
|
||||||
|
|
||||||
@ -26,26 +26,26 @@ public record ExportUserRsp : QueryUserRsp
|
|||||||
public string DeptName { get; init; }
|
public string DeptName { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(3)]
|
[CsvIndex(3)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.邮箱号))]
|
[CsvName(nameof(Ln.邮箱号))]
|
||||||
public override string Email { get; init; }
|
public override string Email { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(6)]
|
[CsvIndex(6)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.是否启用))]
|
[CsvName(nameof(Ln.是否启用))]
|
||||||
public override bool Enabled { get; init; }
|
public override bool Enabled { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(0)]
|
[CsvIndex(0)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.唯一编码))]
|
[CsvName(nameof(Ln.唯一编码))]
|
||||||
public override long Id { get; init; }
|
public override long Id { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(2)]
|
[CsvIndex(2)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.手机号))]
|
[CsvName(nameof(Ln.手机号))]
|
||||||
public override string Mobile { get; init; }
|
public override string Mobile { get; init; }
|
||||||
|
|
||||||
@ -61,8 +61,8 @@ public record ExportUserRsp : QueryUserRsp
|
|||||||
public override IEnumerable<QueryRoleRsp> Roles { get; init; }
|
public override IEnumerable<QueryRoleRsp> Roles { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[CsvIgnore(false)]
|
|
||||||
[CsvIndex(1)]
|
[CsvIndex(1)]
|
||||||
|
[CsvIgnore(false)]
|
||||||
[CsvName(nameof(Ln.用户名))]
|
[CsvName(nameof(Ln.用户名))]
|
||||||
public override string UserName { get; init; }
|
public override string UserName { get; init; }
|
||||||
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
@ -72,6 +72,6 @@ public abstract class WorkBase<TLogger>
|
|||||||
{
|
{
|
||||||
return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
|
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_WAIT)
|
||||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
|
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY_INTERVAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -44,7 +44,6 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
|||||||
, ResponseContentType = context.Response.ContentType
|
, ResponseContentType = context.Response.ContentType
|
||||||
, ResponseHeaders = context.Response.Headers.Json()
|
, ResponseHeaders = context.Response.Headers.Json()
|
||||||
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
|
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
|
||||||
, TraceId = context.TraceIdentifier
|
|
||||||
}
|
}
|
||||||
, Duration = (int)duration
|
, Duration = (int)duration
|
||||||
, HttpMethod = Enum.Parse<HttpMethods>(context.Request.Method, true)
|
, HttpMethod = Enum.Parse<HttpMethods>(context.Request.Method, true)
|
||||||
@ -54,6 +53,7 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
|||||||
, OwnerId = associatedUser?.UserId
|
, OwnerId = associatedUser?.UserId
|
||||||
, OwnerDeptId = associatedUser?.DeptId
|
, OwnerDeptId = associatedUser?.DeptId
|
||||||
, Id = id
|
, Id = id
|
||||||
|
, TraceId = context.GetTraceId()
|
||||||
};
|
};
|
||||||
|
|
||||||
// 打印日志
|
// 打印日志
|
||||||
@ -74,13 +74,10 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
|||||||
|
|
||||||
ContextUserToken userToken = null;
|
ContextUserToken userToken = null;
|
||||||
try {
|
try {
|
||||||
var jsonWebToken
|
userToken = ContextUserToken.Create(token);
|
||||||
= 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>();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
logger.Warn($"{Ln.读取用户令牌出错}: {ex}");
|
logger.Warn($"{Ln.读取用户令牌出错} {ex}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return userToken == null ? null : (userToken.Id, userToken.DeptId, userToken.UserName);
|
return userToken == null ? null : (userToken.Id, userToken.DeptId, userToken.UserName);
|
||||||
|
@ -28,7 +28,7 @@ public static class Numbers
|
|||||||
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
|
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
|
||||||
public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码
|
public const int SECS_CACHE_DIC_CATALOG_CODE = 300; // 秒:缓存时间-字典配置-目录代码
|
||||||
public const int SECS_RED_LOCK_EXPIRY = 30; // 秒:RedLock-锁过期时间,假如持有锁的进程挂掉,最多在此时间内锁将被释放(如持有锁的进程正常,此值不会生效)
|
public const int SECS_RED_LOCK_EXPIRY = 30; // 秒:RedLock-锁过期时间,假如持有锁的进程挂掉,最多在此时间内锁将被释放(如持有锁的进程正常,此值不会生效)
|
||||||
public const int SECS_RED_LOCK_RETRY = 1; // 秒:RedLock-锁等待时间内,多久尝试获取一次
|
public const int SECS_RED_LOCK_RETRY_INTERVAL = 1; // 秒:RedLock-锁等待时间内,多久尝试获取一次
|
||||||
public const int SECS_RED_LOCK_WAIT = 10; // 秒:RedLock-锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
|
public const int SECS_RED_LOCK_WAIT = 10; // 秒:RedLock-锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
|
||||||
public const int SECS_TIMEOUT_HTTP_CLIENT = 15; // 秒:超时时间-默认HTTP客户端
|
public const int SECS_TIMEOUT_HTTP_CLIENT = 15; // 秒:超时时间-默认HTTP客户端
|
||||||
public const int SECS_TIMEOUT_JOB = 600; // 秒:超时时间-作业
|
public const int SECS_TIMEOUT_JOB = 600; // 秒:超时时间-作业
|
||||||
|
@ -22,4 +22,12 @@ public static class HttpContextExtensions
|
|||||||
? ip2
|
? ip2
|
||||||
: me.Connection.RemoteIpAddress;
|
: me.Connection.RemoteIpAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取跟踪标识
|
||||||
|
/// </summary>
|
||||||
|
public static Guid GetTraceId(this HttpContext me)
|
||||||
|
{
|
||||||
|
return me.TraceIdentifier.Md5(Encoding.UTF8).Guid();
|
||||||
|
}
|
||||||
}
|
}
|
@ -8,6 +8,8 @@ namespace NetAdmin.Infrastructure.Extensions;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
private static readonly Regex _regexIpV4 = new(Chars.RGXL_IP_V4);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算Crc32
|
/// 计算Crc32
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -27,6 +29,14 @@ public static class StringExtensions
|
|||||||
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否IPV4地址
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsIpV4(this string me)
|
||||||
|
{
|
||||||
|
return _regexIpV4.IsMatch(me);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// object -> json
|
/// object -> json
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -43,24 +53,6 @@ public static class StringExtensions
|
|||||||
return me.Object(toType, GlobalStatic.JsonSerializerOptions);
|
return me.Object(toType, GlobalStatic.JsonSerializerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 去掉尾部字符串“Async”
|
|
||||||
/// </summary>
|
|
||||||
#pragma warning disable RCS1047, ASA002, VSTHRD200
|
|
||||||
public static string TrimEndAsync(this string me)
|
|
||||||
#pragma warning restore VSTHRD200, ASA002, RCS1047
|
|
||||||
{
|
|
||||||
return TrimSuffix(me, "Async");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 去掉尾部字符串“Options”
|
|
||||||
/// </summary>
|
|
||||||
public static string TrimEndOptions(this string me)
|
|
||||||
{
|
|
||||||
return TrimSuffix(me, "Options");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 去掉前部字符串
|
/// 去掉前部字符串
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -69,6 +61,16 @@ public static class StringExtensions
|
|||||||
return Regex.Replace(me, $"^{clearStr}", string.Empty);
|
return Regex.Replace(me, $"^{clearStr}", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 去掉尾部字符串“Async”
|
||||||
|
/// </summary>
|
||||||
|
#pragma warning disable RCS1047, ASA002, VSTHRD200
|
||||||
|
public static string TrimPrefixAsync(this string me)
|
||||||
|
#pragma warning restore VSTHRD200, ASA002, RCS1047
|
||||||
|
{
|
||||||
|
return TrimPrefix(me, "Async");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 去掉尾部字符串
|
/// 去掉尾部字符串
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -76,4 +78,12 @@ public static class StringExtensions
|
|||||||
{
|
{
|
||||||
return Regex.Replace(me, $"{clearStr}$", string.Empty);
|
return Regex.Replace(me, $"{clearStr}$", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 去掉尾部字符串“Options”
|
||||||
|
/// </summary>
|
||||||
|
public static string TrimSuffixOptions(this string me)
|
||||||
|
{
|
||||||
|
return TrimPrefix(me, "Options");
|
||||||
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@
|
|||||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||||
<PackageReference Include="NSExt" Version="2.2.0"/>
|
<PackageReference Include="NSExt" Version="2.2.0"/>
|
||||||
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.3"/>
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="*.json">
|
<None Update="*.json">
|
||||||
|
@ -15,7 +15,8 @@ public sealed class FreeSqlBuilder(DatabaseOptions databaseOptions)
|
|||||||
{
|
{
|
||||||
var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr)
|
var freeSql = new FreeSql.FreeSqlBuilder().UseConnectionString(databaseOptions.DbType, databaseOptions.ConnStr)
|
||||||
.UseGenerateCommandParameterWithLambda(true)
|
.UseGenerateCommandParameterWithLambda(true)
|
||||||
.UseAutoSyncStructure(false)
|
.UseAutoSyncStructure(
|
||||||
|
initMethods.HasFlag(FreeSqlInitMethods.SyncStructure))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
|
_ = InitDbAsync(freeSql, initMethods); // 初始化数据库 ,异步
|
||||||
|
@ -18,7 +18,7 @@ public sealed class XmlCommentReader : ISingleton
|
|||||||
{
|
{
|
||||||
var xmlComments = specificationDocumentSettings.Value.XmlComments //
|
var xmlComments = specificationDocumentSettings.Value.XmlComments //
|
||||||
?? App.GetConfig<SpecificationDocumentSettingsOptions>(
|
?? App.GetConfig<SpecificationDocumentSettingsOptions>(
|
||||||
nameof(SpecificationDocumentSettingsOptions).TrimEndOptions())
|
nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
|
||||||
.XmlComments;
|
.XmlComments;
|
||||||
foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) {
|
foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) {
|
||||||
var xmlDoc = new XmlDocument();
|
var xmlDoc = new XmlDocument();
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using NetAdmin.Domain.Dto.Dependency;
|
|
||||||
using NetAdmin.Domain.Dto.Sys.Cache;
|
using NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
|
|
||||||
namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
||||||
@ -16,5 +15,10 @@ public interface ICacheModule
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取所有缓存项
|
/// 获取所有缓存项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req);
|
Task<IEnumerable<GetEntryRsp>> GetAllEntriesAsync(GetAllEntriesReq req);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取缓存项
|
||||||
|
/// </summary>
|
||||||
|
Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req);
|
||||||
}
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using NetAdmin.Application.Modules;
|
||||||
|
using NetAdmin.Domain.Dto.Dependency;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
|
||||||
|
namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录日志模块
|
||||||
|
/// </summary>
|
||||||
|
public interface ILoginLogModule : ICrudModule<CreateLoginLogReq, QueryLoginLogRsp // 创建类型
|
||||||
|
, QueryLoginLogReq, QueryLoginLogRsp // 查询类型
|
||||||
|
, DelReq // 删除类型
|
||||||
|
>;
|
@ -10,8 +10,9 @@ namespace NetAdmin.SysComponent.Application.Services.Sys;
|
|||||||
public sealed class ApiService(
|
public sealed class ApiService(
|
||||||
BasicRepository<Sys_Api, string> rpo //
|
BasicRepository<Sys_Api, string> rpo //
|
||||||
, XmlCommentReader xmlCommentReader //
|
, XmlCommentReader xmlCommentReader //
|
||||||
, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) //
|
, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider
|
||||||
: RepositoryService<Sys_Api, string, IApiService>(rpo), IApiService
|
, RedLocker redLocker) //
|
||||||
|
: RedLockerService<Sys_Api, string, IApiService>(rpo, redLocker), IApiService
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||||
@ -125,6 +126,7 @@ public sealed class ApiService(
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task SyncAsync()
|
public async Task SyncAsync()
|
||||||
{
|
{
|
||||||
|
await using var locker = await GetLockerOnceAsync(nameof(SyncAsync)).ConfigureAwait(false);
|
||||||
_ = await Rpo.DeleteAsync(_ => true).ConfigureAwait(false);
|
_ = await Rpo.DeleteAsync(_ => true).ConfigureAwait(false);
|
||||||
|
|
||||||
var list = ReflectionList(false);
|
var list = ReflectionList(false);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using NetAdmin.Application.Services;
|
using NetAdmin.Application.Services;
|
||||||
using NetAdmin.Domain.Dto.Dependency;
|
|
||||||
using NetAdmin.Domain.Dto.Sys.Cache;
|
using NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
@ -31,23 +31,58 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
|
public async Task<IEnumerable<GetEntryRsp>> GetAllEntriesAsync(GetAllEntriesReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
|
#pragma warning disable VSTHRD103
|
||||||
|
var server = connectionMultiplexer.GetServers()[0];
|
||||||
|
|
||||||
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
|
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
|
||||||
var redisResults = (RedisResult[])await database
|
var keys = server.Keys(_redisInstance.Database, $"*{req.Keywords}*", Numbers.MAX_LIMIT_BULK_REQ)
|
||||||
.ExecuteAsync("scan", (req.Page - 1) * req.PageSize, "count"
|
.Take(Numbers.MAX_LIMIT_BULK_REQ)
|
||||||
, req.PageSize)
|
.ToList();
|
||||||
|
#pragma warning restore VSTHRD103
|
||||||
|
|
||||||
|
var dic = new ConcurrentDictionary<string, (DateTime?, RedisType)>();
|
||||||
|
|
||||||
|
await Parallel
|
||||||
|
.ForEachAsync(
|
||||||
|
keys
|
||||||
|
, async (key, _) =>
|
||||||
|
dic.TryAdd(
|
||||||
|
key
|
||||||
|
, (DateTime.Now + await database.KeyTimeToLiveAsync(key).ConfigureAwait(false)
|
||||||
|
, await database.KeyTypeAsync(key).ConfigureAwait(false))))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
return dic.Select(x => new GetEntryRsp { Key = x.Key, ExpireTime = x.Value.Item1, Type = x.Value.Item2 });
|
||||||
|
}
|
||||||
|
|
||||||
var list = ((string[])redisResults![1])!.Where(x => database.KeyType(x) == RedisType.Hash)
|
/// <inheritdoc />
|
||||||
.Select(x => database.HashGetAll(x)
|
public async Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req)
|
||||||
.Append(new HashEntry("key", x))
|
{
|
||||||
.ToArray()
|
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
|
||||||
.ToStringDictionary())
|
|
||||||
.ToList()
|
|
||||||
.ConvertAll(x => x.Adapt<GetAllEntriesRsp>());
|
|
||||||
|
|
||||||
return new PagedQueryRsp<GetAllEntriesRsp>(req.Page, req.PageSize, 10000, list);
|
var ret = new GetEntryRsp {
|
||||||
|
Type = await database.KeyTypeAsync(req.Key).ConfigureAwait(false)
|
||||||
|
, Key = req.Key
|
||||||
|
, ExpireTime = DateTime.Now +
|
||||||
|
await database.KeyTimeToLiveAsync(req.Key).ConfigureAwait(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma warning disable IDE0072
|
||||||
|
ret.Data = ret.Type switch
|
||||||
|
#pragma warning restore IDE0072
|
||||||
|
{
|
||||||
|
RedisType.String => await database.StringGetAsync(req.Key).ConfigureAwait(false)
|
||||||
|
, RedisType.List => string.Join(", ", await database.ListRangeAsync(req.Key).ConfigureAwait(false))
|
||||||
|
, RedisType.Set => string.Join(", ", await database.SetMembersAsync(req.Key).ConfigureAwait(false))
|
||||||
|
, RedisType.SortedSet =>
|
||||||
|
string.Join(", ", await database.SortedSetRangeByRankAsync(req.Key).ConfigureAwait(false))
|
||||||
|
, RedisType.Hash => string.Join(
|
||||||
|
", ", await database.HashGetAllAsync(req.Key).ConfigureAwait(false))
|
||||||
|
, _ => "Unsupported key type"
|
||||||
|
};
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 ILoginLogService : IService, ILoginLogModule;
|
@ -0,0 +1,150 @@
|
|||||||
|
using NetAdmin.Application.Repositories;
|
||||||
|
using NetAdmin.Application.Services;
|
||||||
|
using NetAdmin.Domain.Dto.Dependency;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
|
|
||||||
|
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILoginLogService" />
|
||||||
|
public sealed class LoginLogService(BasicRepository<Sys_LoginLog, long> rpo) //
|
||||||
|
: RepositoryService<Sys_LoginLog, long, ILoginLogService>(rpo), ILoginLogService
|
||||||
|
{
|
||||||
|
/// <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<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return QueryInternal(req)
|
||||||
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
|
.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<QueryLoginLogRsp> CreateAsync(CreateLoginLogReq req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||||
|
return ret.Adapt<QueryLoginLogRsp>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> DeleteAsync(DelReq req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return Rpo.DeleteAsync(a => a.Id == req.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<bool> ExistAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return QueryInternal(req)
|
||||||
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
|
.AnyAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IActionResult> ExportAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
return ExportAsync<QueryLoginLogReq, ExportLoginLogRsp>(QueryInternal, req, Ln.登录日志导出);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
var ret = await QueryInternal(new QueryReq<QueryLoginLogReq> { Filter = req })
|
||||||
|
.ToOneAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
return ret.Adapt<QueryLoginLogRsp>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<PagedQueryRsp<QueryLoginLogRsp>> PagedQueryAsync(PagedQueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
req.ThrowIfInvalid();
|
||||||
|
var list = await QueryInternal(req)
|
||||||
|
.Include(a => a.Owner)
|
||||||
|
.Page(req.Page, req.PageSize)
|
||||||
|
#if DBTYPE_SQLSERVER
|
||||||
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
|
#endif
|
||||||
|
.Count(out var total)
|
||||||
|
.ToListAsync(a => new {
|
||||||
|
a.CreatedClientIp
|
||||||
|
, a.CreatedTime
|
||||||
|
, a.CreatedUserAgent
|
||||||
|
, a.Duration
|
||||||
|
, a.ErrorCode
|
||||||
|
, a.HttpStatusCode
|
||||||
|
, a.Id
|
||||||
|
, a.LoginUserName
|
||||||
|
, Owner = new { a.Owner.Id, a.Owner.UserName }
|
||||||
|
, a.RequestUrl
|
||||||
|
, a.ServerIp
|
||||||
|
})
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new PagedQueryRsp<QueryLoginLogRsp>(req.Page, req.PageSize, total, list.Adapt<List<QueryLoginLogRsp>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<IEnumerable<QueryLoginLogRsp>> QueryAsync(QueryReq<QueryLoginLogReq> 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<QueryLoginLogRsp>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISelect<Sys_LoginLog> QueryInternal(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||||
|
|
||||||
|
if (req.Keywords?.Length > 0) {
|
||||||
|
ret = req.Keywords.IsIpV4()
|
||||||
|
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
||||||
|
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) ||
|
||||||
|
a.LoginUserName == req.Keywords);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
@ -2,19 +2,16 @@ using NetAdmin.Application.Repositories;
|
|||||||
using NetAdmin.Application.Services;
|
using NetAdmin.Application.Services;
|
||||||
using NetAdmin.Domain.Dto.Dependency;
|
using NetAdmin.Domain.Dto.Dependency;
|
||||||
using NetAdmin.Domain.Dto.Sys;
|
using NetAdmin.Domain.Dto.Sys;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
using NetAdmin.Domain.Dto.Sys.RequestLog;
|
using NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
|
|
||||||
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestLogService" />
|
/// <inheritdoc cref="IRequestLogService" />
|
||||||
public sealed class RequestLogService(
|
public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo, LoginLogService loginLogService) //
|
||||||
BasicRepository<Sys_RequestLog, long> rpo
|
|
||||||
, RequestLogDetailService requestLogDetailService) //
|
|
||||||
: RepositoryService<Sys_RequestLog, long, IRequestLogService>(rpo), IRequestLogService
|
: RepositoryService<Sys_RequestLog, long, IRequestLogService>(rpo), IRequestLogService
|
||||||
{
|
{
|
||||||
private static readonly Regex _regex = new(Chars.RGXL_IP_V4);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||||
{
|
{
|
||||||
@ -45,7 +42,12 @@ public sealed class RequestLogService(
|
|||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||||
_ = await requestLogDetailService.CreateAsync(req.Detail).ConfigureAwait(false);
|
|
||||||
|
// 插入登录日志
|
||||||
|
if (req.ApiPathCrc32 == Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Crc32()) {
|
||||||
|
_ = await loginLogService.CreateAsync(req.Adapt<CreateLoginLogReq>()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
return ret.Adapt<QueryRequestLogRsp>();
|
return ret.Adapt<QueryRequestLogRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +90,16 @@ public sealed class RequestLogService(
|
|||||||
public async Task<QueryRequestLogRsp> GetAsync(QueryRequestLogReq req)
|
public async Task<QueryRequestLogRsp> GetAsync(QueryRequestLogReq req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var ret = await QueryInternal(new QueryReq<QueryRequestLogReq> { Filter = req })
|
var df = new DynamicFilterInfo {
|
||||||
|
Field = nameof(QueryRequestLogReq.CreatedTime)
|
||||||
|
, Operator = DynamicFilterOperators.DateRange
|
||||||
|
, Value = new[] {
|
||||||
|
req.CreatedTime.AddHours(-1).yyyy_MM_dd_HH_mm_ss()
|
||||||
|
, req.CreatedTime.AddHours(1).yyyy_MM_dd_HH_mm_ss()
|
||||||
|
}.Json()
|
||||||
|
.Object<JsonElement>()
|
||||||
|
};
|
||||||
|
var ret = await QueryInternal(new QueryReq<QueryRequestLogReq> { Filter = req, DynamicFilter = df })
|
||||||
.Include(a => a.Detail)
|
.Include(a => a.Detail)
|
||||||
.ToOneAsync()
|
.ToOneAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -155,42 +166,26 @@ public sealed class RequestLogService(
|
|||||||
public async Task<PagedQueryRsp<QueryRequestLogRsp>> PagedQueryAsync(PagedQueryReq<QueryRequestLogReq> req)
|
public async Task<PagedQueryRsp<QueryRequestLogRsp>> PagedQueryAsync(PagedQueryReq<QueryRequestLogReq> req)
|
||||||
{
|
{
|
||||||
req.ThrowIfInvalid();
|
req.ThrowIfInvalid();
|
||||||
var select = QueryInternal(req)
|
var select = QueryInternal(req with { Order = Orders.None }, false);
|
||||||
.Page(req.Page, req.PageSize)
|
var selectTemp = select.WithTempQuery(a => new { temp = a });
|
||||||
|
|
||||||
|
if (req.Order == Orders.Random) {
|
||||||
|
selectTemp = selectTemp.OrderByRandom();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectTemp = selectTemp.OrderBy( //
|
||||||
|
req.Prop?.Length > 0, $"{req.Prop} {(req.Order == Orders.Ascending ? "ASC" : "DESC")}");
|
||||||
|
if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) {
|
||||||
|
selectTemp = selectTemp.OrderByDescending(a => a.temp.CreatedTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = await selectTemp.Page(req.Page, req.PageSize)
|
||||||
#if DBTYPE_SQLSERVER
|
#if DBTYPE_SQLSERVER
|
||||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||||
#endif
|
#endif
|
||||||
.Count(out var total);
|
.Count(out var total)
|
||||||
|
.ToListAsync(a => a.temp)
|
||||||
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new PagedQueryRsp<QueryRequestLogRsp>(req.Page, req.PageSize, total
|
return new PagedQueryRsp<QueryRequestLogRsp>(req.Page, req.PageSize, total
|
||||||
@ -229,10 +224,9 @@ public sealed class RequestLogService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.Keywords?.Length > 0) {
|
if (req.Keywords?.Length > 0) {
|
||||||
ret = _regex.IsMatch(req.Keywords)
|
ret = req.Keywords.IsIpV4()
|
||||||
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
||||||
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) ||
|
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0));
|
||||||
a.Owner.UserName == req.Keywords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||||
|
@ -18,12 +18,13 @@ public sealed class ToolsService : ServiceBase<IToolsService>, IToolsService
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<IEnumerable<GetModulesRsp>> GetModulesAsync()
|
public Task<IEnumerable<GetModulesRsp>> GetModulesAsync()
|
||||||
{
|
{
|
||||||
return Task.FromResult<IEnumerable<GetModulesRsp>>( //
|
return Task.FromResult<IEnumerable<GetModulesRsp>>(AppDomain.CurrentDomain.GetAssemblies()
|
||||||
AppDomain.CurrentDomain.GetAssemblies()
|
|
||||||
.Where(x => !x.FullName?.Contains('#') ?? false)
|
|
||||||
.Select(x => {
|
.Select(x => {
|
||||||
var asm = x.GetName();
|
var asm = x.GetName();
|
||||||
return new GetModulesRsp { Name = asm.Name, Version = asm.Version?.ToString() };
|
return new GetModulesRsp {
|
||||||
|
Name = asm.Name
|
||||||
|
, Version = asm.Version?.ToString()
|
||||||
|
};
|
||||||
})
|
})
|
||||||
.OrderBy(x => x.Name));
|
.OrderBy(x => x.Name));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using NetAdmin.Cache;
|
using NetAdmin.Cache;
|
||||||
using NetAdmin.Domain.Dto.Dependency;
|
|
||||||
using NetAdmin.Domain.Dto.Sys.Cache;
|
using NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||||
@ -22,8 +21,14 @@ public sealed class CacheCache(IDistributedCache cache, ICacheService service) /
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
|
public Task<IEnumerable<GetEntryRsp>> GetAllEntriesAsync(GetAllEntriesReq req)
|
||||||
{
|
{
|
||||||
return Service.GetAllEntriesAsync(req);
|
return Service.GetAllEntriesAsync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req)
|
||||||
|
{
|
||||||
|
return Service.GetEntryAsync(req);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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 ILoginLogCache : ICache<IDistributedCache, ILoginLogService>, ILoginLogModule;
|
66
src/backend/NetAdmin.SysComponent.Cache/Sys/LoginLogCache.cs
Normal file
66
src/backend/NetAdmin.SysComponent.Cache/Sys/LoginLogCache.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using NetAdmin.Cache;
|
||||||
|
using NetAdmin.Domain.Dto.Dependency;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
|
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||||
|
|
||||||
|
namespace NetAdmin.SysComponent.Cache.Sys;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILoginLogCache" />
|
||||||
|
public sealed class LoginLogCache(IDistributedCache cache, ILoginLogService service)
|
||||||
|
: DistributedCache<ILoginLogService>(cache, service), IScoped, ILoginLogCache
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||||
|
{
|
||||||
|
return Service.BulkDeleteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<long> CountAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Service.CountAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<QueryLoginLogRsp> CreateAsync(CreateLoginLogReq req)
|
||||||
|
{
|
||||||
|
return Service.CreateAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> DeleteAsync(DelReq req)
|
||||||
|
{
|
||||||
|
return Service.DeleteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<bool> ExistAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Service.ExistAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IActionResult> ExportAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Service.ExportAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
|
||||||
|
{
|
||||||
|
return Service.GetAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<PagedQueryRsp<QueryLoginLogRsp>> PagedQueryAsync(PagedQueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Service.PagedQueryAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<IEnumerable<QueryLoginLogRsp>> QueryAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Service.QueryAsync(req);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
using NetAdmin.Domain.Dto.Dependency;
|
|
||||||
using NetAdmin.Domain.Dto.Sys.Cache;
|
using NetAdmin.Domain.Dto.Sys.Cache;
|
||||||
using NetAdmin.Host.Controllers;
|
using NetAdmin.Host.Controllers;
|
||||||
using NetAdmin.SysComponent.Application.Modules.Sys;
|
using NetAdmin.SysComponent.Application.Modules.Sys;
|
||||||
@ -24,8 +23,16 @@ public sealed class CacheController(ICacheCache cache) : ControllerBase<ICacheCa
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取所有缓存项
|
/// 获取所有缓存项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
|
public Task<IEnumerable<GetEntryRsp>> GetAllEntriesAsync(GetAllEntriesReq req)
|
||||||
{
|
{
|
||||||
return Cache.GetAllEntriesAsync(req);
|
return Cache.GetAllEntriesAsync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取缓存项
|
||||||
|
/// </summary>
|
||||||
|
public Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req)
|
||||||
|
{
|
||||||
|
return Cache.GetEntryAsync(req);
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
using NetAdmin.Domain.Dto.Dependency;
|
||||||
|
using NetAdmin.Domain.Dto.Sys.LoginLog;
|
||||||
|
using NetAdmin.Host.Attributes;
|
||||||
|
using NetAdmin.Host.Controllers;
|
||||||
|
using NetAdmin.SysComponent.Application.Modules.Sys;
|
||||||
|
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||||
|
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||||
|
|
||||||
|
namespace NetAdmin.SysComponent.Host.Controllers.Sys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录日志服务
|
||||||
|
/// </summary>
|
||||||
|
[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))]
|
||||||
|
public sealed class LoginLogController(ILoginLogCache cache) : ControllerBase<ILoginLogCache, ILoginLogService>(cache)
|
||||||
|
, ILoginLogModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 批量删除登录日志
|
||||||
|
/// </summary>
|
||||||
|
[Transaction]
|
||||||
|
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||||
|
{
|
||||||
|
return Cache.BulkDeleteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录日志计数
|
||||||
|
/// </summary>
|
||||||
|
public Task<long> CountAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Cache.CountAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建登录日志
|
||||||
|
/// </summary>
|
||||||
|
[Transaction]
|
||||||
|
public Task<QueryLoginLogRsp> CreateAsync(CreateLoginLogReq req)
|
||||||
|
{
|
||||||
|
return Cache.CreateAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除登录日志
|
||||||
|
/// </summary>
|
||||||
|
[Transaction]
|
||||||
|
public Task<int> DeleteAsync(DelReq req)
|
||||||
|
{
|
||||||
|
return Cache.DeleteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录日志是否存在
|
||||||
|
/// </summary>
|
||||||
|
public Task<bool> ExistAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Cache.ExistAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出登录日志
|
||||||
|
/// </summary>
|
||||||
|
public Task<IActionResult> ExportAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Cache.ExportAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取单个登录日志
|
||||||
|
/// </summary>
|
||||||
|
public Task<QueryLoginLogRsp> GetAsync(QueryLoginLogReq req)
|
||||||
|
{
|
||||||
|
return Cache.GetAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分页查询登录日志
|
||||||
|
/// </summary>
|
||||||
|
public Task<PagedQueryRsp<QueryLoginLogRsp>> PagedQueryAsync(PagedQueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Cache.PagedQueryAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询登录日志
|
||||||
|
/// </summary>
|
||||||
|
public Task<IEnumerable<QueryLoginLogRsp>> QueryAsync(QueryReq<QueryLoginLogReq> req)
|
||||||
|
{
|
||||||
|
return Cache.QueryAsync(req);
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,8 @@ namespace NetAdmin.SysComponent.Host.Controllers.Sys;
|
|||||||
/// 请求日志服务
|
/// 请求日志服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))]
|
[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))]
|
||||||
public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequestLogCache, IRequestLogService>(cache)
|
public sealed class RequestLogController(IRequestLogCache cache)
|
||||||
, IRequestLogModule
|
: ControllerBase<IRequestLogCache, IRequestLogService>(cache), IRequestLogModule
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量删除请求日志
|
/// 批量删除请求日志
|
@ -26,4 +26,15 @@ export default {
|
|||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存项
|
||||||
|
*/
|
||||||
|
getEntry: {
|
||||||
|
url: `${config.API_URL}/api/sys/cache/get.entry`,
|
||||||
|
name: `获取缓存项`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
106
src/frontend/admin/src/api/sys/loginlog.js
Normal file
106
src/frontend/admin/src/api/sys/loginlog.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* 登录日志服务
|
||||||
|
* @module @/api/sys/login.log
|
||||||
|
*/
|
||||||
|
import config from '@/config'
|
||||||
|
import http from '@/utils/request'
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* 批量删除登录日志
|
||||||
|
*/
|
||||||
|
bulkDelete: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/bulk.delete`,
|
||||||
|
name: `批量删除登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录日志计数
|
||||||
|
*/
|
||||||
|
count: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/count`,
|
||||||
|
name: `登录日志计数`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建登录日志
|
||||||
|
*/
|
||||||
|
create: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/create`,
|
||||||
|
name: `创建登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除登录日志
|
||||||
|
*/
|
||||||
|
delete: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/delete`,
|
||||||
|
name: `删除登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录日志是否存在
|
||||||
|
*/
|
||||||
|
exist: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/exist`,
|
||||||
|
name: `登录日志是否存在`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出登录日志
|
||||||
|
*/
|
||||||
|
export: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/export`,
|
||||||
|
name: `导出登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个登录日志
|
||||||
|
*/
|
||||||
|
get: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/get`,
|
||||||
|
name: `获取单个登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询登录日志
|
||||||
|
*/
|
||||||
|
pagedQuery: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/paged.query`,
|
||||||
|
name: `分页查询登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询登录日志
|
||||||
|
*/
|
||||||
|
query: {
|
||||||
|
url: `${config.API_URL}/api/sys/login.log/query`,
|
||||||
|
name: `查询登录日志`,
|
||||||
|
post: async function (data = {}, config = {}) {
|
||||||
|
return await http.post(this.url, data, config)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* 请求日志服务
|
* 请求日志服务
|
||||||
* @module @/api/sys/log
|
* @module @/api/sys/request.log
|
||||||
*/
|
*/
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
import http from '@/utils/request'
|
import http from '@/utils/request'
|
||||||
@ -9,7 +9,7 @@ export default {
|
|||||||
* 请求日志计数
|
* 请求日志计数
|
||||||
*/
|
*/
|
||||||
count: {
|
count: {
|
||||||
url: `${config.API_URL}/api/sys/log/count`,
|
url: `${config.API_URL}/api/sys/request.log/count`,
|
||||||
name: `请求日志计数`,
|
name: `请求日志计数`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -20,7 +20,7 @@ export default {
|
|||||||
* 导出请求日志
|
* 导出请求日志
|
||||||
*/
|
*/
|
||||||
export: {
|
export: {
|
||||||
url: `${config.API_URL}/api/sys/log/export`,
|
url: `${config.API_URL}/api/sys/request.log/export`,
|
||||||
name: `导出请求日志`,
|
name: `导出请求日志`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -31,7 +31,7 @@ export default {
|
|||||||
* 获取单个请求日志
|
* 获取单个请求日志
|
||||||
*/
|
*/
|
||||||
get: {
|
get: {
|
||||||
url: `${config.API_URL}/api/sys/log/get`,
|
url: `${config.API_URL}/api/sys/request.log/get`,
|
||||||
name: `获取单个请求日志`,
|
name: `获取单个请求日志`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -42,7 +42,7 @@ export default {
|
|||||||
* 获取条形图数据
|
* 获取条形图数据
|
||||||
*/
|
*/
|
||||||
getBarChart: {
|
getBarChart: {
|
||||||
url: `${config.API_URL}/api/sys/log/get.bar.chart`,
|
url: `${config.API_URL}/api/sys/request.log/get.bar.chart`,
|
||||||
name: `获取条形图数据`,
|
name: `获取条形图数据`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -53,7 +53,7 @@ export default {
|
|||||||
* 描述分组饼图数据
|
* 描述分组饼图数据
|
||||||
*/
|
*/
|
||||||
getPieChartByApiSummary: {
|
getPieChartByApiSummary: {
|
||||||
url: `${config.API_URL}/api/sys/log/get.pie.chart.by.api.summary`,
|
url: `${config.API_URL}/api/sys/request.log/get.pie.chart.by.api.summary`,
|
||||||
name: `描述分组饼图数据`,
|
name: `描述分组饼图数据`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -64,7 +64,7 @@ export default {
|
|||||||
* 状态码分组饼图数据
|
* 状态码分组饼图数据
|
||||||
*/
|
*/
|
||||||
getPieChartByHttpStatusCode: {
|
getPieChartByHttpStatusCode: {
|
||||||
url: `${config.API_URL}/api/sys/log/get.pie.chart.by.http.status.code`,
|
url: `${config.API_URL}/api/sys/request.log/get.pie.chart.by.http.status.code`,
|
||||||
name: `状态码分组饼图数据`,
|
name: `状态码分组饼图数据`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -75,7 +75,7 @@ export default {
|
|||||||
* 分页查询请求日志
|
* 分页查询请求日志
|
||||||
*/
|
*/
|
||||||
pagedQuery: {
|
pagedQuery: {
|
||||||
url: `${config.API_URL}/api/sys/log/paged.query`,
|
url: `${config.API_URL}/api/sys/request.log/paged.query`,
|
||||||
name: `分页查询请求日志`,
|
name: `分页查询请求日志`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
||||||
@ -86,7 +86,7 @@ export default {
|
|||||||
* 查询请求日志
|
* 查询请求日志
|
||||||
*/
|
*/
|
||||||
query: {
|
query: {
|
||||||
url: `${config.API_URL}/api/sys/log/query`,
|
url: `${config.API_URL}/api/sys/request.log/query`,
|
||||||
name: `查询请求日志`,
|
name: `查询请求日志`,
|
||||||
post: async function (data = {}, config = {}) {
|
post: async function (data = {}, config = {}) {
|
||||||
return await http.post(this.url, data, config)
|
return await http.post(this.url, data, config)
|
@ -4,7 +4,7 @@
|
|||||||
<div
|
<div
|
||||||
:style="{ display: $TOOL.getNestedProperty(row, $attrs.prop) ? 'flex' : 'none' }"
|
:style="{ display: $TOOL.getNestedProperty(row, $attrs.prop) ? 'flex' : 'none' }"
|
||||||
@click="click($TOOL.getNestedProperty(row, $attrs.prop))"
|
@click="click($TOOL.getNestedProperty(row, $attrs.prop))"
|
||||||
class="avatar">
|
class="el-table-column-avatar">
|
||||||
<el-avatar v-if="$TOOL.getNestedProperty(row, $attrs.nestProp)" :src="getAvatar(row, $attrs.nestProp)" size="small"></el-avatar>
|
<el-avatar v-if="$TOOL.getNestedProperty(row, $attrs.nestProp)" :src="getAvatar(row, $attrs.nestProp)" size="small"></el-avatar>
|
||||||
<div>
|
<div>
|
||||||
<p>{{ $TOOL.getNestedProperty(row, $attrs.nestProp) }}</p>
|
<p>{{ $TOOL.getNestedProperty(row, $attrs.nestProp) }}</p>
|
||||||
@ -44,18 +44,4 @@ export default {
|
|||||||
watch: {},
|
watch: {},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style scoped></style>
|
||||||
.avatar {
|
|
||||||
div:last-child {
|
|
||||||
line-height: 1.2rem;
|
|
||||||
p:last-child {
|
|
||||||
color: var(--el-color-info-light-3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -17,7 +17,7 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
if (this.ip) {
|
if (this.ip) {
|
||||||
this.region = '...'
|
this.region = '...'
|
||||||
http.get(`http://ip.line92.com/?ip=${this.ip}`).then((x) => {
|
http.get(`http://ip.line92.xyz/?ip=${this.ip}`).then((x) => {
|
||||||
this.region = x.region
|
this.region = x.region
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
51
src/frontend/admin/src/components/scTable/fieldFilter.vue
Normal file
51
src/frontend/admin/src/components/scTable/fieldFilter.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<sc-dialog v-model="visible" :title="$t('高级筛选')" :width="800" destroy-on-close>
|
||||||
|
<el-form :model="form" :rules="rules" label-width="10rem" ref="form">
|
||||||
|
<el-form-item :label="$t('字段名')" prop="field">
|
||||||
|
<el-input v-model="form.field" :placeholder="$t('字段名')" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('操作符')" prop="operator">
|
||||||
|
<el-input v-model="form.operator" :placeholder="$t('操作符')" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('字段值')" prop="value">
|
||||||
|
<el-input v-model="form.value" :placeholder="$t('一行一个')" :rows="5" clearable type="textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||||
|
<el-button @click="submit" type="primary">{{ $t('确定') }}</el-button>
|
||||||
|
</template>
|
||||||
|
</sc-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {},
|
||||||
|
visible: false,
|
||||||
|
callback: () => {},
|
||||||
|
rules: {
|
||||||
|
field: [{ required: true, message: this.$t('请输入字段名'), trigger: 'blur' }],
|
||||||
|
operator: [{ required: true, message: this.$t('请输入操作符'), trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(form, callback) {
|
||||||
|
Object.assign(this.form, form)
|
||||||
|
this.visible = true
|
||||||
|
this.callback = callback
|
||||||
|
},
|
||||||
|
async submit() {
|
||||||
|
const valid = await this.$refs.form.validate().catch(() => {})
|
||||||
|
if (!valid) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.callback(this.form)
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
@ -200,12 +200,14 @@
|
|||||||
<sc-contextmenu-item v-if="exportApi" :title="$t('导出文件')" command="export" divided icon="el-icon-download"></sc-contextmenu-item>
|
<sc-contextmenu-item v-if="exportApi" :title="$t('导出文件')" command="export" divided icon="el-icon-download"></sc-contextmenu-item>
|
||||||
<sc-contextmenu-item :title="$t('重新加载')" command="refresh" icon="el-icon-refresh" suffix="Ctrl+R"></sc-contextmenu-item>
|
<sc-contextmenu-item :title="$t('重新加载')" command="refresh" icon="el-icon-refresh" suffix="Ctrl+R"></sc-contextmenu-item>
|
||||||
</sc-contextmenu>
|
</sc-contextmenu>
|
||||||
|
<field-filter ref="fieldFilterDialog"></field-filter>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import config from '@/config/table'
|
import config from '@/config/table'
|
||||||
import columnSetting from './columnSetting'
|
import columnSetting from './columnSetting'
|
||||||
import scContextmenuItem from '@/components/scContextmenu/item.vue'
|
import scContextmenuItem from '@/components/scContextmenu/item.vue'
|
||||||
import scContextmenu from '@/components/scContextmenu/index.vue'
|
import scContextmenu from '@/components/scContextmenu/index.vue'
|
||||||
|
import fieldFilter from './fieldFilter.vue'
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
|
|
||||||
@ -215,6 +217,7 @@ export default {
|
|||||||
scContextmenu,
|
scContextmenu,
|
||||||
scContextmenuItem,
|
scContextmenuItem,
|
||||||
columnSetting,
|
columnSetting,
|
||||||
|
fieldFilter,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
vue: { type: Object },
|
vue: { type: Object },
|
||||||
@ -378,29 +381,19 @@ export default {
|
|||||||
await this.vue.rowDel(this.current.row)
|
await this.vue.rowDel(this.current.row)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const kv = command.split('^|^')
|
const kv = command.split('^|^')
|
||||||
let value
|
this.$refs.fieldFilterDialog.open({ field: kv[0], operator: kv[1], value: kv[2] }, (data) => {
|
||||||
try {
|
const value = data.value?.split('\n') ?? ['']
|
||||||
value = await this.$prompt(this.$t('仅显示 {field} {operator}:', { field: kv[0], operator: kv[1] }), this.$t('高级筛选'), {
|
|
||||||
inputplaceholder: this.$t('一行一个'),
|
|
||||||
inputPattern: /.*/,
|
|
||||||
inputType: 'textarea',
|
|
||||||
inputValue: kv[2],
|
|
||||||
})
|
|
||||||
} catch {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
value = value.value?.split('\n') ?? ['']
|
|
||||||
this.vue.query.dynamicFilter.filters.push({
|
this.vue.query.dynamicFilter.filters.push({
|
||||||
field: kv[0],
|
field: data.field,
|
||||||
operator: kv[1],
|
operator: data.operator,
|
||||||
value: value.length === 1 ? value[0] : value,
|
value: value.length === 1 ? value[0] : value,
|
||||||
})
|
})
|
||||||
if (this.onCommand) {
|
if (this.onCommand) {
|
||||||
this.onCommand(this.vue.query.dynamicFilter.filters)
|
this.onCommand(this.vue.query.dynamicFilter.filters)
|
||||||
}
|
}
|
||||||
this.upData()
|
this.upData()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
contextMenuVisibleChange(visible) {
|
contextMenuVisibleChange(visible) {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
|
@ -486,4 +486,13 @@ export default {
|
|||||||
'作业趋势(Today)': 'Job trend (Today)',
|
'作业趋势(Today)': 'Job trend (Today)',
|
||||||
后退一时: 'Back an hour',
|
后退一时: 'Back an hour',
|
||||||
后退一日: 'Back a day',
|
后退一日: 'Back a day',
|
||||||
|
登录日志: 'Login log',
|
||||||
|
关键词: 'Keyword',
|
||||||
|
数据类型: 'Data type',
|
||||||
|
字段名: 'Field',
|
||||||
|
操作符: 'Operator',
|
||||||
|
字段值: 'Value',
|
||||||
|
一行一个: 'One line per item',
|
||||||
|
请输入字段名: 'Please enter field name',
|
||||||
|
请输入操作符: 'Please enter operator',
|
||||||
}
|
}
|
@ -483,4 +483,13 @@ export default {
|
|||||||
'作业趋势(Today)': '作业趋势(Today)',
|
'作业趋势(Today)': '作业趋势(Today)',
|
||||||
后退一时: '后退一时',
|
后退一时: '后退一时',
|
||||||
后退一日: '后退一日',
|
后退一日: '后退一日',
|
||||||
|
登录日志: '登录日志',
|
||||||
|
关键词: '关键词',
|
||||||
|
数据类型: '数据类型',
|
||||||
|
字段名: '字段名',
|
||||||
|
操作符: '操作符',
|
||||||
|
字段值: '字段值',
|
||||||
|
一行一个: '一行一个',
|
||||||
|
请输入字段名: '请输入字段名',
|
||||||
|
请输入操作符: '请输入操作符',
|
||||||
}
|
}
|
@ -36,6 +36,13 @@ const routes = [
|
|||||||
title: '账号信息',
|
title: '账号信息',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/profile/logs',
|
||||||
|
component: () => import(/* webpackChunkName: "userRegister" */ '@/views/profile/logs.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '登录日志',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -552,3 +552,19 @@ textarea {
|
|||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
color: var(--el-color-black);
|
color: var(--el-color-black);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-table-column-avatar {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
> div:last-child {
|
||||||
|
line-height: 1.2rem;
|
||||||
|
|
||||||
|
> p:last-child {
|
||||||
|
color: var(--el-color-info-light-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -253,12 +253,9 @@ tool.unicodeDecode = function (str) {
|
|||||||
}
|
}
|
||||||
// 高亮关键词
|
// 高亮关键词
|
||||||
tool.highLightKeywords = function (str) {
|
tool.highLightKeywords = function (str) {
|
||||||
console.error(str)
|
return str
|
||||||
var ret = str
|
|
||||||
.replace(new RegExp('(Body)', 'gi'), '<span class=keywords-highlight>$1</span>')
|
.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>')
|
.replace(new RegExp('(http://cloud_code_adm_api.*?),', 'gi'), '<span class=keywords-highlight>$1</span>')
|
||||||
console.error(ret)
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
// 属性排序
|
// 属性排序
|
||||||
tool.sortProperties = function (obj) {
|
tool.sortProperties = function (obj) {
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
<chart-bar
|
<chart-bar
|
||||||
:api="[
|
:api="[
|
||||||
{
|
{
|
||||||
file: 'sys_log',
|
file: 'sys_requestlog',
|
||||||
name: 'getBarChart',
|
name: 'getBarChart',
|
||||||
label: '今日',
|
label: '今日',
|
||||||
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
|
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
file: 'sys_log',
|
file: 'sys_requestlog',
|
||||||
name: 'getBarChart',
|
name: 'getBarChart',
|
||||||
label: '昨日',
|
label: '昨日',
|
||||||
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
|
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
<chart-pie
|
<chart-pie
|
||||||
:api="[
|
:api="[
|
||||||
{
|
{
|
||||||
file: 'sys_log',
|
file: 'sys_requestlog',
|
||||||
name: 'getPieChartByApiSummary',
|
name: 'getPieChartByApiSummary',
|
||||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||||
radius: ['70%', '100%'],
|
radius: ['70%', '100%'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
file: 'sys_log',
|
file: 'sys_requestlog',
|
||||||
name: 'getPieChartByHttpStatusCode',
|
name: 'getPieChartByHttpStatusCode',
|
||||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||||
radius: [0, '30%'],
|
radius: [0, '30%'],
|
||||||
|
@ -29,7 +29,9 @@
|
|||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main class="profile-main">
|
<el-main class="profile-main">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
|
<keep-alive>
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
@ -63,6 +65,11 @@ export default {
|
|||||||
title: '我的消息',
|
title: '我的消息',
|
||||||
component: '/profile/message',
|
component: '/profile/message',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'el-icon-clock',
|
||||||
|
title: '登录日志',
|
||||||
|
component: '/profile/logs',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -1,39 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card :header="$t('近7天操作记录')" shadow="never">
|
<el-card :header="$t('登录日志')" shadow="never">
|
||||||
<scTable :data="data" height="auto" hideDo paginationLayout="total, prev, pager, next" ref="table">
|
<login-log :keywords="$GLOBAL.user.id" :show-filter="false"></login-log>
|
||||||
<sc-table-column :label="$t('序号')" type="index"></sc-table-column>
|
|
||||||
<sc-table-column :label="$t('业务名称')" min-width="240" prop="title"></sc-table-column>
|
|
||||||
<sc-table-column label="IP" prop="ip" width="150"></sc-table-column>
|
|
||||||
<sc-table-column :label="$t('结果')" prop="code" width="150">
|
|
||||||
<el-tag type="success">{{ $t('成功') }}</el-tag>
|
|
||||||
</sc-table-column>
|
|
||||||
<sc-table-column :label="$t('操作时间')" prop="time" width="150"></sc-table-column>
|
|
||||||
</scTable>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScTable from '@/components/scTable/index.vue'
|
import LoginLog from '@/views/sys/log/login/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ScTable },
|
components: { LoginLog },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {}
|
||||||
data: [
|
|
||||||
{
|
|
||||||
title: '修改用户 lolowan',
|
|
||||||
ip: '211.187.11.18',
|
|
||||||
code: '成功',
|
|
||||||
time: '2022-10-10 08:41:17',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用户登录',
|
|
||||||
ip: '211.187.11.18',
|
|
||||||
code: '成功',
|
|
||||||
time: '2022-10-10 08:21:51',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
74
src/frontend/admin/src/views/sys/cache/index.vue
vendored
74
src/frontend/admin/src/views/sys/cache/index.vue
vendored
@ -52,14 +52,34 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</el-header>
|
</el-header>
|
||||||
|
<el-header>
|
||||||
<el-main class="nopadding">
|
<div class="left-panel">
|
||||||
<sc-table :params="query" :query-api="$API.sys_cache.getAllEntries" @row-click="rowClick" ref="table" row-key="key" stripe>
|
<form @keyup.enter="search" @submit.prevent="search" class="right-panel-search">
|
||||||
<el-table-column :label="$t('键名')" prop="key" show-overflow-tooltip />
|
<el-input v-model="this.query.keywords" :placeholder="$t('关键词')" clearable style="width: 25rem" />
|
||||||
<el-table-column :label="$t('键值')" prop="data" show-overflow-tooltip />
|
<el-button-group>
|
||||||
<el-table-column :label="$t('滑动过期')" align="right" prop="sldExpTime" width="200" />
|
<el-button @click="search" icon="el-icon-search" type="primary">{{ $t('查询') }}</el-button>
|
||||||
<el-table-column :label="$t('绝对过期')" align="right" prop="absExpTime" width="200" />
|
<el-button @click="reset" icon="el-icon-refresh-left">{{ $t('重置') }}</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel"></div>
|
||||||
|
</el-header>
|
||||||
|
<el-main v-loading="loading" class="nopadding">
|
||||||
|
<sc-table v-if="tableData.length > 0" :data="tableData" :page-size="100" hide-refresh pagination-layout="total" stripe>
|
||||||
|
<el-table-column :label="$t('键名')" prop="key" />
|
||||||
|
<el-table-column :label="$t('数据类型')" align="center" prop="type" width="100" />
|
||||||
|
<el-table-column :label="$t('过期时间')" align="right" prop="expireTime" width="200" />
|
||||||
|
<na-col-operation
|
||||||
|
:buttons="[
|
||||||
|
{
|
||||||
|
icon: 'el-icon-view',
|
||||||
|
click: rowClick,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:vue="this"
|
||||||
|
width="100" />
|
||||||
</sc-table>
|
</sc-table>
|
||||||
|
<el-empty v-else></el-empty>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
<na-info v-if="dialog.info" ref="info"></na-info>
|
<na-info v-if="dialog.info" ref="info"></na-info>
|
||||||
@ -74,14 +94,14 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
loading: true,
|
||||||
dialog: {
|
dialog: {
|
||||||
info: false,
|
info: false,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
filter: {
|
keywords: '',
|
||||||
dbIndex: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
tableData: [],
|
||||||
statistics: {
|
statistics: {
|
||||||
keyspaceHits: 0,
|
keyspaceHits: 0,
|
||||||
keyspaceMisses: 0,
|
keyspaceMisses: 0,
|
||||||
@ -93,10 +113,32 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
reset() {
|
||||||
|
this.query.keywords = ''
|
||||||
|
this.search()
|
||||||
|
},
|
||||||
|
search() {
|
||||||
|
this.getData()
|
||||||
|
},
|
||||||
async rowClick(row) {
|
async rowClick(row) {
|
||||||
|
this.loading = true
|
||||||
|
const res = await this.$API.sys_cache.getEntry.post({ key: row.key })
|
||||||
this.dialog.info = true
|
this.dialog.info = true
|
||||||
await this.$nextTick()
|
await this.$nextTick()
|
||||||
this.$refs.info.open(this.$TOOL.sortProperties(row), this.$t('缓存详情'))
|
this.$refs.info.open(this.$TOOL.sortProperties(res.data), this.$t('缓存详情'))
|
||||||
|
this.loading = false
|
||||||
|
},
|
||||||
|
async getData() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await this.$API.sys_cache.getAllEntries.post(this.query)
|
||||||
|
if (res.data) {
|
||||||
|
this.tableData = res.data
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
this.loading = false
|
||||||
},
|
},
|
||||||
async cacheStatistics() {
|
async cacheStatistics() {
|
||||||
try {
|
try {
|
||||||
@ -109,15 +151,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
this.cacheStatistics()
|
this.cacheStatistics()
|
||||||
},
|
this.getData()
|
||||||
watch: {
|
|
||||||
'query.filter.dbIndex': {
|
|
||||||
handler() {
|
|
||||||
this.$refs.table.upData()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<el-container>
|
<el-container>
|
||||||
<el-header style="height: auto; padding: 0 1rem">
|
<el-header style="height: auto; padding: 0 1rem">
|
||||||
<sc-select-filter
|
<sc-select-filter
|
||||||
|
v-if="showFilter"
|
||||||
:data="[
|
:data="[
|
||||||
{
|
{
|
||||||
title: $t('登录结果'),
|
title: $t('登录结果'),
|
||||||
@ -29,7 +30,7 @@
|
|||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:vue="this"
|
:vue="this"
|
||||||
@reset="Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))"
|
@reset="onReset"
|
||||||
@search="onSearch"
|
@search="onSearch"
|
||||||
dateFormat="YYYY-MM-DD HH:mm:ss"
|
dateFormat="YYYY-MM-DD HH:mm:ss"
|
||||||
dateType="datetimerange"
|
dateType="datetimerange"
|
||||||
@ -40,12 +41,12 @@
|
|||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="nopadding">
|
<el-main class="nopadding">
|
||||||
<sc-table
|
<sc-table
|
||||||
:context-menus="['id', 'httpStatusCode', 'createdClientIp', 'createdUserAgent', 'createdTime']"
|
:context-menus="['id', 'httpStatusCode', 'loginUserName', 'createdClientIp', 'createdUserAgent', 'createdTime']"
|
||||||
:context-opers="['view']"
|
:context-opers="['view']"
|
||||||
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
||||||
:export-api="$API.sys_log.export"
|
:export-api="$API.sys_loginlog.export"
|
||||||
:params="query"
|
:params="query"
|
||||||
:query-api="$API.sys_log.pagedQuery"
|
:query-api="$API.sys_loginlog.pagedQuery"
|
||||||
:vue="this"
|
:vue="this"
|
||||||
ref="table"
|
ref="table"
|
||||||
remote-filter
|
remote-filter
|
||||||
@ -59,14 +60,14 @@
|
|||||||
{{ row.httpStatusCode === 200 ? '成功' : '失败' }}
|
{{ row.httpStatusCode === 200 ? '成功' : '失败' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('登录名')" prop="detail.loginName" width="150" />
|
<el-table-column :label="$t('登录名')" prop="loginUserName" sortable="custom" width="150" />
|
||||||
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<na-ip :ip="row.createdClientIp"></na-ip>
|
<na-ip :ip="row.createdClientIp"></na-ip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('操作系统')" align="center" prop="detail.os" width="150" />
|
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
|
||||||
<el-table-column :label="$t('用户代理')" prop="detail.createdUserAgent" show-overflow-tooltip sortable="custom" />
|
<el-table-column :label="$t('用户代理')" prop="createdUserAgent" show-overflow-tooltip sortable="custom" />
|
||||||
<na-col-operation
|
<na-col-operation
|
||||||
:buttons="[
|
:buttons="[
|
||||||
{
|
{
|
||||||
@ -91,13 +92,7 @@ export default {
|
|||||||
naInfo,
|
naInfo,
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
created() {
|
created() {},
|
||||||
this.query.dynamicFilter.filters.push({
|
|
||||||
field: 'apiPathCrc32',
|
|
||||||
operator: 'eq',
|
|
||||||
value: '1290209789',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dialog: {
|
dialog: {
|
||||||
@ -106,13 +101,7 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
query: {
|
query: {
|
||||||
dynamicFilter: {
|
dynamicFilter: {
|
||||||
filters: [
|
filters: [],
|
||||||
{
|
|
||||||
field: 'createdTime',
|
|
||||||
operator: 'dateRange',
|
|
||||||
value: [this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'), this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
filter: {},
|
filter: {},
|
||||||
keywords: this.keywords,
|
keywords: this.keywords,
|
||||||
@ -128,15 +117,12 @@ export default {
|
|||||||
})
|
})
|
||||||
this.$refs.search.search()
|
this.$refs.search.search()
|
||||||
},
|
},
|
||||||
|
onReset() {
|
||||||
|
if (!this.showFilter) return
|
||||||
|
Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))
|
||||||
|
},
|
||||||
//搜索
|
//搜索
|
||||||
onSearch(form) {
|
onSearch(form) {
|
||||||
if (this.query.dynamicFilter.filters.findIndex((x) => x.field === 'apiPathCrc32') < 0) {
|
|
||||||
this.query.dynamicFilter.filters.push({
|
|
||||||
field: 'apiPathCrc32',
|
|
||||||
operator: 'eq',
|
|
||||||
value: '1290209789',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (Array.isArray(form.dy.createdTime)) {
|
if (Array.isArray(form.dy.createdTime)) {
|
||||||
this.query.dynamicFilter.filters.push({
|
this.query.dynamicFilter.filters.push({
|
||||||
field: 'createdTime',
|
field: 'createdTime',
|
||||||
@ -165,7 +151,7 @@ export default {
|
|||||||
async rowClick(row) {
|
async rowClick(row) {
|
||||||
this.dialog.info = true
|
this.dialog.info = true
|
||||||
await this.$nextTick()
|
await this.$nextTick()
|
||||||
const res = await this.$API.sys_log.get.post({
|
const res = await this.$API.sys_loginlog.get.post({
|
||||||
id: row.id,
|
id: row.id,
|
||||||
})
|
})
|
||||||
this.$refs.info.open(this.$TOOL.sortProperties(res.data), this.$t('日志详情:{id}', { id: row.id }))
|
this.$refs.info.open(this.$TOOL.sortProperties(res.data), this.$t('日志详情:{id}', { id: row.id }))
|
||||||
@ -180,18 +166,8 @@ export default {
|
|||||||
type: 'root',
|
type: 'root',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
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`,
|
|
||||||
]
|
|
||||||
this.$refs.search.keeps.push({
|
|
||||||
field: 'createdTime',
|
|
||||||
value: this.$refs.search.form.dy.createdTime,
|
|
||||||
type: 'dy',
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
props: ['keywords'],
|
props: { keywords: { type: String }, showFilter: { type: Boolean, default: true } },
|
||||||
watch: {},
|
watch: {},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -37,16 +37,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'cascader',
|
type: 'cascader',
|
||||||
field: ['dy', 'api.id'],
|
field: ['dy', 'apiPathCrc32'],
|
||||||
api: $API.sys_api.query,
|
api: $API.sys_api.query,
|
||||||
props: { label: 'summary', value: 'id', checkStrictly: true, expandTrigger: 'hover', emitPath: false },
|
props: { label: 'summary', value: 'pathCrc32', checkStrictly: true, expandTrigger: 'hover', emitPath: false },
|
||||||
placeholder: $t('请求服务'),
|
placeholder: $t('请求服务'),
|
||||||
style: 'width:20rem',
|
style: 'width:20rem',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'input',
|
type: 'input',
|
||||||
field: ['root', 'keywords'],
|
field: ['root', 'keywords'],
|
||||||
placeholder: $t('日志编号 / 用户 / 客户端IP'),
|
placeholder: $t('日志编号 / 用户编号 / 客户端IP'),
|
||||||
style: 'width:25rem',
|
style: 'width:25rem',
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
@ -65,10 +65,11 @@
|
|||||||
:context-menus="['id', 'httpStatusCode', 'apiPathCrc32', 'ownerId', 'httpMethod', 'duration', 'createdClientIp', 'createdTime']"
|
:context-menus="['id', 'httpStatusCode', 'apiPathCrc32', 'ownerId', 'httpMethod', 'duration', 'createdClientIp', 'createdTime']"
|
||||||
:context-opers="[]"
|
:context-opers="[]"
|
||||||
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
||||||
:export-api="$API.sys_log.export"
|
:export-api="$API.sys_requestlog.export"
|
||||||
:params="query"
|
:params="query"
|
||||||
:query-api="$API.sys_log.pagedQuery"
|
:query-api="$API.sys_requestlog.pagedQuery"
|
||||||
:vue="this"
|
:vue="this"
|
||||||
|
@data-change="dataChange"
|
||||||
ref="table"
|
ref="table"
|
||||||
remote-filter
|
remote-filter
|
||||||
remote-sort
|
remote-sort
|
||||||
@ -84,8 +85,12 @@
|
|||||||
<el-table-column :label="$t('请求服务')" align="center">
|
<el-table-column :label="$t('请求服务')" align="center">
|
||||||
<el-table-column :label="$t('路径')" prop="apiPathCrc32" show-overflow-tooltip sortable="custom">
|
<el-table-column :label="$t('路径')" prop="apiPathCrc32" show-overflow-tooltip sortable="custom">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<p>{{ row.api.id }}</p>
|
<p>
|
||||||
<p>{{ row.api.summary }}</p>
|
{{ apis?.find((x) => x.pathCrc32 === row.apiPathCrc32)?.id }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ apis?.find((x) => x.pathCrc32 === row.apiPathCrc32)?.summary }}
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('方法')" align="center" prop="httpMethod" sortable="custom" width="100">
|
<el-table-column :label="$t('方法')" align="center" prop="httpMethod" sortable="custom" width="100">
|
||||||
@ -104,15 +109,29 @@
|
|||||||
width="90">
|
width="90">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<na-col-user
|
<el-table-column
|
||||||
v-auth="'sys/log/operation/user'"
|
v-auth="'sys/log/operation/user'"
|
||||||
:label="$t('用户')"
|
:label="$t('用户')"
|
||||||
header-align="center"
|
header-align="center"
|
||||||
nestProp="owner.userName"
|
|
||||||
nestProp2="owner.id"
|
|
||||||
prop="ownerId"
|
prop="ownerId"
|
||||||
sortable="custom"
|
sortable="custom"
|
||||||
width="170"></na-col-user>
|
width="170">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="row.ownerId" :style="{ display: 'flex' }" @click="userClick(row.ownerId)" class="el-table-column-avatar">
|
||||||
|
<el-avatar
|
||||||
|
v-if="owners?.find((x) => x.id === row.ownerId)"
|
||||||
|
:src="
|
||||||
|
owners?.find((x) => x.id === row.ownerId)?.avatar ??
|
||||||
|
$CONFIG.DEFAULT_AVATAR(owners?.find((x) => x.id === row.ownerId)?.userName)
|
||||||
|
"
|
||||||
|
size="small"></el-avatar>
|
||||||
|
<div>
|
||||||
|
<p>{{ owners?.find((x) => x.id === row.ownerId)?.userName }}</p>
|
||||||
|
<p>{{ owners?.find((x) => x.id === row.ownerId)?.id }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<na-ip :ip="row.createdClientIp"></na-ip>
|
<na-ip :ip="row.createdClientIp"></na-ip>
|
||||||
@ -132,14 +151,24 @@
|
|||||||
</el-container>
|
</el-container>
|
||||||
|
|
||||||
<na-info v-if="dialog.info" ref="info"></na-info>
|
<na-info v-if="dialog.info" ref="info"></na-info>
|
||||||
|
<save-dialog
|
||||||
|
v-if="dialog.save"
|
||||||
|
@closed="dialog.save = null"
|
||||||
|
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||||
|
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||||
|
ref="saveDialog"></save-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const saveDialog = defineAsyncComponent(() => import('@/views/sys/user/save.vue'))
|
||||||
import naInfo from '@/components/naInfo/index.vue'
|
import naInfo from '@/components/naInfo/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
naInfo,
|
naInfo,
|
||||||
|
saveDialog,
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
created() {
|
created() {
|
||||||
@ -152,6 +181,8 @@ export default {
|
|||||||
dialog: {
|
dialog: {
|
||||||
info: false,
|
info: false,
|
||||||
},
|
},
|
||||||
|
owners: [],
|
||||||
|
apis: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
query: {
|
query: {
|
||||||
dynamicFilter: {
|
dynamicFilter: {
|
||||||
@ -159,7 +190,10 @@ export default {
|
|||||||
{
|
{
|
||||||
field: 'createdTime',
|
field: 'createdTime',
|
||||||
operator: 'dateRange',
|
operator: 'dateRange',
|
||||||
value: [this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'), this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')],
|
value: [
|
||||||
|
this.$TOOL.dateFormat(new Date(new Date() - 3600 * 1000), 'yyyy-MM-dd hh:mm:ss'),
|
||||||
|
this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -171,6 +205,38 @@ export default {
|
|||||||
},
|
},
|
||||||
inject: ['reload'],
|
inject: ['reload'],
|
||||||
methods: {
|
methods: {
|
||||||
|
userClick(id) {
|
||||||
|
this.dialog.save = { mode: 'view', row: { id } }
|
||||||
|
},
|
||||||
|
async dataChange(data) {
|
||||||
|
this.owners = []
|
||||||
|
this.apis = []
|
||||||
|
const ownerIds = data.data.rows?.filter((x) => x.ownerId).map((x) => x.ownerId)
|
||||||
|
const apiCrcs = data.data.rows?.map((x) => x.apiPathCrc32)
|
||||||
|
const res = await Promise.all([
|
||||||
|
ownerIds && ownerIds.length > 0
|
||||||
|
? this.$API.sys_user.query.post({
|
||||||
|
dynamicFilter: {
|
||||||
|
field: 'id',
|
||||||
|
operator: 'any',
|
||||||
|
value: ownerIds,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: new Promise((x) => x({ data: [] })),
|
||||||
|
|
||||||
|
apiCrcs && apiCrcs.length > 0
|
||||||
|
? this.$API.sys_api.query.post({
|
||||||
|
dynamicFilter: {
|
||||||
|
field: 'pathCrc32',
|
||||||
|
operator: 'any',
|
||||||
|
value: apiCrcs,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: new Promise((x) => x({ data: [] })),
|
||||||
|
])
|
||||||
|
this.owners = res[0].data
|
||||||
|
this.apis = res[1].data
|
||||||
|
},
|
||||||
filterChange(data) {
|
filterChange(data) {
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||||
@ -194,11 +260,11 @@ export default {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (typeof form.dy['api.id'] === 'string' && form.dy['api.id'].trim() !== '') {
|
if (typeof form.dy['apiPathCrc32'] === 'number' && form.dy['apiPathCrc32'] !== 0) {
|
||||||
this.query.dynamicFilter.filters.push({
|
this.query.dynamicFilter.filters.push({
|
||||||
field: 'api.id',
|
field: 'apiPathCrc32',
|
||||||
operator: 'eq',
|
operator: 'eq',
|
||||||
value: form.dy['api.id'],
|
value: form.dy['apiPathCrc32'],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,8 +297,9 @@ export default {
|
|||||||
async rowClick(row) {
|
async rowClick(row) {
|
||||||
this.dialog.info = true
|
this.dialog.info = true
|
||||||
await this.$nextTick()
|
await this.$nextTick()
|
||||||
const res = await this.$API.sys_log.get.post({
|
const res = await this.$API.sys_requestlog.get.post({
|
||||||
id: row.id,
|
id: row.id,
|
||||||
|
createdTime: row.createdTime,
|
||||||
})
|
})
|
||||||
this.$refs.info.open(this.$TOOL.sortProperties(res.data), this.$t('日志详情:{id}', { id: row.id }))
|
this.$refs.info.open(this.$TOOL.sortProperties(res.data), this.$t('日志详情:{id}', { id: row.id }))
|
||||||
},
|
},
|
||||||
@ -253,11 +320,12 @@ export default {
|
|||||||
value: this.ownerId,
|
value: this.ownerId,
|
||||||
type: 'dy',
|
type: 'dy',
|
||||||
})
|
})
|
||||||
|
this.$refs.search.form.dy.ownerId = this.ownerId
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$refs.search.form.dy.createdTime = [
|
this.$refs.search.form.dy.createdTime = [
|
||||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
this.$TOOL.dateFormat(new Date(new Date() - 3600 * 1000), 'yyyy-MM-dd hh:mm:ss'),
|
||||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'),
|
||||||
]
|
]
|
||||||
this.$refs.search.keeps.push({
|
this.$refs.search.keeps.push({
|
||||||
field: 'createdTime',
|
field: 'createdTime',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user