Merge pull request '🍉 代码优化' (#416) from jasondom/Admin.NET.Pro:v2-2 into v2

Reviewed-on: https://code.adminnet.top/Admin.NET/Admin.NET.Pro/pulls/416
This commit is contained in:
zuohuaijun 2025-08-24 23:46:33 +08:00
commit c33e1d2742
37 changed files with 785 additions and 418 deletions

View File

@ -39,7 +39,7 @@ public class CommonConst
public const string SendErrorMail = "Send:ErrorMail";
/// <summary>
/// 远程请求请求头参数键值
/// 远程请求请求头参数键值前缀
/// </summary>
public const string HttpRemoteHeaderKeyPrefix = "__HTTP_CLIENT_";

View File

@ -11,10 +11,11 @@ namespace Admin.NET.Core;
/// <summary>
/// Http请求日志表
/// </summary>
[SugarTable(null, "Http请求日志表")]
[SysTable]
[LogTable]
public partial class SysLogHttp : EntityBaseId
[SugarTable(null, "Http请求日志表")]
[SugarIndex("i_{table}_n", nameof(HttpClientName), OrderByType.Asc)]
public partial class SysLogHttp : EntityTenantId
{
/// <summary>
/// 客户端名称
@ -43,6 +44,12 @@ public partial class SysLogHttp : EntityBaseId
[SugarColumn(ColumnDescription = "是否成功")]
public YesNoEnum? IsSuccessStatusCode { get; set; }
/// <summary>
/// 模块名称
/// </summary>
[SugarColumn(ColumnDescription = "模块名称")]
public string? ActionName { get; set; }
/// <summary>
/// 请求地址
/// </summary>
@ -108,4 +115,17 @@ public partial class SysLogHttp : EntityBaseId
/// </summary>
[SugarColumn(ColumnDescription = "创建时间")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 创建者Id
/// </summary>
[OwnerUser]
[SugarColumn(ColumnDescription = "创建者Id", IsOnlyIgnoreUpdate = true)]
public virtual long? CreateUserId { get; set; }
/// <summary>
/// 创建者姓名
/// </summary>
[SugarColumn(ColumnDescription = "创建者姓名", Length = 64, IsOnlyIgnoreUpdate = true)]
public virtual string? CreateUserName { get; set; }
}

View File

@ -13,8 +13,8 @@ namespace Admin.NET.Core;
/// </summary>
public class DatabaseLoggingWriter : IDatabaseLoggingWriter, IDisposable
{
private static readonly Lazy<UserManager> _userManager = new(() => App.GetService<UserManager>());
private static readonly Lazy<SqlSugarRepository<SysUser>> _sysUserRep = new(() => App.GetService<SqlSugarRepository<SysUser>>());
private static readonly Lazy<UserManager> _userManager = new(() => App.GetService<UserManager>());
private readonly ILogger<DatabaseLoggingWriter> _logger;
private readonly SysConfigService _sysConfigService;
private readonly IEventPublisher _eventPublisher;

View File

@ -14,9 +14,10 @@ namespace Admin.NET.Core;
/// </summary>
public class HttpLoggingHandler : DelegatingHandler, ITransient
{
private static readonly string HttpNameKey = CommonConst.HttpRemoteHeaderKeyPrefix + "NAME__";
private static readonly string ApiDescKey = CommonConst.HttpRemoteHeaderKeyPrefix + "API_DESC__";
private static readonly string IgnoreLogKey = CommonConst.HttpRemoteHeaderKeyPrefix + "IGNORE_LOG__";
private static readonly string ApiDescKey = CommonConst.HttpRemoteHeaderKeyPrefix + "API_DESC__";
private static readonly string HttpNameKey = CommonConst.HttpRemoteHeaderKeyPrefix + "NAME__";
private static readonly Lazy<UserManager> _userManager = new(() => App.GetService<UserManager>());
private readonly Dictionary<string, bool> _enabledLogMap;
private readonly SysConfigService _sysConfigService;
@ -41,19 +42,26 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
if (!enabledLog) return await base.SendAsync(request, cancellationToken);
// 判断当前配置日志开关
var attrInfo = GetRemoteApiAttrAndRemove(request.Headers);
if (!string.IsNullOrWhiteSpace(attrInfo.HttpName)) enabledLog = _enabledLogMap.GetOrDefault(attrInfo.HttpName);
if (!enabledLog || attrInfo.IgnoreLog) return await base.SendAsync(request, cancellationToken);
(string apiDesc, bool ignoreLog) = GetRemoteApiAttrAndRemove(request.Headers);
_ = request.Options.TryGetValue<string>(HttpNameKey, out var httpName);
if (!string.IsNullOrWhiteSpace(httpName)) enabledLog = _enabledLogMap.GetOrDefault(httpName);
if (!enabledLog || ignoreLog) return await base.SendAsync(request, cancellationToken);
var stopWatch = Stopwatch.StartNew();
var urlList = request.RequestUri?.LocalPath.Split("/") ?? [];
var sysLogHttp = new SysLogHttp
{
HttpApiDesc = attrInfo.ApiDesc,
HttpClientName = attrInfo.HttpName,
HttpClientName = httpName,
HttpApiDesc = apiDesc,
HttpMethod = request.Method.Method,
ActionName = urlList.Length >= 2 ? $"{urlList[^2]}/{urlList[^1]}" : urlList.Length >= 1 ? urlList[^1] : null,
RequestUrl = request.RequestUri?.ToString(),
RequestHeaders = request.Headers.ToDictionary(u => u.Key, u => u.Value.Join(";")).ToJson()
RequestHeaders = request.Headers.ToDictionary(u => u.Key, u => u.Value.Join(";")).ToJson(),
TenantId = _userManager.Value?.TenantId,
CreateUserId = _userManager.Value?.UserId,
CreateUserName = _userManager.Value?.RealName,
};
// _userManager
if (request.Content != null) sysLogHttp.RequestBody = await request.Content.ReadAsStringAsync(cancellationToken);
sysLogHttp.StartTime = DateTime.Now;
@ -88,16 +96,15 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
/// </summary>
/// <param name="headers"></param>
/// <returns></returns>
private static HttpRemoteApiAttrDto GetRemoteApiAttrAndRemove(HttpRequestHeaders headers)
private static (string apiDesc, bool ignoreLog) GetRemoteApiAttrAndRemove(HttpRequestHeaders headers)
{
var result = new HttpRemoteApiAttrDto
var result = new
{
HttpName = headers?.FirstOrDefault(u => u.Key == HttpNameKey).Value?.ToString(),
ApiDesc = headers?.FirstOrDefault(u => u.Key == ApiDescKey).Value?.ToString(),
ApiDesc = headers?.FirstOrDefault(u => u.Key == ApiDescKey).Value?.FirstOrDefault()?.ToString(),
IgnoreLog = headers?.FirstOrDefault(u => u.Key == IgnoreLogKey).Value?.ToBoolean() ?? false,
};
RemoveRemoteApiAttr(headers);
return result;
return (result.ApiDesc, result.IgnoreLog);
}
/// <summary>
@ -108,7 +115,11 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
private static void RemoveRemoteApiAttr(HttpRequestHeaders headers)
{
if (headers == null) return;
foreach (var kv in headers.Where(kv => kv.Key.StartsWith(CommonConst.HttpRemoteHeaderKeyPrefix))) headers.Remove(kv.Key);
var keys = headers
.Where(kv => kv.Key.StartsWith(CommonConst.HttpRemoteHeaderKeyPrefix))
.Select(u => u.Key)
.ToList();
foreach (var key in keys) headers.Remove(key);
}
/// <summary>
@ -121,29 +132,8 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
public static HttpRequestBuilder SetRemoteApiAttr(HttpRequestBuilder builder, string httpName, HttpRemoteApiAttribute attr)
{
builder.WithHeader(IgnoreLogKey, attr.IgnoreLog, replace:true);
builder.WithHeader(HttpNameKey, attr.Desc, replace:true);
builder.WithHeader(ApiDescKey, attr.Desc, replace:true);
builder.SetHttpClientName(httpName);
return builder;
}
}
/// <summary>
/// 远程请求相关属性
/// </summary>
public class HttpRemoteApiAttrDto
{
/// <summary>
/// 客户端名称
/// </summary>
public string HttpName { get; set; }
/// <summary>
/// 接口描述
/// </summary>
public string ApiDesc { get; set; }
/// <summary>
/// 是否忽略日志
/// </summary>
public bool IgnoreLog { get; set; }
}

View File

@ -262,7 +262,7 @@ public class LoggingParametersDto
public class LoggingReturnInformationDto
{
/// <summary>
/// 返回类型如X.Core.XResult<System.Object>
/// 返回类型
/// </summary>
public string Type { get; set; }
@ -272,7 +272,7 @@ public class LoggingReturnInformationDto
public int? HttpStatusCode { get; set; }
/// <summary>
/// 实际返回类型如Task<List<T>>
/// 实际返回类型
/// </summary>
public string ActType { get; set; }

View File

@ -0,0 +1,31 @@
// // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
// //
// // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
// //
// // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
//
// using System.Net;
//
// namespace Admin.NET.Core;
//
// /// <summary>
// /// 代理管理器接口
// /// </summary>
// public interface IProxyManager
// {
// /// <summary>
// /// 获取当前代理
// /// </summary>
// WebProxy GetCurrentProxy();
//
// /// <summary>
// /// 刷新代理
// /// </summary>
// Task RefreshProxiesAsync();
//
// /// <summary>
// /// 获取所有代理
// /// </summary>
// /// <returns></returns>
// List<WebProxy> GetAllProxies();
// }

View File

@ -0,0 +1,106 @@
// // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
// //
// // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
// //
// // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
//
// using System.Net;
//
// namespace Admin.NET.Core;
//
// /// <summary>
// /// 代理管理器
// /// </summary>
// public class ProxyManager : IProxyManager, IDisposable, ITransient
// {
// private List<WebProxy> _proxies = new();
//
// private readonly HttpRemotesOptions _options;
// private readonly object _lock = new();
// private readonly Timer _refreshTimer;
// private int _currentIndex = 0;
//
// public ProxyManager(IOptions<HttpRemotesOptions> options)
// {
// _options = options.Value;
//
// // 启动后立即加载一次
// RefreshProxiesAsync().Wait();
//
// // 每 24 小时刷新一次(可改为每天固定时间)
// _refreshTimer = new Timer(async _ => await RefreshProxiesAsync(),
// null, TimeSpan.FromHours(24), TimeSpan.FromHours(24));
// }
//
// public async Task RefreshProxiesAsync()
// {
// try
// {
// var newProxies = await FetchProxiesFromRemoteAsync();
// if (newProxies != null && newProxies.Any())
// {
// lock (_lock)
// {
// _proxies = newProxies
// .Select(p => new WebProxy(_options.Proxy.Address)
// {
// Credentials = !string.IsNullOrEmpty(_options.Proxy.Account)
// ? new NetworkCredential(_options.Proxy.Account, _options.Proxy.Password)
// : null
// })
// .ToList();
// _currentIndex = 0; // 重置索引
// }
// Console.WriteLine($"✅ 代理列表已刷新,共 {_proxies.Count} 个代理");
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"❌ 刷新代理列表失败: {ex.Message}");
// }
// }
//
// private async Task<List<ProxyConfig>> FetchProxiesFromRemoteAsync()
// {
// // 示例:从远程 API 获取代理
// using var client = new HttpClient();
// var response = await client.GetAsync("https://your-proxy-api.com/daily");
// if (response.IsSuccessStatusCode)
// {
// var json = await response.Content.ReadAsStringAsync();
// return JsonSerializer.Deserialize<List<ProxyConfig>>(json,
// new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
// }
//
// // 可替换为数据库、文件、Redis 等来源
// return new List<ProxyConfig>
// {
// new() { Address = "http://proxy1:8080", Username = "user", Password = "pass" },
// new() { Address = "http://proxy2:8080" },
// };
// }
//
// public WebProxy GetCurrentProxy()
// {
// lock (_lock)
// {
// if (!_proxies.Any()) return null;
// var proxy = _proxies[_currentIndex % _proxies.Count];
// _currentIndex = (_currentIndex + 1) % _proxies.Count;
// return proxy;
// }
// }
//
// public List<WebProxy> GetAllProxies()
// {
// lock (_lock)
// {
// return new List<WebProxy>(_proxies);
// }
// }
//
// public void Dispose()
// {
// _refreshTimer?.Dispose();
// }
// }

View File

@ -87,6 +87,11 @@ public class PageLogHttpInput : BasePageInput
/// </summary>
public string SearchKey { get; set; }
/// <summary>
/// 模块名称
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// 客户端名称
/// </summary>
@ -142,7 +147,6 @@ public class PageLogHttpInput : BasePageInput
/// 创建时间范围
/// </summary>
public DateTime?[] CreateTimeRange { get; set; }
}
/// <summary>
@ -164,6 +168,27 @@ public class ExportLogHttpInput : PageLogHttpInput
[ExcelImporter(SheetIndex = 1, IsOnlyErrorRows = true)]
public class ImportLogHttpInput : BaseImportInput
{
/// <summary>
/// 请求模块
/// </summary>
[ImporterHeader(Name = "请求模块")]
[ExporterHeader("请求模块", Format = "", Width = 25, IsBold = true)]
public string ActionName { get; set; }
/// <summary>
/// 客户端名称
/// </summary>
[ImporterHeader(Name = "客户端名称")]
[ExporterHeader("客户端名称", Format = "", Width = 25, IsBold = true)]
public string HttpClientName { get; set; }
/// <summary>
/// 接口描述
/// </summary>
[ImporterHeader(Name = "接口描述")]
[ExporterHeader("接口描述", Format = "", Width = 25, IsBold = true)]
public string HttpApiDesc { get; set; }
/// <summary>
/// 请求方式
/// </summary>
@ -248,4 +273,11 @@ public class ImportLogHttpInput : BaseImportInput
[ImporterHeader(Name = "耗时(毫秒)")]
[ExporterHeader("耗时(毫秒)", Format = "", Width = 25, IsBold = true)]
public long? Elapsed { get; set; }
/// <summary>
/// 创建用户
/// </summary>
[ImporterHeader(Name = "创建用户")]
[ExporterHeader("创建用户", Format = "", Width = 25, IsBold = true)]
public string CreateUserName { get; set; }
}

View File

@ -16,6 +16,11 @@ public class PageLogHttpOutput
/// </summary>
public long? Id { get; set; }
/// <summary>
/// 请求模块
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// 客户端名称
/// </summary>
@ -91,6 +96,11 @@ public class PageLogHttpOutput
/// </summary>
public DateTime? CreateTime { get; set; }
/// <summary>
/// 创建用户
/// </summary>
public string CreateUserName { get; set; }
}
/// <summary>

View File

@ -33,6 +33,7 @@ public class SysLogHttpService : IDynamicApiController, ITransient
input.Keyword = input.Keyword?.Trim();
var query = _sysLogHttpRep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.HttpClientName.Contains(input.Keyword) || u.HttpApiDesc.Contains(input.Keyword) || u.RequestUrl.Contains(input.Keyword) || u.RequestBody.Contains(input.Keyword) || u.ResponseBody.Contains(input.Keyword) || u.Exception.Contains(input.Keyword))
.WhereIF(!string.IsNullOrWhiteSpace(input.ActionName), u => u.ActionName.Contains(input.ActionName.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.HttpClientName), u => u.HttpClientName.Contains(input.HttpClientName.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.HttpApiDesc), u => u.HttpApiDesc.Contains(input.HttpApiDesc.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.RequestUrl), u => u.RequestUrl.Contains(input.RequestUrl.Trim()))
@ -58,7 +59,6 @@ public class SysLogHttpService : IDynamicApiController, ITransient
{
return await _sysLogHttpRep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.HttpClientName.Contains(input.Keyword) || u.HttpApiDesc.Contains(input.Keyword) || u.RequestUrl.Contains(input.Keyword) || u.RequestBody.Contains(input.Keyword) || u.ResponseBody.Contains(input.Keyword) || u.Exception.Contains(input.Keyword))
.WhereIF(!string.IsNullOrWhiteSpace(input.HttpClientName), u => u.HttpClientName.Contains(input.HttpClientName.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.HttpApiDesc), u => u.HttpApiDesc.Contains(input.HttpApiDesc.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.RequestUrl?.Trim()), u => u.RequestUrl.Contains(input.RequestUrl.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.RequestBody?.Trim()), u => u.RequestBody.Contains(input.RequestBody.Trim()))
@ -67,6 +67,7 @@ public class SysLogHttpService : IDynamicApiController, ITransient
.WhereIF(!string.IsNullOrWhiteSpace(input.HttpMethod?.Trim()), u => u.HttpMethod == input.HttpMethod)
.WhereIF(input.IsSuccessStatusCode != null, u => u.IsSuccessStatusCode == input.IsSuccessStatusCode)
.WhereIF(input.StatusCode != null, u => u.StatusCode == (HttpStatusCode)input.StatusCode)
.WhereIF(input.HttpClientName != null, u => u.HttpClientName == input.HttpClientName.Trim())
.WhereIF(input.CreateTimeRange?.Length == 2, u => u.CreateTime >= input.CreateTimeRange[0] && u.CreateTime <= input.CreateTimeRange[1])
.ToListAsync();
}
@ -113,6 +114,16 @@ public class SysLogHttpService : IDynamicApiController, ITransient
return list;
}
/// <summary>
/// 获取客户端名称集 🔖
/// </summary>
/// <returns></returns>
[DisplayName("获取客户端名称集")]
public async Task<List<string>> GetHttpClientName()
{
return await _sysLogHttpRep.AsQueryable().Select(u => u.HttpClientName).Distinct().ToListAsync();
}
/// <summary>
/// 导出请求日志记录 🔖
/// </summary>

