瀏覽代碼

🤓1、恢复异常日志单独处理 2、升级所有依赖及其他优化

zuohuaijun 3 年之前
父節點
當前提交
fea0b7362f

+ 5 - 5
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -19,11 +19,11 @@
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.3.0" />
     <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
     <PackageReference Include="DotNetCore.Compile.Environment" Version="3.2.0" />
-    <PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.1.0" />
+    <PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.2.2.1" />
     <PackageReference Include="FluentEmail.Smtp" Version="3.0.2" />
-    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.4" />
-    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.4" />
-    <PackageReference Include="Furion.Pure" Version="4.8.8.4" />
+    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.6" />
+    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.6" />
+    <PackageReference Include="Furion.Pure" Version="4.8.8.6" />
     <PackageReference Include="IPTools.China" Version="1.6.0" />
     <PackageReference Include="Lazy.Captcha.Core" Version="2.0.3" />
     <PackageReference Include="Magicodes.IE.Excel" Version="2.7.4.4" />
@@ -34,7 +34,7 @@
     <PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.9" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="2.26.1" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="2.18.0" />
-    <PackageReference Include="SqlSugarCore" Version="5.1.4.67" />
+    <PackageReference Include="SqlSugarCore" Version="5.1.4.69" />
     <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.2" />
     <PackageReference Include="UAParser" Version="3.1.47" />
     <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />

+ 65 - 0
Admin.NET/Admin.NET.Core/Entity/SysLogEx.cs