View File

@ -43,8 +43,10 @@ public class SysTenantService : IDynamicApiController, ITransient
SysRoleMenuService sysRoleMenuService,
SysConfigService sysConfigService,
SysCacheService sysCacheService,
IEventPublisher eventPublisher)
IEventPublisher eventPublisher,
UserManager userManager)
{
_userManager = userManager;
_sysTenantRep = sysTenantRep;
_sysOrgRep = sysOrgRep;
_sysRoleRep = sysRoleRep;

View File

@ -0,0 +1,47 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System;
using System.Linq;
using System.Reflection;
using Furion;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace Admin.NET.Web.Core;
/// <summary>
/// 应用程序启动组件
/// </summary>
public class ApplicationComponent : IApplicationComponent
{
/// <summary>
/// 构建 WebApplication 对象过程中装载中间件
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <param name="componentContext"></param>
public void Load(IApplicationBuilder app, IWebHostEnvironment env, ComponentContext componentContext)
{
// 扫描所有继承 AppStartup 的类(排序执行顺序)
var startups = App.EffectiveTypes
.Where(u => typeof(AppStartup).IsAssignableFrom(u) && u.IsClass && !u.IsAbstract && !u.IsGenericType && u.GetMethod("LoadAppComponent") != null)
.OrderByDescending(u => !u.IsDefined(typeof(AppStartupAttribute), true) ? 0 : u.GetCustomAttribute<AppStartupAttribute>(true).Order);
if (startups == null || !startups.Any())
return;
try
{
foreach (var type in startups)
{
var startup = Activator.CreateInstance(type) as AppStartup;
var initDataMethod = type.GetMethod("LoadAppComponent");
initDataMethod?.Invoke(startup, [app, env, componentContext]);
}
}
catch { }
}
}

View File

@ -0,0 +1,44 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Admin.NET.Web.Core;
/// <summary>
/// Web组件
/// </summary>
public class WebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
// 设置日志过滤
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return !new[] { "Microsoft.Hosting", "Microsoft.AspNetCore" }.Any(u => category.StartsWith(u)) && logLevel >= LogLevel.Information;
});
// 配置接口超时时间和请求大小Kestrel方式
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30);
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(30);
options.Limits.MaxRequestBodySize = 1073741824; // 限制大小1GB默认28.6MB
});
// 配置 Formoptionsmultipart/form-data请求大小
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 1073741824; // 限制大小1GB默认128MB
});
}
}

View File

@ -4,63 +4,6 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Furion;
using Microsoft.AspNetCore.Http.Features;
using System.Reflection;
using Admin.NET.Web.Core;
Serve.Run(RunOptions.Default.AddWebComponent<WebComponent>().UseComponent<ApplicationComponent>());
public class WebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
// 设置日志过滤
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return !new[] { "Microsoft.Hosting", "Microsoft.AspNetCore" }.Any(u => category.StartsWith(u)) && logLevel >= LogLevel.Information;
});
// 配置接口超时时间和请求大小Kestrel方式
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30);
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(30);
options.Limits.MaxRequestBodySize = 1073741824; // 限制大小1GB默认28.6MB
});
// 配置 Formoptionsmultipart/form-data请求大小
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 1073741824; // 限制大小1GB默认128MB
});
}
}
public class ApplicationComponent : IApplicationComponent
{
/// <summary>
/// 构建 WebApplication 对象过程中装载中间件
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <param name="componentContext"></param>
public void Load(IApplicationBuilder app, IWebHostEnvironment env, ComponentContext componentContext)
{
// 扫描所有继承 AppStartup 的类(排序执行顺序)
var startups = App.EffectiveTypes
.Where(u => typeof(AppStartup).IsAssignableFrom(u) && u.IsClass && !u.IsAbstract && !u.IsGenericType && u.GetMethod("LoadAppComponent") != null)
.OrderByDescending(u => !u.IsDefined(typeof(AppStartupAttribute), true) ? 0 : u.GetCustomAttribute<AppStartupAttribute>(true).Order);
if (startups == null || !startups.Any())
return;
try
{
foreach (var type in startups)
{
var startup = Activator.CreateInstance(type) as AppStartup;
var initDataMethod = type.GetMethod("LoadAppComponent");
initDataMethod?.Invoke(startup, [app, env, componentContext]);
}
}
catch { }
}
}
Serve.Run(RunOptions.Default.AddWebComponent<WebComponent>().UseComponent<ApplicationComponent>());