@@ -0,0 +1,65 @@
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 系统异常日志表
+/// </summary>
+[SugarTable(null, "系统异常日志表")]
+[SystemTable]
+public class SysLogEx : SysLogVis
+{
+    /// <summary>
+    /// 请求方式
+    /// </summary>
+    [SugarColumn(ColumnDescription = "请求方式", Length = 32)]
+    [MaxLength(32)]
+    public string? HttpMethod { get; set; }
+
+    /// <summary>
+    /// 请求地址
+    /// </summary>
+    [SugarColumn(ColumnDescription = "请求地址", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string? RequestUrl { get; set; }
+
+    /// <summary>
+    /// 请求参数
+    /// </summary>
+    [SugarColumn(ColumnDescription = "请求参数", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string? RequestParam { get; set; }
+
+    /// <summary>
+    /// 返回结果
+    /// </summary>
+    [SugarColumn(ColumnDescription = "返回结果", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string? ReturnResult { get; set; }
+
+    /// <summary>
+    /// 事件Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "事件Id")]
+    public int? EventId { get; set; }
+
+    /// <summary>
+    /// 线程Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "线程Id")]
+    public int? ThreadId { get; set; }
+
+    /// <summary>
+    /// 请求跟踪Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "请求跟踪Id", Length = 128)]
+    [MaxLength(128)]
+    public string? TraceId { get; set; }
+
+    /// <summary>
+    /// 异常信息
+    /// </summary>
+    [SugarColumn(ColumnDescription = "异常信息", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string? Exception { get; set; }
+
+    /// <summary>
+    /// 日志消息Json
+    /// </summary>
+    [SugarColumn(ColumnDescription = "日志消息Json", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string? Message { get; set; }
+}

+ 6 - 0
Admin.NET/Admin.NET.Core/Entity/SysLogVis.cs

@@ -87,6 +87,12 @@ public class SysLogVis : EntityTenant
     [SugarColumn(ColumnDescription = "日志时间")]
     public DateTime? LogDateTime { get; set; }
 
+    /// <summary>
+    /// 日志级别
+    /// </summary>
+    [SugarColumn(ColumnDescription = "日志级别")]
+    public LogLevel LogLevel { get; set; }
+
     /// <summary>
     /// 账号
     /// </summary>

+ 1 - 0
Admin.NET/Admin.NET.Core/GlobalUsings.cs

@@ -21,6 +21,7 @@ global using Microsoft.AspNetCore.Mvc;
 global using Microsoft.AspNetCore.Mvc.Filters;
 global using Microsoft.Extensions.Configuration;
 global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
 global using Microsoft.Extensions.Options;
 global using NewLife.Caching;
 global using Newtonsoft.Json;

+ 82 - 46
Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs

@@ -1,6 +1,4 @@
 using IPTools.Core;
-using Nest;
-using UAParser;
 
 namespace Admin.NET.Core;
 
@@ -11,13 +9,17 @@ public class DatabaseLoggingWriter : IDatabaseLoggingWriter
 {
     private readonly SqlSugarRepository<SysLogVis> _sysLogVisRep; // 访问日志
     private readonly SqlSugarRepository<SysLogOp> _sysLogOpRep;   // 操作日志
+    private readonly SqlSugarRepository<SysLogEx> _sysLogExRep;   // 异常日志
     private readonly SysConfigService _sysConfigService; // 参数配置服务
 
     public DatabaseLoggingWriter(SqlSugarRepository<SysLogVis> sysLogVisRep,
-        SqlSugarRepository<SysLogOp> sysLogOpRep, SysConfigService sysConfigService)
+        SqlSugarRepository<SysLogOp> sysLogOpRep,
+        SqlSugarRepository<SysLogEx> sysLogExRep,
+        SysConfigService sysConfigService)
     {
         _sysLogVisRep = sysLogVisRep;
         _sysLogOpRep = sysLogOpRep;
+        _sysLogExRep = sysLogExRep;
         _sysConfigService = sysConfigService;
     }
 
@@ -53,9 +55,10 @@ public class DatabaseLoggingWriter : IDatabaseLoggingWriter
         var browser = $"{client.UA.Family} {client.UA.Major}.{client.UA.Minor} / {client.Device.Family}";
         var os = $"{client.OS.Family} {client.OS.Major} {client.OS.Minor}";
 
-        if (loggingMonitor.actionName == "userInfo" || loggingMonitor.actionName == "logout")
+        // 记录异常日志并发送邮件
+        if (logMsg.Exception != null || loggingMonitor.exception != null)
         {
-            await _sysLogVisRep.InsertAsync(new SysLogVis
+            await _sysLogExRep.InsertAsync(new SysLogEx
             {
                 ControllerName = loggingMonitor.controllerName,
                 ActionName = loggingMonitor.actionTypeName,
@@ -71,56 +74,89 @@ public class DatabaseLoggingWriter : IDatabaseLoggingWriter
                 LogDateTime = logMsg.LogDateTime,
                 Account = account,
                 RealName = realName,
+                HttpMethod = loggingMonitor.httpMethod,
+                RequestUrl = loggingMonitor.requestUrl,
+                RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
+                ReturnResult = loggingMonitor.returnInformation == null ? null : JSON.Serialize(loggingMonitor.returnInformation),
+                EventId = logMsg.EventId.Id,
+                ThreadId = logMsg.ThreadId,
+                TraceId = logMsg.TraceId,
+                Exception = JSON.Serialize(loggingMonitor.exception),
+                Message = logMsg.Message,
                 CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
-                TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId)
+                TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+                LogLevel = logMsg.LogLevel
             });
-        }
-        else
-        {
-            // 是否启用操作日志
-            var sysOpLogEnabled = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysOpLog);
-            if (sysOpLogEnabled)
-            {
-                await _sysLogOpRep.InsertAsync(new SysLogOp
-                {
-                    ControllerName = loggingMonitor.controllerName,
-                    ActionName = loggingMonitor.actionTypeName,
-                    DisplayTitle = loggingMonitor.displayTitle,
-                    Status = loggingMonitor.returnInformation?.httpStatusCode,
-                    RemoteIp = remoteIPv4,
-                    Location = ipLocation,
-                    Longitude = longitude,
-                    Latitude = latitude,
-                    Browser = browser, // loggingMonitor.userAgent,
-                    Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
-                    Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
-                    LogDateTime = logMsg.LogDateTime,
-                    Account = account,
-                    RealName = realName,
-                    HttpMethod = loggingMonitor.httpMethod,
-                    RequestUrl = loggingMonitor.requestUrl,
-                    RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
-                    ReturnResult = loggingMonitor.returnInformation == null ? null : JSON.Serialize(loggingMonitor.returnInformation),
-                    EventId = logMsg.EventId.Id,
-                    ThreadId = logMsg.ThreadId,
-                    TraceId = logMsg.TraceId,
-                    Exception = loggingMonitor.exception == null ? null : JSON.Serialize(loggingMonitor.exception),
-                    Message = logMsg.Message,
-                    CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
-                    TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId)
-                });
-            }
-        }
 
-        // 若有异常时则发送邮件
-        if (logMsg.Exception != null)
-        {
+            // 将异常日志发送到邮件
             try
             {
                 await App.GetRequiredService<SysMessageService>().SendEmail(JSON.Serialize(loggingMonitor.exception));
             }
             catch { }
+
+            return;
+        }
+
+        // 记录访问日志-登录登出
+        if (loggingMonitor.actionName == "userInfo" || loggingMonitor.actionName == "logout")
+        {
+            await _sysLogVisRep.InsertAsync(new SysLogVis
+            {
+                ControllerName = loggingMonitor.controllerName,
+                ActionName = loggingMonitor.actionTypeName,
+                DisplayTitle = loggingMonitor.displayTitle,
+                Status = loggingMonitor.returnInformation?.httpStatusCode,
+                RemoteIp = remoteIPv4,
+                Location = ipLocation,
+                Longitude = longitude,
+                Latitude = latitude,
+                Browser = browser, // loggingMonitor.userAgent,
+                Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+                Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+                LogDateTime = logMsg.LogDateTime,
+                Account = account,
+                RealName = realName,
+                CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+                TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+                LogLevel = logMsg.LogLevel
+            });
+
+            return;
         }
+
+        // 记录操作日志
+        var enabledSysOpLog = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysOpLog);
+        if (!enabledSysOpLog) return;
+        await _sysLogOpRep.InsertAsync(new SysLogOp
+        {
+            ControllerName = loggingMonitor.controllerName,
+            ActionName = loggingMonitor.actionTypeName,
+            DisplayTitle = loggingMonitor.displayTitle,
+            Status = loggingMonitor.returnInformation?.httpStatusCode,
+            RemoteIp = remoteIPv4,
+            Location = ipLocation,
+            Longitude = longitude,
+            Latitude = latitude,
+            Browser = browser, // loggingMonitor.userAgent,
+            Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+            Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+            LogDateTime = logMsg.LogDateTime,
+            Account = account,
+            RealName = realName,
+            HttpMethod = loggingMonitor.httpMethod,
+            RequestUrl = loggingMonitor.requestUrl,
+            RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
+            ReturnResult = loggingMonitor.returnInformation == null ? null : JSON.Serialize(loggingMonitor.returnInformation),
+            EventId = logMsg.EventId.Id,
+            ThreadId = logMsg.ThreadId,
+            TraceId = logMsg.TraceId,
+            Exception = loggingMonitor.exception == null ? null : JSON.Serialize(loggingMonitor.exception),
+            Message = logMsg.Message,
+            CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+            TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+            LogLevel = logMsg.LogLevel
+        });
     }
 
     /// <summary>

+ 7 - 3
Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs

@@ -137,9 +137,13 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
             new SysMenu{ Id=1310000000522, Pid=1310000000521, Title="查询", Permission="sysOplog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1310000000523, Pid=1310000000521, Title="清空", Permission="sysOplog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1310000000524, Pid=1310000000521, Title="导出", Permission="sysOplog:export", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
-            new SysMenu{ Id=1310000000531, Pid=1310000000501, Title="差异日志", Path="/log/difflog", Name="sysDifflog", Component="/system/log/difflog/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
-            new SysMenu{ Id=1310000000532, Pid=1310000000531, Title="查询", Permission="sysDifflog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
-            new SysMenu{ Id=1310000000533, Pid=1310000000531, Title="清空", Permission="sysDifflog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000531, Pid=1310000000501, Title="异常日志", Path="/log/exlog", Name="sysExlog", Component="/system/log/exlog/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
+            new SysMenu{ Id=1310000000532, Pid=1310000000531, Title="查询", Permission="sysExlog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000533, Pid=1310000000531, Title="清空", Permission="sysExlog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000534, Pid=1310000000531, Title="导出", Permission="sysExlog:export", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000541, Pid=1310000000501, Title="差异日志", Path="/log/difflog", Name="sysDifflog", Component="/system/log/difflog/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
+            new SysMenu{ Id=1310000000542, Pid=1310000000541, Title="查询", Permission="sysDifflog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000543, Pid=1310000000541, Title="清空", Permission="sysDifflog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
 
             new SysMenu{ Id=1310000000601, Pid=0, Title="开发工具", Path="/develop", Name="develop", Component="Layout", Icon="ele-Cpu", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=1300 },
             new SysMenu{ Id=1310000000611, Pid=1310000000601, Title="库表管理", Path="/develop/database", Name="sysDatabase", Component="/system/database/index",Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },

+ 63 - 0
Admin.NET/Admin.NET.Core/Service/Logging/SysLogExService.cs

@@ -0,0 +1,63 @@
+using Magicodes.ExporterAndImporter.Excel;
+
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 系统异常日志服务
+/// </summary>
+[ApiDescriptionSettings(Order = 350)]
+public class SysLogExService : IDynamicApiController, ITransient
+{
+    private readonly SqlSugarRepository<SysLogEx> _sysLogExRep;
+
+    public SysLogExService(SqlSugarRepository<SysLogEx> sysLogExRep)
+    {
+        _sysLogExRep = sysLogExRep;
+    }
+
+    /// <summary>
+    /// 获取异常日志分页列表
+    /// </summary>
+    /// <returns></returns>
+    [SuppressMonitor]
+    [DisplayName("获取异常日志分页列表")]
+    public async Task<SqlSugarPagedList<SysLogEx>> Page(PageLogInput input)
+    {
+        return await _sysLogExRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()),
+                u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime)
+            //.OrderBy(u => u.CreateTime, OrderByType.Desc)
+            .OrderBuilder(input)
+            .ToPagedListAsync(input.Page, input.PageSize);
+    }
+
+    /// <summary>
+    /// 清空异常日志
+    /// </summary>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Clear"), HttpPost]
+    [DisplayName("清空异常日志")]
+    public async Task<bool> Clear()
+    {
+        return await _sysLogExRep.DeleteAsync(u => u.Id > 0);
+    }
+
+    /// <summary>
+    /// 导出异常日志
+    /// </summary>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Export"), NonUnify]
+    [DisplayName("导出异常日志")]
+    public async Task<IActionResult> ExportLogEx(LogInput input)
+    {
+        var logExList = await _sysLogExRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()),
+                    u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime)
+            .OrderBy(u => u.CreateTime, OrderByType.Desc)
+            .Select<ExportLogDto>().ToListAsync();
+
+        IExcelExporter excelExporter = new ExcelExporter();
+        var res = await excelExporter.ExportAsByteArray(logExList);
+        return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "异常日志.xlsx" };
+    }
+}

+ 2 - 2
Admin.NET/Admin.NET.Core/Service/Logging/SysLogOpService.cs

@@ -50,14 +50,14 @@ public class SysLogOpService : IDynamicApiController, ITransient
     [DisplayName("导出操作日志")]
     public async Task<IActionResult> ExportLogOp(LogInput input)
     {
-        var lopOpList = await _sysLogOpRep.AsQueryable()
+        var logOpList = await _sysLogOpRep.AsQueryable()
             .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()),
                     u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime)
             .OrderBy(u => u.CreateTime, OrderByType.Desc)
             .Select<ExportLogDto>().ToListAsync();
 
         IExcelExporter excelExporter = new ExcelExporter();
-        var res = await excelExporter.ExportAsByteArray(lopOpList);
+        var res = await excelExporter.ExportAsByteArray(logOpList);
         return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "操作日志.xlsx" };
     }
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Logging/SysLogVisService.cs

@@ -3,7 +3,7 @@
 /// <summary>
 /// 系统访问日志服务
 /// </summary>
-[ApiDescriptionSettings(Order = 350)]
+[ApiDescriptionSettings(Order = 340)]
 public class SysLogVisService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysLogVis> _sysLogVisRep;

+ 1 - 0
Web/src/api-services/api.ts

@@ -24,6 +24,7 @@ export * from './apis/sys-enum-api';
 export * from './apis/sys-file-api';
 export * from './apis/sys-job-api';
 export * from './apis/sys-log-diff-api';
+export * from './apis/sys-log-ex-api';
 export * from './apis/sys-log-op-api';
 export * from './apis/sys-log-vis-api';
 export * from './apis/sys-menu-api';

+ 277 - 0
Web/src/api-services/apis/sys-log-ex-api.ts

@@ -0,0 +1,277 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import globalAxios, { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios';
+import { Configuration } from '../configuration';
+// Some imports not used depending on template conditions
+// @ts-ignore
+import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
+import { AdminResultBoolean } from '../models';
+import { AdminResultSqlSugarPagedListSysLogEx } from '../models';
+import { LogInput } from '../models';
+import { PageLogInput } from '../models';
+/**
+ * SysLogExApi - axios parameter creator
+ * @export
+ */
+export const SysLogExApiAxiosParamCreator = function (configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 清空异常日志
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysLogExClearPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysLogEx/clear`;
+            // 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: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+
+            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 {LogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysLogExExportPost: async (body?: LogInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysLogEx/export`;
+            // 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: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            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};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 获取异常日志分页列表
+         * @param {PageLogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysLogExPagePost: async (body?: PageLogInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysLogEx/page`;
+            // 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: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            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};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+    }
+};
+
+/**
+ * SysLogExApi - functional programming interface
+ * @export
+ */
+export const SysLogExApiFp = function(configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 清空异常日志
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExClearPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultBoolean>>> {
+            const localVarAxiosArgs = await SysLogExApiAxiosParamCreator(configuration).apiSysLogExClearPost(options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 导出异常日志
+         * @param {LogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExExportPost(body?: LogInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysLogExApiAxiosParamCreator(configuration).apiSysLogExExportPost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 获取异常日志分页列表
+         * @param {PageLogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExPagePost(body?: PageLogInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSqlSugarPagedListSysLogEx>>> {
+            const localVarAxiosArgs = await SysLogExApiAxiosParamCreator(configuration).apiSysLogExPagePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+    }
+};
+
+/**
+ * SysLogExApi - factory interface
+ * @export
+ */
+export const SysLogExApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+    return {
+        /**
+         * 
+         * @summary 清空异常日志
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExClearPost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultBoolean>> {
+            return SysLogExApiFp(configuration).apiSysLogExClearPost(options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 导出异常日志
+         * @param {LogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExExportPost(body?: LogInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysLogExApiFp(configuration).apiSysLogExExportPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取异常日志分页列表
+         * @param {PageLogInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysLogExPagePost(body?: PageLogInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSqlSugarPagedListSysLogEx>> {
+            return SysLogExApiFp(configuration).apiSysLogExPagePost(body, options).then((request) => request(axios, basePath));
+        },
+    };
+};
+
+/**
+ * SysLogExApi - object-oriented interface
+ * @export
+ * @class SysLogExApi
+ * @extends {BaseAPI}
+ */
+export class SysLogExApi extends BaseAPI {
+    /**
+     * 
+     * @summary 清空异常日志
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysLogExApi
+     */
+    public async apiSysLogExClearPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultBoolean>> {
+        return SysLogExApiFp(this.configuration).apiSysLogExClearPost(options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 导出异常日志
+     * @param {LogInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysLogExApi
+     */
+    public async apiSysLogExExportPost(body?: LogInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysLogExApiFp(this.configuration).apiSysLogExExportPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取异常日志分页列表
+     * @param {PageLogInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysLogExApi
+     */
+    public async apiSysLogExPagePost(body?: PageLogInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSqlSugarPagedListSysLogEx>> {
+        return SysLogExApiFp(this.configuration).apiSysLogExPagePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+}

+ 57 - 0
Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-log-ex.ts

@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { SqlSugarPagedListSysLogEx } from './sql-sugar-paged-list-sys-log-ex';
+/**
+ * 全局返回结果
+ * @export
+ * @interface AdminResultSqlSugarPagedListSysLogEx
+ */
+export interface AdminResultSqlSugarPagedListSysLogEx {
+    /**
+     * 状态码
+     * @type {number}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    code?: number;
+    /**
+     * 类型success、warning、error
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    type?: string | null;
+    /**
+     * 错误信息
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    message?: string | null;
+    /**
+     * 
+     * @type {SqlSugarPagedListSysLogEx}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    result?: SqlSugarPagedListSysLogEx;
+    /**
+     * 附加数据
+     * @type {any}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    extras?: any | null;
+    /**
+     * 时间
+     * @type {Date}
+     * @memberof AdminResultSqlSugarPagedListSysLogEx
+     */
+    time?: Date;
+}

+ 4 - 0
Web/src/api-services/models/index.ts

@@ -56,6 +56,7 @@ export * from './admin-result-sql-sugar-paged-list-sys-dict-data';
 export * from './admin-result-sql-sugar-paged-list-sys-dict-type';
 export * from './admin-result-sql-sugar-paged-list-sys-file';
 export * from './admin-result-sql-sugar-paged-list-sys-log-diff';
+export * from './admin-result-sql-sugar-paged-list-sys-log-ex';
 export * from './admin-result-sql-sugar-paged-list-sys-log-op';
 export * from './admin-result-sql-sugar-paged-list-sys-log-vis';
 export * from './admin-result-sql-sugar-paged-list-sys-notice';
@@ -128,6 +129,7 @@ export * from './job-detail-input';
 export * from './job-output';
 export * from './job-trigger-input';
 export * from './log-input';
+export * from './log-level';
 export * from './login-input';
 export * from './login-output';
 export * from './login-user-output';
@@ -166,6 +168,7 @@ export * from './sql-sugar-paged-list-sys-dict-data';
 export * from './sql-sugar-paged-list-sys-dict-type';
 export * from './sql-sugar-paged-list-sys-file';
 export * from './sql-sugar-paged-list-sys-log-diff';
+export * from './sql-sugar-paged-list-sys-log-ex';
 export * from './sql-sugar-paged-list-sys-log-op';
 export * from './sql-sugar-paged-list-sys-log-vis';
 export * from './sql-sugar-paged-list-sys-notice';
@@ -192,6 +195,7 @@ export * from './sys-job-cluster';
 export * from './sys-job-detail';
 export * from './sys-job-trigger';
 export * from './sys-log-diff';
+export * from './sys-log-ex';
 export * from './sys-log-op';
 export * from './sys-log-vis';
 export * from './sys-menu';

+ 28 - 0
Web/src/api-services/models/log-level.ts

@@ -0,0 +1,28 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 
+ * @export
+ * @enum {string}
+ */
+export enum LogLevel {
+    NUMBER_0 = 0,
+    NUMBER_1 = 1,
+    NUMBER_2 = 2,
+    NUMBER_3 = 3,
+    NUMBER_4 = 4,
+    NUMBER_5 = 5,
+    NUMBER_6 = 6
+}
+

+ 63 - 0
Web/src/api-services/models/sql-sugar-paged-list-sys-log-ex.ts

@@ -0,0 +1,63 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { SysLogEx } from './sys-log-ex';
+/**
+ * 分页泛型集合
+ * @export
+ * @interface SqlSugarPagedListSysLogEx
+ */
+export interface SqlSugarPagedListSysLogEx {
+    /**
+     * 页码
+     * @type {number}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    page?: number;
+    /**
+     * 页容量
+     * @type {number}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    pageSize?: number;
+    /**
+     * 总条数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    total?: number;
+    /**
+     * 总页数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    totalPages?: number;
+    /**
+     * 当前页集合
+     * @type {Array<SysLogEx>}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    items?: Array<SysLogEx> | null;
+    /**
+     * 是否有上一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    hasPrevPage?: boolean;
+    /**
+     * 是否有下一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysLogEx
+     */
+    hasNextPage?: boolean;
+}

+ 207 - 0
Web/src/api-services/models/sys-log-ex.ts

@@ -0,0 +1,207 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { LogLevel } from './log-level';
+/**
+ * 系统异常日志表
+ * @export
+ * @interface SysLogEx
+ */
+export interface SysLogEx {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof SysLogEx
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof SysLogEx
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof SysLogEx
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    tenantId?: number | null;
+    /**
+     * 模块名称
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    controllerName?: string | null;
+    /**
+     * 方法名称
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    actionName?: string | null;
+    /**
+     * 显示名称
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    displayTitle?: string | null;
+    /**
+     * 执行状态
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    status?: string | null;
+    /**
+     * IP地址
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    remoteIp?: string | null;
+    /**
+     * 登录地点
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    location?: string | null;
+    /**
+     * 经度
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    longitude?: number | null;
+    /**
+     * 维度
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    latitude?: number | null;
+    /**
+     * 浏览器
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    browser?: string | null;
+    /**
+     * 操作系统
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    os?: string | null;
+    /**
+     * 操作用时
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    elapsed?: number | null;
+    /**
+     * 日志时间
+     * @type {Date}
+     * @memberof SysLogEx
+     */
+    logDateTime?: Date | null;
+    /**
+     * 
+     * @type {LogLevel}
+     * @memberof SysLogEx
+     */
+    logLevel?: LogLevel;
+    /**
+     * 账号
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    account?: string | null;
+    /**
+     * 真实姓名
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    realName?: string | null;
+    /**
+     * 请求方式
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    httpMethod?: string | null;
+    /**
+     * 请求地址
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    requestUrl?: string | null;
+    /**
+     * 请求参数
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    requestParam?: string | null;
+    /**
+     * 返回结果
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    returnResult?: string | null;
+    /**
+     * 事件Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    eventId?: number | null;
+    /**
+     * 线程Id
+     * @type {number}
+     * @memberof SysLogEx
+     */
+    threadId?: number | null;
+    /**
+     * 请求跟踪Id
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    traceId?: string | null;
+    /**
+     * 异常信息
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    exception?: string | null;
+    /**
+     * 日志消息Json
+     * @type {string}
+     * @memberof SysLogEx
+     */
+    message?: string | null;
+}

+ 7 - 0
Web/src/api-services/models/sys-log-op.ts

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */
+import { LogLevel } from './log-level';
 /**
  * 系统操作日志表
  * @export
@@ -131,6 +132,12 @@ export interface SysLogOp {
      * @memberof SysLogOp
      */
     logDateTime?: Date | null;
+    /**
+     * 
+     * @type {LogLevel}
+     * @memberof SysLogOp
+     */
+    logLevel?: LogLevel;
     /**
      * 账号
      * @type {string}

+ 7 - 0
Web/src/api-services/models/sys-log-vis.ts

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */
+import { LogLevel } from './log-level';
 /**
  * 系统访问日志表
  * @export
@@ -131,6 +132,12 @@ export interface SysLogVis {
      * @memberof SysLogVis
      */
     logDateTime?: Date | null;
+    /**
+     * 
+     * @type {LogLevel}
+     * @memberof SysLogVis
+     */
+    logLevel?: LogLevel;
     /**
      * 账号
      * @type {string}

+ 232 - 0
Web/src/views/system/log/exlog/index.vue

@@ -0,0 +1,232 @@
+<template>
+	<div class="sys-exlog-container" v-loading="state.loading">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
+				<el-form-item label="开始时间" prop="name">
+					<el-date-picker v-model="state.queryParams.startTime" type="datetime" placeholder="开始时间" :shortcuts="shortcuts" />
+				</el-form-item>
+				<el-form-item label="结束时间" prop="code">
+					<el-date-picker v-model="state.queryParams.endTime" type="datetime" placeholder="结束时间" :shortcuts="shortcuts" />
+				</el-form-item>
+				<el-form-item>
+					<el-button-group>
+						<el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'sysExlog:page'"> 查询 </el-button>
+						<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
+					</el-button-group>
+				</el-form-item>
+				<el-form-item>
+					<el-button icon="ele-DeleteFilled" type="danger" @click="clearLog" v-auth="'sysExlog:clear'"> 清空 </el-button>
+					<el-button icon="ele-FolderOpened" @click="exportLog" v-auth="'sysOplog:export'"> 导出 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+
+		<el-card class="full-table" shadow="hover" style="margin-top: 8px">
+			<el-table :data="state.logData" @sort-change="sortChange" style="width: 100%" border :row-class-name="tableRowClassName">
+				<el-table-column type="index" label="序号" width="55" align="center" />
+				<el-table-column prop="controllerName" label="模块名称" width="100" show-overflow-tooltip />
+				<el-table-column prop="displayTitle" label="显示名称" width="150" show-overflow-tooltip />
+				<el-table-column prop="actionName" label="方法名称" width="100" show-overflow-tooltip />
+				<el-table-column prop="httpMethod" label="请求方式" width="90" align="center" show-overflow-tooltip />
+				<el-table-column prop="requestUrl" label="请求地址" width="200" show-overflow-tooltip />
+				<!-- <el-table-column prop="requestParam" label="请求参数" show-overflow-tooltip />
+				<el-table-column prop="returnResult" label="返回结果" show-overflow-tooltip /> -->
+				<el-table-column prop="logLevel" label="级别" width="70" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag v-if="scope.row.logLevel === 1">调试</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 2">消息</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 3">警告</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 4">错误</el-tag>
+						<el-tag v-else>其他</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="eventId" label="事件Id" width="70" align="center" show-overflow-tooltip />
+				<el-table-column prop="threadId" label="线程Id" sortable="custom" width="90" align="center" show-overflow-tooltip />
+				<el-table-column prop="traceId" label="请求跟踪Id" width="150" sortable="custom" show-overflow-tooltip />
+				<el-table-column prop="account" label="账号名称" width="100" show-overflow-tooltip />
+				<el-table-column prop="realName" label="真实姓名" width="100" show-overflow-tooltip />
+				<el-table-column prop="remoteIp" label="IP地址" width="120" show-overflow-tooltip />
+				<el-table-column prop="location" label="登录地点" width="150" show-overflow-tooltip />
+				<el-table-column prop="browser" label="浏览器" show-overflow-tooltip />
+				<el-table-column prop="os" label="操作系统" width="150" show-overflow-tooltip />
+				<el-table-column prop="status" label="状态" width="70" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="success" v-if="scope.row.status === '200'">成功</el-tag>
+						<el-tag type="danger" v-else>失败</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="elapsed" label="耗时(ms)" width="100" align="center" show-overflow-tooltip />
+				<el-table-column prop="exception" label="异常对象" width="150" show-overflow-tooltip />
+				<!-- <el-table-column prop="message" label="日志消息" width="160" fixed="right" show-overflow-tooltip /> -->
+				<el-table-column prop="logDateTime" label="日志时间" width="160" align="center" fixed="right" show-overflow-tooltip />
+				<el-table-column label="操作" width="80" align="center" fixed="right" show-overflow-tooltip>
+					<template #default="scope">
+						<el-button icon="ele-InfoFilled" size="small" text type="primary" @click="viewDetail(scope.row)" v-auth="'sysOplog:page'">详情 </el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<el-pagination
+				v-model:currentPage="state.tableParams.page"
+				v-model:page-size="state.tableParams.pageSize"
+				:total="state.tableParams.total"
+				:page-sizes="[10, 20, 50, 100]"
+				small
+				background
+				@size-change="handleSizeChange"
+				@current-change="handleCurrentChange"
+				layout="total, sizes, prev, pager, next, jumper"
+			/>
+		</el-card>
+		<el-dialog v-model="state.dialogVisible" draggable width="1000px">
+			<template #header>
+				<div style="color: #fff">
+					<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Document /> </el-icon>
+					<span> 日志详情 </span>
+				</div>
+			</template>
+			<pre>{{ state.content }}</pre>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysExLog">
+import { onMounted, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { downloadByData, getFileName } from '/@/utils/download';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysLogExApi } from '/@/api-services/api';
+import { SysLogEx } from '/@/api-services/models';
+
+const state = reactive({
+	loading: false,
+	queryParams: {
+		startTime: undefined,
+		endTime: undefined,
+	},
+	tableParams: {
+		page: 1,
+		pageSize: 20,
+		field: 'createTime', // 默认的排序字段
+		order: 'descending', // 排序方向
+		descStr: 'descending', // 降序排序的关键字符
+		total: 0 as any,
+	},
+	logData: [] as Array<SysLogEx>,
+	dialogVisible: false,
+	content: '',
+});
+
+onMounted(async () => {
+	handleQuery();
+});
+
+// 查询操作
+const handleQuery = async () => {
+	if (state.queryParams.startTime == null) state.queryParams.startTime = undefined;
+	if (state.queryParams.endTime == null) state.queryParams.endTime = undefined;
+
+	state.loading = true;
+	let params = Object.assign(state.queryParams, state.tableParams);
+	var res = await getAPI(SysLogExApi).apiSysLogExPagePost(params);
+	state.logData = res.data.result?.items ?? [];
+	state.tableParams.total = res.data.result?.total;
+	state.loading = false;
+};
+
+// 重置操作
+const resetQuery = () => {
+	state.queryParams.startTime = undefined;
+	state.queryParams.endTime = undefined;
+	handleQuery();
+};
+
+// 清空日志
+const clearLog = async () => {
+	state.loading = true;
+	await getAPI(SysLogExApi).apiSysLogExClearPost();
+	state.loading = false;
+
+	ElMessage.success('清空成功');
+	handleQuery();
+};
+
+// 导出日志
+const exportLog = async () => {
+	state.loading = true;
+	var res = await getAPI(SysLogExApi).apiSysLogExExportPost(state.queryParams, { responseType: 'blob' });
+	state.loading = false;
+
+	var fileName = getFileName(res.headers);
+	downloadByData(res.data as any, fileName);
+};
+
+// 改变页面容量
+const handleSizeChange = (val: number) => {
+	state.tableParams.pageSize = val;
+	handleQuery();
+};
+
+// 改变页码序号
+const handleCurrentChange = (val: number) => {
+	state.tableParams.page = val;
+	handleQuery();
+};
+
+// 查看详情
+const viewDetail = (row: any) => {
+	state.content = row.message;
+	state.dialogVisible = true;
+};
+
+// 设置行颜色
+const tableRowClassName = (row: any) => {
+	return row.row.exception != null ? 'warning-row' : '';
+};
+
+const shortcuts = [
+	{
+		text: '今天',
+		value: new Date(),
+	},
+	{
+		text: '昨天',
+		value: () => {
+			const date = new Date();
+			date.setTime(date.getTime() - 3600 * 1000 * 24);
+			return date;
+		},
+	},
+	{
+		text: '上周',
+		value: () => {
+			const date = new Date();
+			date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+			return date;
+		},
+	},
+];
+
+// 列排序
+const sortChange = (column: any) => {
+	state.tableParams.field = column.prop;
+	state.tableParams.order = column.order;
+	handleQuery();
+};
+</script>
+
+<style lang="scss" scoped>
+.el-popper {
+	max-width: 60%;
+}
+pre {
+	white-space: break-spaces;
+	line-height: 20px;
+}
+.el-table .warning-row {
+	--el-table-tr-bg-color: var(--el-color-warning-light-9);
+}
+.el-table .success-row {
+	--el-table-tr-bg-color: var(--el-color-success-light-9);
+}
+</style>

+ 10 - 1
Web/src/views/system/log/oplog/index.vue

@@ -31,6 +31,15 @@
 				<el-table-column prop="requestUrl" label="请求地址" width="200" show-overflow-tooltip />
 				<!-- <el-table-column prop="requestParam" label="请求参数" show-overflow-tooltip />
 				<el-table-column prop="returnResult" label="返回结果" show-overflow-tooltip /> -->
+				<el-table-column prop="logLevel" label="级别" width="70" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag v-if="scope.row.logLevel === 1">调试</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 2">消息</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 3">警告</el-tag>
+						<el-tag v-else-if="scope.row.logLevel === 4">错误</el-tag>
+						<el-tag v-else>其他</el-tag>
+					</template>
+				</el-table-column>
 				<el-table-column prop="eventId" label="事件Id" width="70" align="center" show-overflow-tooltip />
 				<el-table-column prop="threadId" label="线程Id" sortable="custom" width="90" align="center" show-overflow-tooltip />
 				<el-table-column prop="traceId" label="请求跟踪Id" width="150" sortable="custom" show-overflow-tooltip />
@@ -47,7 +56,7 @@
 					</template>
 				</el-table-column>
 				<el-table-column prop="elapsed" label="耗时(ms)" width="100" align="center" show-overflow-tooltip />
-				<el-table-column prop="exception" label="异常对象" width="150" show-overflow-tooltip />
+				<!-- <el-table-column prop="exception" label="异常对象" width="150" show-overflow-tooltip /> -->
 				<!-- <el-table-column prop="message" label="日志消息" width="160" fixed="right" show-overflow-tooltip /> -->
 				<el-table-column prop="logDateTime" label="日志时间" width="160" align="center" fixed="right" show-overflow-tooltip />
 				<el-table-column label="操作" width="80" align="center" fixed="right" show-overflow-tooltip>