View File

@ -59,7 +59,7 @@ public class BaseIdWorkWxOutput : BaseWorkWxOutput
/// 获取接口凭证输入参数
/// </summary>
/// https://developer.work.weixin.qq.com/document/path/91039
[HttpRemoteApi(Action = "gettoken", Desc = "获取接口凭证", HttpMethod = HttpMethodEnum.Get, IgnoreLog = true)]
[HttpRemoteApi(Action = "gettoken", Desc = "获取接口凭证", HttpMethod = HttpMethodEnum.Get, IgnoreLog = false)]
public class TokenWorkWxInput
{
/// <summary>

View File

@ -21,13 +21,13 @@ namespace Admin.NET.Plugin.WorkWeixin;
public class CreateDeptWorkWxInput : AuthWorkWxInput
{
/// <summary>
/// 部门名称。同一个层级的部门名称不能重复。长度限制为1~64个UTF-8字符字符不能包括\:*?"<>
/// 部门名称。同一个层级的部门名称不能重复。长度限制为1~64个UTF-8字符字符不能包括\:*?"&lt;&gt;|
/// </summary>
/// <remarks>是否必填:是</remarks>
[CustomJsonProperty("name")]
[Required(ErrorMessage = "部门名称不能为空")]
[StringLength(64, MinimumLength = 1, ErrorMessage = "部门名称长度必须在1-64个字符之间")]
[RegularExpression(@"^[^\\:*?""<>]+$", ErrorMessage = "\\:*?\"<>字符")]
[RegularExpression(@"^[^\\:*?""<>|]+$", ErrorMessage = "\\:*?\"<>|字符")]
public string Name { get; set; }
/// <summary>
@ -36,7 +36,7 @@ public class CreateDeptWorkWxInput : AuthWorkWxInput
/// <remarks>是否必填:否</remarks>
[CustomJsonProperty("name_en")]
[StringLength(64, MinimumLength = 1, ErrorMessage = "英文名称长度必须在1-64个字符之间")]
[RegularExpression(@"^[^\\:*?""<>]*$", ErrorMessage = "\\:*?\"<>字符")]
[RegularExpression(@"^[^\\:*?""<>|]*$", ErrorMessage = "\\:*?\"<>|字符")]
public string NameEn { get; set; }
/// <summary>
@ -89,12 +89,12 @@ public class UpdateDeptWorkWxInput : AuthWorkWxInput
public long Id { get; set; }
/// <summary>
/// 部门名称。长度限制为1~64个UTF-8字符字符不能包括\:*?"<>
/// 部门名称。长度限制为1~64个UTF-8字符字符不能包括\:*?"&lt;&gt;|
/// </summary>
/// <remarks>是否必填:否</remarks>
[CustomJsonProperty("name")]
[StringLength(64, MinimumLength = 1, ErrorMessage = "部门名称长度必须在1-64个字符之间")]
[RegularExpression(@"^[^\\:*?""<>]+$", ErrorMessage = "\\:*?\"<>字符")]
[RegularExpression(@"^[^\\:*?""<>|]+$", ErrorMessage = "\\:*?\"<>|字符")]
public string Name { get; set; }
/// <summary>
@ -103,7 +103,7 @@ public class UpdateDeptWorkWxInput : AuthWorkWxInput
/// <remarks>是否必填:否</remarks>
[CustomJsonProperty("name_en")]
[StringLength(64, MinimumLength = 1, ErrorMessage = "英文名称长度必须在1-64个字符之间")]
[RegularExpression(@"^[^\\:*?""<>]*$", ErrorMessage = "\\:*?\"<>字符")]
[RegularExpression(@"^[^\\:*?""<>|]*$", ErrorMessage = "\\:*?\"<>|字符")]
public string NameEn { get; set; }
/// <summary>

View File

@ -36,6 +36,11 @@ public class WorkWxBaseService(
CorpId = await sysConfigService.GetConfigValueByCode(WorkWeixinConst.WorkWeixinCorpId),
CorpSecret = await sysConfigService.GetConfigValueByCode(WorkWeixinConst.WorkWeixinCorpSecret)
});
if (string.IsNullOrWhiteSpace(result.AccessToken))
{
Log.Error("[企业微信] 获取接口凭证失败");
return null;
}
sysCacheService.Set(WorkWeixinConst.KeyWorkWeixinToken, result.AccessToken, TimeSpan.FromSeconds(result.ExpiresIn));
return result.AccessToken;
}
@ -58,7 +63,14 @@ public class WorkWxBaseService(
var url = opt.BaseAddress + $"/cgi-bin/{attr.Action}?";
if (input is AuthWorkWxInput)
{
// 重试3次
var retryMax = 3;
var token = sysCacheService.Get<string>(WorkWeixinConst.KeyWorkWeixinToken) ?? await GetTokenAsync();
while (retryMax-- > 0 && string.IsNullOrWhiteSpace(token))
{
token = await GetTokenAsync();
await Task.Delay(1500);
}
url += "access_token=" + token;
}
@ -73,13 +85,13 @@ public class WorkWxBaseService(
HttpMethodEnum.Post => await httpRemoteService.PostAsync(url,
builder => builder.SetRemoteApiAttr(opt.HttpName, attr)
.SetContent(new StringContent(JSON.Serialize(input, CustomJsonPropertyConverter.Options), Encoding.UTF8, "application/json"))),
_ => throw Oops.Oh($"[企业微信] 不支持的请求方式{attr.HttpMethod.ToString()}({typeof(T).FullName})"),
_ => throw Oops.Oh($"[企业微信] 不支持的请求方式{attr.HttpMethod.ToString()}({typeof(T).FullName})"),
};
}
catch (Exception ex)
{
Log.Error(ex.Message);
throw Oops.Oh("[企业微信] 服务不可用,请检查网路是否正常" + ex.Message);
throw Oops.Oh("[企业微信] 服务不可用,请检查网路是否正常" + ex.Message);
}
return await HandleHttpResponseAsync<R>(response);
}
@ -101,7 +113,7 @@ public class WorkWxBaseService(
{
var resp = JSON.Deserialize<R>(responseContent, CustomJsonPropertyConverter.Options);
if (resp?.ErrCode == 0) return resp;
throw Oops.Oh("[企业微信] " + resp?.ErrMsg);
throw Oops.Oh("[企业微信] 请求失败:" + resp?.ErrMsg);
}
catch (Exception ex)
{

View File

@ -373,7 +373,7 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
},
/**
*
* @summary 🔖
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -521,7 +521,7 @@ export const SysAuthApiFp = function(configuration?: Configuration) {
},
/**
*
* @summary 🔖
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -611,7 +611,7 @@ export const SysAuthApiFactory = function (configuration?: Configuration, basePa
},
/**
*
* @summary 🔖
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -705,7 +705,7 @@ export class SysAuthApi extends BaseAPI {
}
/**
*
* @summary 🔖
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysAuthApi

View File

@ -18,6 +18,7 @@ import { Configuration } from '../configuration';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
import { AdminNETResultListStatLogOutput } from '../models';
import { AdminNETResultListString } from '../models';
import { AdminNETResultListSysLogHttp } from '../models';
import { AdminNETResultSqlSugarPagedListPageLogHttpOutput } from '../models';
import { AdminNETResultSysLogHttp } from '../models';
@ -133,10 +134,56 @@ export const SysLogHttpApiAxiosParamCreator = function (configuration?: Configur
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysLogHttpHttpClientNameGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysLogHttp/httpClientName`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {string} [searchKey]
* @param {string} [actionName]
* @param {string} [httpClientName]
* @param {string} [httpApiDesc]
* @param {string} [httpMethod]
* @param {YesNoEnum} [isSuccessStatusCode]
* @param {string} [requestUrl]
@ -162,7 +209,7 @@ export const SysLogHttpApiAxiosParamCreator = function (configuration?: Configur
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysLogHttpListGet: async (searchKey?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
apiSysLogHttpListGet: async (searchKey?: string, actionName?: string, httpClientName?: string, httpApiDesc?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysLogHttp/list`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@ -187,6 +234,18 @@ export const SysLogHttpApiAxiosParamCreator = function (configuration?: Configur
localVarQueryParameter['SearchKey'] = searchKey;
}
if (actionName !== undefined) {
localVarQueryParameter['ActionName'] = actionName;
}
if (httpClientName !== undefined) {
localVarQueryParameter['HttpClientName'] = httpClientName;
}
if (httpApiDesc !== undefined) {
localVarQueryParameter['HttpApiDesc'] = httpApiDesc;
}
if (httpMethod !== undefined) {
localVarQueryParameter['HttpMethod'] = httpMethod;
}
@ -421,10 +480,26 @@ export const SysLogHttpApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysLogHttpHttpClientNameGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListString>>> {
const localVarAxiosArgs = await SysLogHttpApiAxiosParamCreator(configuration).apiSysLogHttpHttpClientNameGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {string} [searchKey]
* @param {string} [actionName]
* @param {string} [httpClientName]
* @param {string} [httpApiDesc]
* @param {string} [httpMethod]
* @param {YesNoEnum} [isSuccessStatusCode]
* @param {string} [requestUrl]
@ -450,8 +525,8 @@ export const SysLogHttpApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysLogHttpListGet(searchKey?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysLogHttp>>> {
const localVarAxiosArgs = await SysLogHttpApiAxiosParamCreator(configuration).apiSysLogHttpListGet(searchKey, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options);
async apiSysLogHttpListGet(searchKey?: string, actionName?: string, httpClientName?: string, httpApiDesc?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysLogHttp>>> {
const localVarAxiosArgs = await SysLogHttpApiAxiosParamCreator(configuration).apiSysLogHttpListGet(searchKey, actionName, httpClientName, httpApiDesc, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
@ -513,10 +588,22 @@ export const SysLogHttpApiFactory = function (configuration?: Configuration, bas
async apiSysLogHttpExportPost(body?: ExportLogHttpInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysLogHttpApiFp(configuration).apiSysLogHttpExportPost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysLogHttpHttpClientNameGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListString>> {
return SysLogHttpApiFp(configuration).apiSysLogHttpHttpClientNameGet(options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {string} [searchKey]
* @param {string} [actionName]
* @param {string} [httpClientName]
* @param {string} [httpApiDesc]
* @param {string} [httpMethod]
* @param {YesNoEnum} [isSuccessStatusCode]
* @param {string} [requestUrl]
@ -542,8 +629,8 @@ export const SysLogHttpApiFactory = function (configuration?: Configuration, bas
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysLogHttpListGet(searchKey?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysLogHttp>> {
return SysLogHttpApiFp(configuration).apiSysLogHttpListGet(searchKey, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options).then((request) => request(axios, basePath));
async apiSysLogHttpListGet(searchKey?: string, actionName?: string, httpClientName?: string, httpApiDesc?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysLogHttp>> {
return SysLogHttpApiFp(configuration).apiSysLogHttpListGet(searchKey, actionName, httpClientName, httpApiDesc, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options).then((request) => request(axios, basePath));
},
/**
*
@ -596,10 +683,23 @@ export class SysLogHttpApi extends BaseAPI {
public async apiSysLogHttpExportPost(body?: ExportLogHttpInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysLogHttpApiFp(this.configuration).apiSysLogHttpExportPost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysLogHttpApi
*/
public async apiSysLogHttpHttpClientNameGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListString>> {
return SysLogHttpApiFp(this.configuration).apiSysLogHttpHttpClientNameGet(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {string} [searchKey]
* @param {string} [actionName]
* @param {string} [httpClientName]
* @param {string} [httpApiDesc]
* @param {string} [httpMethod]
* @param {YesNoEnum} [isSuccessStatusCode]
* @param {string} [requestUrl]
@ -626,8 +726,8 @@ export class SysLogHttpApi extends BaseAPI {
* @throws {RequiredError}
* @memberof SysLogHttpApi
*/
public async apiSysLogHttpListGet(searchKey?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysLogHttp>> {
return SysLogHttpApiFp(this.configuration).apiSysLogHttpListGet(searchKey, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options).then((request) => request(this.axios, this.basePath));
public async apiSysLogHttpListGet(searchKey?: string, actionName?: string, httpClientName?: string, httpApiDesc?: string, httpMethod?: string, isSuccessStatusCode?: YesNoEnum, requestUrl?: string, requestBody?: string, statusCode?: number, responseBody?: string, exception?: string, createTime?: Date, createTimeRange?: Array<Date>, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, searchFields?: Array<string>, searchKeyword?: string, keyword?: string, filterLogic?: FilterLogicEnum, filterFilters?: Array<Filter>, filterField?: string, filterOperator?: FilterOperatorEnum, filterValue?: any, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysLogHttp>> {
return SysLogHttpApiFp(this.configuration).apiSysLogHttpListGet(searchKey, actionName, httpClientName, httpApiDesc, httpMethod, isSuccessStatusCode, requestUrl, requestBody, statusCode, responseBody, exception, createTime, createTimeRange, page, pageSize, field, order, descStr, searchFields, searchKeyword, keyword, filterLogic, filterFilters, filterField, filterOperator, filterValue, options).then((request) => request(this.axios, this.basePath));
}
/**
*

View File

@ -13,6 +13,7 @@
*/
import { StatusEnum } from './status-enum';
import { YesNoEnum } from './yes-no-enum';
/**
*
*
@ -170,4 +171,10 @@ export interface AddDictDataInput {
* @memberof AddDictDataInput
*/
status?: StatusEnum;
/**
* @type {YesNoEnum}
* @memberof AddDictDataInput
*/
isEnum?: YesNoEnum;
}

View File

@ -131,6 +131,12 @@ export interface AddDictTypeInput {
*/
isTenant?: YesNoEnum;
/**
* @type {YesNoEnum}
* @memberof AddDictTypeInput
*/
isEnum?: YesNoEnum;
/**
*
*

View File

@ -36,6 +36,14 @@ export interface ConstOutput {
*/
code?: any | null;
/**
*
*
* @type {string}
* @memberof ConstOutput
*/
desc?: string | null;
/**
*
*

View File

@ -91,6 +91,30 @@ export interface ExportLogHttpInput {
*/
searchKey?: string | null;
/**
*
*
* @type {string}
* @memberof ExportLogHttpInput
*/
actionName?: string | null;
/**
*
*
* @type {string}
* @memberof ExportLogHttpInput
*/
httpClientName?: string | null;
/**
*
*
* @type {string}
* @memberof ExportLogHttpInput
*/
httpApiDesc?: string | null;
/**
*
*

View File

@ -91,6 +91,30 @@ export interface PageLogHttpInput {
*/
searchKey?: string | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpInput
*/
actionName?: string | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpInput
*/
httpClientName?: string | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpInput
*/
httpApiDesc?: string | null;
/**
*
*

View File

@ -29,6 +29,30 @@ export interface PageLogHttpOutput {
*/
id?: number | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpOutput
*/
actionName?: string | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpOutput
*/
httpClientName?: string | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpOutput
*/
httpApiDesc?: string | null;
/**
*
*
@ -130,4 +154,12 @@ export interface PageLogHttpOutput {
* @memberof PageLogHttpOutput
*/
createTime?: Date | null;
/**
*
*
* @type {string}
* @memberof PageLogHttpOutput
*/
createUserName?: string | null;
}

View File

@ -13,6 +13,7 @@
*/
import { StatusEnum } from './status-enum';
import { YesNoEnum } from './yes-no-enum';
/**
*
*
@ -170,4 +171,10 @@ export interface SysDictData {
* @memberof SysDictData
*/
status?: StatusEnum;
/**
* @type {YesNoEnum}
* @memberof SysDictData
*/
isEnum?: YesNoEnum;
}

View File

@ -137,6 +137,12 @@ export interface SysDictType {
*/
isTenant?: YesNoEnum;
/**
* @type {YesNoEnum}
* @memberof SysDictType
*/
isEnum?: YesNoEnum;
/**
*
*

View File

@ -28,62 +28,6 @@ export interface SysLogDiff {
*/
id?: number;
/**
*
*
* @type {Date}
* @memberof SysLogDiff
*/
createTime?: Date;
/**
*
*
* @type {Date}
* @memberof SysLogDiff
*/
updateTime?: Date | null;
/**
* Id
*
* @type {number}
* @memberof SysLogDiff
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogDiff
*/
createUserName?: string | null;
/**
* Id
*
* @type {number}
* @memberof SysLogDiff
*/
updateUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogDiff
*/
updateUserName?: string | null;
/**
*
*
* @type {boolean}
* @memberof SysLogDiff
*/
isDelete?: boolean;
/**
* Id
*
@ -147,4 +91,28 @@ export interface SysLogDiff {
* @memberof SysLogDiff
*/
elapsed?: number | null;
/**
*
*
* @type {Date}
* @memberof SysLogDiff
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogDiff
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogDiff
*/
createUserName?: string | null;
}

View File

@ -29,62 +29,6 @@ export interface SysLogEx {
*/
id?: number;
/**
*
*
* @type {Date}
* @memberof SysLogEx
*/
createTime?: Date;
/**
*
*
* @type {Date}
* @memberof SysLogEx
*/
updateTime?: Date | null;
/**
* Id
*
* @type {number}
* @memberof SysLogEx
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogEx
*/
createUserName?: string | null;
/**
* Id
*
* @type {number}
* @memberof SysLogEx
*/
updateUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogEx
*/
updateUserName?: string | null;
/**
*
*
* @type {boolean}
* @memberof SysLogEx
*/
isDelete?: boolean;
/**
* Id
*
@ -211,6 +155,30 @@ export interface SysLogEx {
*/
realName?: string | null;
/**
*
*
* @type {Date}
* @memberof SysLogEx
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogEx
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogEx
*/
createUserName?: string | null;
/**
*
*

View File

@ -30,6 +30,30 @@ export interface SysLogHttp {
*/
id?: number;
/**
* Id
*
* @type {number}
* @memberof SysLogHttp
*/
tenantId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogHttp
*/
httpClientName?: string | null;
/**
*
*
* @type {string}
* @memberof SysLogHttp
*/
httpApiDesc?: string | null;
/**
*
*
@ -44,6 +68,14 @@ export interface SysLogHttp {
*/
isSuccessStatusCode?: YesNoEnum;
/**
*
*
* @type {string}
* @memberof SysLogHttp
*/
actionName?: string | null;
/**
*
*
@ -129,4 +161,20 @@ export interface SysLogHttp {
* @memberof SysLogHttp
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogHttp
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogHttp
*/
createUserName?: string | null;
}

View File

@ -28,62 +28,6 @@ export interface SysLogMsg {
*/
id?: number;
/**
*
*
* @type {Date}
* @memberof SysLogMsg
*/
createTime?: Date;
/**
*
*
* @type {Date}
* @memberof SysLogMsg
*/
updateTime?: Date | null;
/**
* Id
*
* @type {number}
* @memberof SysLogMsg
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogMsg
*/
createUserName?: string | null;
/**
* Id
*
* @type {number}
* @memberof SysLogMsg
*/
updateUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogMsg
*/
updateUserName?: string | null;
/**
*
*
* @type {boolean}
* @memberof SysLogMsg
*/
isDelete?: boolean;
/**
* Id
*
@ -227,4 +171,28 @@ export interface SysLogMsg {
* @memberof SysLogMsg
*/
sendDevice?: string | null;
/**
*
*
* @type {Date}
* @memberof SysLogMsg
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogMsg
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogMsg
*/
createUserName?: string | null;
}

View File

@ -29,62 +29,6 @@ export interface SysLogOp {
*/
id?: number;
/**
*
*
* @type {Date}
* @memberof SysLogOp
*/
createTime?: Date;
/**
*
*
* @type {Date}
* @memberof SysLogOp
*/
updateTime?: Date | null;
/**
* Id
*
* @type {number}
* @memberof SysLogOp
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogOp
*/
createUserName?: string | null;
/**
* Id
*
* @type {number}
* @memberof SysLogOp
*/
updateUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogOp
*/
updateUserName?: string | null;
/**
*
*
* @type {boolean}
* @memberof SysLogOp
*/
isDelete?: boolean;
/**
* Id
*
@ -211,6 +155,30 @@ export interface SysLogOp {
*/
realName?: string | null;
/**
*
*
* @type {Date}
* @memberof SysLogOp
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogOp
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogOp
*/
createUserName?: string | null;
/**
*
*

View File

@ -29,62 +29,6 @@ export interface SysLogVis {
*/
id?: number;
/**
*
*
* @type {Date}
* @memberof SysLogVis
*/
createTime?: Date;
/**
*
*
* @type {Date}
* @memberof SysLogVis
*/
updateTime?: Date | null;
/**
* Id
*
* @type {number}
* @memberof SysLogVis
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogVis
*/
createUserName?: string | null;
/**
* Id
*
* @type {number}
* @memberof SysLogVis
*/
updateUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogVis
*/
updateUserName?: string | null;
/**
*
*
* @type {boolean}
* @memberof SysLogVis
*/
isDelete?: boolean;
/**
* Id
*
@ -210,4 +154,28 @@ export interface SysLogVis {
* @memberof SysLogVis
*/
realName?: string | null;
/**
*
*
* @type {Date}
* @memberof SysLogVis
*/
createTime?: Date;
/**
* Id
*
* @type {number}
* @memberof SysLogVis
*/
createUserId?: number | null;
/**
*
*
* @type {string}
* @memberof SysLogVis
*/
createUserName?: string | null;
}

View File

@ -13,6 +13,7 @@
*/
import { StatusEnum } from './status-enum';
import { YesNoEnum } from './yes-no-enum';
/**
*
*
@ -170,4 +171,10 @@ export interface UpdateDictDataInput {
* @memberof UpdateDictDataInput
*/
status?: StatusEnum;
/**
* @type {YesNoEnum}
* @memberof UpdateDictDataInput
*/
isEnum?: YesNoEnum;
}

View File

@ -131,6 +131,12 @@ export interface UpdateDictTypeInput {
*/
isTenant?: YesNoEnum;
/**
* @type {YesNoEnum}
* @memberof UpdateDictTypeInput
*/
isEnum?: YesNoEnum;
/**
*
*

View File

@ -53,17 +53,18 @@
<script lang="ts" setup>
import {ref, reactive, computed} from 'vue';
import { StringToObj } from '/@/utils/json-utils';
import { SysLogHttp } from '/@/api-services/system/models';
import VueJsonPretty from 'vue-json-pretty';
import { LogHttp } from '/@/api-services/system';
const state = reactive({
visible: false,
selectedTabName: '0',
});
const data = ref<LogHttp>({});
const data = ref<SysLogHttp>({});
const openDialog = (row: any) => {
state.visible = true;
data.value ??= {};
state.selectedTabName = '0';
Object.assign(data.value, row);
data.value.requestUrl = StringToObj(row.requestUrl);
data.value.requestHeaders = StringToObj(row.requestHeaders);
data.value.requestBody = StringToObj(row.requestBody);
@ -73,13 +74,6 @@ const openDialog = (row: any) => {
};
const queryObject = computed(() => Object.fromEntries(new URLSearchParams(new URL(data.value?.requestUrl ?? '').search)) ?? {});
const tryJsonParse = (str: string) => {
try {
return JSON.parse(str);
} catch (e) {
return str;
}
};
defineExpose({
openDialog,
});

View File

@ -8,7 +8,14 @@
<el-row :gutter="10">
<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="客户端" prop="httpClientName">
<el-input v-model="state.queryParams.httpClientName" placeholder="请输入客户端" clearable @keyup.enter.native="handleQuery(true)" />
<el-select v-model="state.queryParams.httpClientName" placeholder="请选择客户端" clearable @keyup.enter.native="handleQuery(true)">
<el-option v-for="item in state.clientNameList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="模块名" prop="actionName">
<el-input v-model="state.queryParams.actionName" placeholder="请输入模块名" clearable @keyup.enter.native="handleQuery(true)" />
</el-form-item>
</el-col>
<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
@ -87,8 +94,7 @@
</template>
<template #row_requestUrl="{ row, $index }">
<el-button v-if="row.requestUrl" class="ml5" icon="ele-CopyDocument" text type="primary" @click="(event: any) => handleCopyUrl(event, row.requestUrl)" />
{{ row.requestUrl.substring(0, row.requestUrl.length >= 50 ? 50 : row.requestUrl.length) }}
{{ row.requestUrl.length >= 50 ? '...' : ''}}
{{ row.requestUrl }}
</template>
<template #row_requestBody="{ row, $index }">
{{ row.requestBody }}
@ -142,6 +148,7 @@ const state = reactive({
},
visible: false,
logMaxValue: 1,
clientNameList: [] as string[],
});
//
const localPageParamKey = 'localPageParam:sysLogHttp';
@ -155,6 +162,7 @@ const options = useVxeTable<PageLogHttpOutput>(
{ field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' },
{ field: 'createTime', title: '创建时间', minWidth: 150, showOverflow: 'tooltip' },
{ field: 'httpClientName', title: '客户端', minWidth: 110, showOverflow: 'tooltip' },
{ field: 'actionName', title: '模块名', minWidth: 110, showOverflow: 'tooltip' },
{ field: 'httpMethod', title: '请求方式', minWidth: 60, showOverflow: 'tooltip' },
{ field: 'isSuccessStatusCode', title: '是否成功', minWidth: 60, showOverflow: 'tooltip', slots: { default: 'row_isSuccessStatusCode' } },
{ field: 'httpApiDesc', title: '接口描述', minWidth: 150, showOverflow: 'tooltip' },
@ -168,6 +176,7 @@ const options = useVxeTable<PageLogHttpOutput>(
{ field: 'startTime', title: '开始时间', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_startTime' } },
{ field: 'endTime', title: '结束时间', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_endTime' } },
{ field: 'elapsed', title: '耗时(毫秒)', minWidth: 90, showOverflow: 'tooltip' },
{ field: 'createUserName', title: '创建用户', minWidth: 90, showOverflow: 'tooltip' },
],
},
// vxeGrid()vxe-table
@ -187,6 +196,7 @@ const options = useVxeTable<PageLogHttpOutput>(
//
onMounted(async () => {
state.clientNameList = await getAPI(SysLogHttpApi).apiSysLogHttpHttpClientNameGet().then(res => res.data.result ?? []);
state.localPageParam = Local.get(localPageParamKey) || state.localPageParam;
});