diff --git a/CoreCms.Net.Configuration/AppSettingsConstVars.cs b/CoreCms.Net.Configuration/AppSettingsConstVars.cs
index 5652c5ba..1bcf6d87 100644
--- a/CoreCms.Net.Configuration/AppSettingsConstVars.cs
+++ b/CoreCms.Net.Configuration/AppSettingsConstVars.cs
@@ -96,6 +96,15 @@ namespace CoreCms.Net.Configuration
/// 用户访问记录-过滤ip
///
public static readonly string MiddlewareRecordAccessLogsIgnoreApis = AppSettingsHelper.GetContent("Middleware", "RecordAccessLogs", "IgnoreApis");
+ ///
+ /// 是否开启记录到文件模式
+ ///
+ public static readonly bool MiddlewareRecordAccessLogsEnabledFileMode = AppSettingsHelper.GetContent("Middleware", "RecordAccessLogs", "EnabledFileMode").ObjToBool();
+ ///
+ /// 是否开启记录到数据库模式
+ ///
+ public static readonly bool MiddlewareRecordAccessLogsEnabledDbMode = AppSettingsHelper.GetContent("Middleware", "RecordAccessLogs", "EnabledDbMode").ObjToBool();
+
#endregion
diff --git a/CoreCms.Net.Configuration/GlobalEnumVars.cs b/CoreCms.Net.Configuration/GlobalEnumVars.cs
index cf485471..5e503b3b 100644
--- a/CoreCms.Net.Configuration/GlobalEnumVars.cs
+++ b/CoreCms.Net.Configuration/GlobalEnumVars.cs
@@ -5,10 +5,22 @@ namespace CoreCms.Net.Configuration
///
/// 系统常用枚举类
///
- public class GlobalEnumVars
+ public static class GlobalEnumVars
{
#region 系统相关===============================================================
+ ///
+ /// 多端划分
+ ///
+ public enum CoreShopSystemCategory
+ {
+ Admin = 0,
+ Api = 1,
+ Pc = 2,
+ H5 = 3
+ }
+
+
///
/// 缓存优先级:低、普通、高、永不移除
///
diff --git a/CoreCms.Net.Filter/AdminsControllerPermission.cs b/CoreCms.Net.Filter/AdminsControllerPermission.cs
index 34810d85..f188dcc4 100644
--- a/CoreCms.Net.Filter/AdminsControllerPermission.cs
+++ b/CoreCms.Net.Filter/AdminsControllerPermission.cs
@@ -15,88 +15,108 @@ using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
+using CoreCms.Net.Caching.Manual;
+using CoreCms.Net.Caching.MemoryCache;
+using CoreCms.Net.Configuration;
namespace CoreCms.Net.Filter
{
- public class AdminsControllerPermission
+ public static class AdminsControllerPermission
{
+
+ ///
+ /// 缓存ActionPermission名称
+ ///
+ private const string CacheCoreCmsActionPermission = "CacheCoreCmsActionPermission";
+ ///
+ /// 缓存ControllerPermission名称
+ ///
+ private const string CacheCoreCmsControllerPermission = "CacheCoreCmsControllerPermission";
+
+
///
/// 反射获取所有controller 和action
///
///
- public static List GetAllControllerAndActionByAssembly()
+ private static ControllerPermissionResult GetAllControllerAndActionByAssembly()
{
-
var result = new List();
var types = Assembly.Load("CoreCms.Net.Web.Admin").GetTypes();
-
var noController = new[] { "ToolsController", "LoginController", "DemoController" };
+ var acs = new List();
+
var controllers = types.Where(p => p.Name.Contains("Controller") && !noController.Contains(p.Name));
foreach (var type in controllers)
{
- if (type.Name.Length > 10 && type.BaseType.Name == "ControllerBase" && type.Name.EndsWith("Controller")) //如果是Controller
+ if (type.BaseType != null && (type.Name.Length <= 10 || type.BaseType.Name != "ControllerBase" || !type.Name.EndsWith("Controller"))) continue;
+
+ var members = type.GetMethods();
+ var cp = new ControllerPermission();
+ cp.name = type.Name.Substring(0, type.Name.Length - 10);
+ cp.action = new List();
+ cp.controllerName = cp.name;
+
+ var objs = type.GetCustomAttributes(typeof(DescriptionAttribute), true);
+ if (objs.Length > 0) cp.description = (objs[0] as DescriptionAttribute)?.Description;
+ //附加此代码用于代码生成器显示选择
+ if (!string.IsNullOrEmpty(cp.description))
{
- var members = type.GetMethods();
- var cp = new ControllerPermission
- {
- name = type.Name.Substring(0, type.Name.Length - 10),
- action = new List()
- };
-
- var objs = type.GetCustomAttributes(typeof(DescriptionAttribute), true);
- if (objs.Length > 0) cp.description = (objs[0] as DescriptionAttribute).Description;
-
- if (!string.IsNullOrEmpty(cp.description))
- {
- cp.name += "【" + cp.description + "】";
- }
-
-
- var newMembers = members.Where(p =>
- p.ReturnType.FullName != null && (p.ReturnType.Name == "ActionResult" ||
- p.ReturnType.Name == "FileResult" ||
- p.ReturnType.Name == "JsonResult" ||
- (p.ReturnType.GenericTypeArguments.Length > 0 && p.ReturnType.GenericTypeArguments[0].Name == "JsonResult") ||
- p.ReturnType.Name == "AdminUiCallBack" ||
- p.ReturnType.Name == "IActionResult" ||
- p.ReturnType.FullName.Contains("CoreCms.Net.Model.ViewModels.UI.AdminUiCallBack"))
- ).ToList();
-
- foreach (var member in newMembers)
- {
- if (member.Name == "ValidationProblem" || member.Name == "Json") continue;
-
- //if (member.ReturnType.Name == "ActionResult" || member.ReturnType.Name == "FileResult" || member.ReturnType.Name == "JsonResult" || (member.ReturnType.GenericTypeArguments.Length > 0 && member.ReturnType.GenericTypeArguments[0].Name == "JsonResult")) //如果是Action
- //{
- //}
-
-
- var ap = new ActionPermission
- {
- name = member.Name,
- actionName = member.Name,
- controllerName = member.DeclaringType.Name.Substring(0, member.DeclaringType.Name.Length - 10)
- };
- // 去掉“Controller”后缀
-
- var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), true);
- if (attrs.Length > 0) ap.description = (attrs[0] as DescriptionAttribute).Description;
-
- if (!string.IsNullOrEmpty(ap.description))
- {
- ap.name += "【" + ap.description + "】";
- }
- cp.action.Add(ap);
-
- }
- cp.action = cp.action.Distinct(new ModelComparer()).ToList();
- result.Add(cp);
+ cp.name += "【" + cp.description + "】";
}
+
+ var newMembers = members.Where(p =>
+ p.ReturnType.FullName != null && (p.ReturnType.Name == "ActionResult" ||
+ p.ReturnType.Name == "FileResult" ||
+ p.ReturnType.Name == "JsonResult" ||
+ (p.ReturnType.GenericTypeArguments.Length > 0 && p.ReturnType.GenericTypeArguments[0].Name == "JsonResult") ||
+ p.ReturnType.Name == "AdminUiCallBack" ||
+ p.ReturnType.Name == "IActionResult" ||
+ p.ReturnType.FullName.Contains("CoreCms.Net.Model.ViewModels.UI.AdminUiCallBack"))
+ ).ToList();
+
+ foreach (var member in newMembers)
+ {
+ if (member.Name == "ValidationProblem" || member.Name == "Json") continue;
+
+ //if (member.ReturnType.Name == "ActionResult" || member.ReturnType.Name == "FileResult" || member.ReturnType.Name == "JsonResult" || (member.ReturnType.GenericTypeArguments.Length > 0 && member.ReturnType.GenericTypeArguments[0].Name == "JsonResult")) //如果是Action
+ //{
+ //}
+
+ var ap = new ActionPermission();
+ ap.name = member.Name;
+ ap.actionName = member.Name;
+ if (member.DeclaringType != null)
+ {
+ // 去掉“Controller”后缀
+ ap.controllerName = member.DeclaringType.Name.Substring(0, member.DeclaringType.Name.Length - 10);
+ }
+ ap.path = "/Api/" + ap.controllerName + "/" + member.Name;
+
+ var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), true);
+ if (attrs.Length > 0) ap.description = (attrs[0] as DescriptionAttribute)?.Description;
+ //附加此代码用于代码生成器显示选择
+ if (!string.IsNullOrEmpty(ap.description))
+ {
+ ap.name += "【" + ap.description + "】";
+ }
+ ap.controllerDescription = cp.description;
+
+ cp.action.Add(ap);
+ acs.Add(ap);
+ }
+ cp.action = cp.action.Distinct(new ModelComparer()).ToList();
+ result.Add(cp);
}
- return result;
+
+ var resultObj = new ControllerPermissionResult
+ {
+ ControllersAndActions = result,
+ Actions = acs
+ };
+ return resultObj;
}
private class ModelComparer : IEqualityComparer
@@ -111,46 +131,132 @@ namespace CoreCms.Net.Filter
return obj.name.ToUpper().GetHashCode();
}
}
+
+ ///
+ /// 获取缓存ActionPermission
+ ///
+ ///
+ public static List GetCacheCoreCmsActionPermission()
+ {
+ var memoryCacheManager = new MemoryCacheManager();
+ var cache = memoryCacheManager.Get>(CacheCoreCmsActionPermission);
+ return cache ?? UpdateCacheCoreCmsActionPermission().Actions;
+ }
+
+ ///
+ /// 获取缓存ControllerPermission名称
+ ///
+ ///
+ public static List GetCacheCoreCmsControllerPermission()
+ {
+ var memoryCacheManager = new MemoryCacheManager();
+ var cache = memoryCacheManager.Get>(CacheCoreCmsControllerPermission);
+ return cache ?? UpdateCacheCoreCmsActionPermission().ControllersAndActions;
+ }
+
+ ///
+ /// 更新cache
+ ///
+ private static ControllerPermissionResult UpdateCacheCoreCmsActionPermission()
+ {
+ var list = GetAllControllerAndActionByAssembly();
+ var memoryCacheManager = new MemoryCacheManager();
+ //缓存24小时
+ memoryCacheManager.Set(CacheCoreCmsControllerPermission, list.ControllersAndActions, 1440);
+ memoryCacheManager.Set(CacheCoreCmsActionPermission, list.Actions, 1440);
+ return list;
+ }
}
-
- public class ActionPermission
+ ///
+ /// 外部包一圈
+ ///
+ public class ControllerPermissionResult
{
///
- /// 请求地址
+ /// 实际结果集
///
- public virtual string name { get; set; }
+ public List ControllersAndActions { get; set; }
///
- /// 请求地址
+ /// 只获取的action集合,用于缓存
///
- public virtual string controllerName { get; set; }
+ public List Actions { get; set; }
+
+ }
+
+ ///
+ /// action数据
+ ///
+ public sealed class ActionPermission
+ {
+ ///
+ /// 地址
+ ///
+ public string path { get; set; }
///
- /// 请求地址
+ /// 地址及描述
///
- public virtual string actionName { get; set; }
+ public string name { get; set; }
+
+ ///
+ /// 控制器
+ ///
+ public string controllerName { get; set; }
+
+ ///
+ /// 控制器描述
+ ///
+ public string controllerDescription { get; set; }
+
+ ///
+ /// 方法
+ ///
+ public string actionName { get; set; }
///
/// 描述
///
- public virtual string description { get; set; }
+ public string description { get; set; }
- public virtual string type { get; set; } = "action";
+ ///
+ /// 类型
+ ///
+ public string type { get; set; } = "action";
}
- public class ControllerPermission
+ ///
+ /// Controller数据
+ ///
+ public sealed class ControllerPermission
{
- public virtual string name { get; set; }
+ ///
+ /// 控制器
+ ///
+ public string controllerName { get; set; }
- public virtual string description { get; set; }
+ ///
+ /// 控制器和描述
+ ///
+ public string name { get; set; }
- public virtual IList action { get; set; }
+ ///
+ /// 描述
+ ///
+ public string description { get; set; }
+ ///
+ /// 方法列表
+ ///
+ public IList action { get; set; }
- public virtual string type { get; set; } = "controller";
+ ///
+ /// 类型
+ ///
+ public string type { get; set; } = "controller";
}
}
diff --git a/CoreCms.Net.Filter/CoreCms.Net.Filter.csproj b/CoreCms.Net.Filter/CoreCms.Net.Filter.csproj
index 79506632..f9e96bae 100644
--- a/CoreCms.Net.Filter/CoreCms.Net.Filter.csproj
+++ b/CoreCms.Net.Filter/CoreCms.Net.Filter.csproj
@@ -11,6 +11,7 @@
+
diff --git a/CoreCms.Net.IRepository/System/ISysUserOperationLogRepository.cs b/CoreCms.Net.IRepository/System/ISysUserOperationLogRepository.cs
new file mode 100644
index 00000000..6b3f95eb
--- /dev/null
+++ b/CoreCms.Net.IRepository/System/ISysUserOperationLogRepository.cs
@@ -0,0 +1,44 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:27:47
+ * Description: 暂无
+ ***********************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.ViewModels.Basics;
+using CoreCms.Net.Model.ViewModels.UI;
+using SqlSugar;
+
+
+namespace CoreCms.Net.IRepository
+{
+ ///
+ /// 用户操作日志 工厂接口
+ ///
+ public interface ISysUserOperationLogRepository : IBaseRepository
+ {
+ ///
+ /// 重写根据条件查询分页数据
+ ///
+ /// 判断集合
+ /// 排序方式
+ /// 当前页面索引
+ /// 分布大小
+ ///
+ /// 是否使用WITH(NOLOCK)
+ ///
+ new Task> QueryPageAsync(
+ Expression> predicate,
+ Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1,
+ int pageSize = 20, bool blUseNoLock = false);
+
+ }
+}
diff --git a/CoreCms.Net.IServices/System/ISysUserOperationLogServices.cs b/CoreCms.Net.IServices/System/ISysUserOperationLogServices.cs
new file mode 100644
index 00000000..da7dd4b6
--- /dev/null
+++ b/CoreCms.Net.IServices/System/ISysUserOperationLogServices.cs
@@ -0,0 +1,44 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:27:47
+ * Description: 暂无
+ ***********************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.ViewModels.Basics;
+using CoreCms.Net.Model.ViewModels.UI;
+using SqlSugar;
+
+namespace CoreCms.Net.IServices
+{
+ ///
+ /// 用户操作日志 服务工厂接口
+ ///
+ public interface ISysUserOperationLogServices : IBaseServices
+ {
+ #region 重写根据条件查询分页数据
+ ///
+ /// 重写根据条件查询分页数据
+ ///
+ /// 判断集合
+ /// 排序方式
+ /// 当前页面索引
+ /// 分布大小
+ ///
+ /// 是否使用WITH(NOLOCK)
+ ///
+ new Task> QueryPageAsync(
+ Expression> predicate,
+ Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1,
+ int pageSize = 20, bool blUseNoLock = false);
+ #endregion
+ }
+}
diff --git a/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj b/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj
index cc4bad31..394ce2ef 100644
--- a/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj
+++ b/CoreCms.Net.Middlewares/CoreCms.Net.Middlewares.csproj
@@ -8,6 +8,7 @@
+
diff --git a/CoreCms.Net.Middlewares/ExceptionHandlerMiddForAdmin.cs b/CoreCms.Net.Middlewares/ExceptionHandlerMiddForAdmin.cs
index c86ec506..77a7046e 100644
--- a/CoreCms.Net.Middlewares/ExceptionHandlerMiddForAdmin.cs
+++ b/CoreCms.Net.Middlewares/ExceptionHandlerMiddForAdmin.cs
@@ -13,60 +13,57 @@
using System;
-using System.Collections.Generic;
using System.Net;
-using System.Text;
using System.Threading.Tasks;
using CoreCms.Net.Loging;
using CoreCms.Net.Model.ViewModels.UI;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
+using NLog;
-namespace CoreCms.Net.Middlewares
+namespace CoreCms.Net.Middlewares;
+
+///
+/// 异常错误统一返回记录
+///
+public class ExceptionHandlerMiddForAdmin
{
- ///
- /// 异常错误统一返回记录
- ///
- public class ExceptionHandlerMiddForAdmin
+ private readonly RequestDelegate _next;
+
+ public ExceptionHandlerMiddForAdmin(RequestDelegate next)
{
- private readonly RequestDelegate _next;
+ _next = next;
+ }
- public ExceptionHandlerMiddForAdmin(RequestDelegate next)
+ public async Task Invoke(HttpContext context)
+ {
+ try
{
- _next = next;
+ await _next(context);
}
-
- public async Task Invoke(HttpContext context)
+ catch (Exception ex)
{
- try
- {
- await _next(context);
- }
- catch (Exception ex)
- {
- await HandleExceptionAsync(context, ex);
- }
- }
-
- private async Task HandleExceptionAsync(HttpContext context, Exception ex)
- {
- if (ex == null) return;
- NLogUtil.WriteAll(NLog.LogLevel.Error, LogType.Web, "全局捕获异常", "全局捕获异常", new Exception("全局捕获异常", ex));
- await WriteExceptionAsync(context, ex).ConfigureAwait(false);
- }
-
- private static async Task WriteExceptionAsync(HttpContext context, Exception e)
- {
- if (e is UnauthorizedAccessException) context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
- else if (e is Exception) context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
-
- context.Response.ContentType = "application/json";
- var jm = new AdminUiCallBack();
- jm.code = 500;
- jm.data = e;
- jm.msg = "全局捕获异常";
- await context.Response.WriteAsync(JsonConvert.SerializeObject(jm)).ConfigureAwait(false);
+ await HandleExceptionAsync(context, ex);
}
}
-}
+
+ private async Task HandleExceptionAsync(HttpContext context, Exception ex)
+ {
+ if (ex == null) return;
+ NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "全局捕获异常", "全局捕获异常", new Exception("全局捕获异常", ex));
+ await WriteExceptionAsync(context, ex).ConfigureAwait(false);
+ }
+
+ private static async Task WriteExceptionAsync(HttpContext context, Exception e)
+ {
+ if (e is UnauthorizedAccessException) context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
+ else if (e != null) context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
+
+ context.Response.ContentType = "application/json";
+ var jm = new AdminUiCallBack();
+ jm.code = 500;
+ jm.data = e;
+ jm.msg = "全局捕获异常";
+ await context.Response.WriteAsync(JsonConvert.SerializeObject(jm)).ConfigureAwait(false);
+ }
+}
\ No newline at end of file
diff --git a/CoreCms.Net.Middlewares/ExceptionHandlerMiddForClent.cs b/CoreCms.Net.Middlewares/ExceptionHandlerMiddForClent.cs
index e8dd1a40..6acf793d 100644
--- a/CoreCms.Net.Middlewares/ExceptionHandlerMiddForClent.cs
+++ b/CoreCms.Net.Middlewares/ExceptionHandlerMiddForClent.cs
@@ -13,69 +13,63 @@
using System;
-using System.Collections.Generic;
using System.Net;
-using System.Text;
using System.Threading.Tasks;
-using CoreCms.Net.IServices;
using CoreCms.Net.Loging;
-using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.ViewModels.UI;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
+using NLog;
-namespace CoreCms.Net.Middlewares
+namespace CoreCms.Net.Middlewares;
+
+///
+/// 异常错误统一返回记录
+///
+public class ExceptionHandlerMiddForClent
{
- ///
- /// 异常错误统一返回记录
- ///
- public class ExceptionHandlerMiddForClent
+ private readonly RequestDelegate _next;
+
+
+ public ExceptionHandlerMiddForClent(RequestDelegate next)
{
- private readonly RequestDelegate _next;
+ _next = next;
+ }
-
- public ExceptionHandlerMiddForClent(RequestDelegate next)
+ public async Task Invoke(HttpContext context)
+ {
+ try
{
- _next = next;
+ await _next(context);
}
-
- public async Task Invoke(HttpContext context)
+ catch (Exception ex)
{
- try
- {
- await _next(context);
- }
- catch (Exception ex)
- {
- await HandleExceptionAsync(context, ex);
- }
- }
-
- private async Task HandleExceptionAsync(HttpContext context, Exception ex)
- {
- if (ex == null) return;
-
- NLogUtil.WriteAll(NLog.LogLevel.Error, LogType.ApiRequest, "全局捕获异常", "全局捕获异常", new Exception("全局捕获异常", ex));
-
- await WriteExceptionAsync(context, ex).ConfigureAwait(false);
- }
-
- private static async Task WriteExceptionAsync(HttpContext context, Exception e)
- {
- if (e is UnauthorizedAccessException)
- context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
- else if (e is Exception)
- context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
-
- context.Response.ContentType = "application/json";
- var jm = new WebApiCallBack();
- jm.status = false;
- jm.code = 500;
- jm.data = e;
- jm.msg = "全局数据异常";
- await context.Response.WriteAsync(JsonConvert.SerializeObject(jm)).ConfigureAwait(false);
+ await HandleExceptionAsync(context, ex);
}
}
-}
+
+ private async Task HandleExceptionAsync(HttpContext context, Exception ex)
+ {
+ if (ex == null) return;
+
+ NLogUtil.WriteAll(LogLevel.Error, LogType.ApiRequest, "全局捕获异常", "全局捕获异常", new Exception("全局捕获异常", ex));
+
+ await WriteExceptionAsync(context, ex).ConfigureAwait(false);
+ }
+
+ private static async Task WriteExceptionAsync(HttpContext context, Exception e)
+ {
+ if (e is UnauthorizedAccessException)
+ context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
+ else if (e != null)
+ context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
+
+ context.Response.ContentType = "application/json";
+ var jm = new WebApiCallBack();
+ jm.status = false;
+ jm.code = 500;
+ jm.data = e;
+ jm.msg = "全局数据异常";
+ await context.Response.WriteAsync(JsonConvert.SerializeObject(jm)).ConfigureAwait(false);
+ }
+}
\ No newline at end of file
diff --git a/CoreCms.Net.Middlewares/IPLogMildd.cs b/CoreCms.Net.Middlewares/IPLogMildd.cs
index 1bf81cd5..468b82e1 100644
--- a/CoreCms.Net.Middlewares/IPLogMildd.cs
+++ b/CoreCms.Net.Middlewares/IPLogMildd.cs
@@ -67,9 +67,9 @@ namespace CoreCms.Net.Middlewares
if (!string.IsNullOrEmpty(requestInfo))
{
- Parallel.For(0, 1, e =>
+ Parallel.For(0, 1, _ =>
{
- LogLockHelper.OutSql2Log("RequestIpInfoLog", "RequestIpInfoLog" + dt.ToString("yyyy-MM-dd-HH"), new string[] { requestInfo + "," }, false);
+ LogLockHelper.OutSql2Log("RequestIpInfoLog", "RequestIpInfoLog" + dt.ToString("yyyy-MM-dd-HH"), new[] { requestInfo + "," }, false);
});
request.Body.Position = 0;
}
@@ -77,6 +77,7 @@ namespace CoreCms.Net.Middlewares
}
catch (Exception)
{
+ // ignored
}
}
else
@@ -95,10 +96,7 @@ namespace CoreCms.Net.Middlewares
var ip = context.Request.Headers["X-Forwarded-For"].ObjectToString();
if (string.IsNullOrEmpty(ip))
{
- if (context.Connection.RemoteIpAddress != null)
- {
- ip = context.Connection.RemoteIpAddress.MapToIPv4().ObjectToString();
- }
+ ip = context.Connection.RemoteIpAddress.ObjectToString();
}
return ip;
}
diff --git a/CoreCms.Net.Middlewares/MiddlewareHelpers.cs b/CoreCms.Net.Middlewares/MiddlewareHelpers.cs
index 8ab90028..76eda593 100644
--- a/CoreCms.Net.Middlewares/MiddlewareHelpers.cs
+++ b/CoreCms.Net.Middlewares/MiddlewareHelpers.cs
@@ -78,10 +78,11 @@ namespace CoreCms.Net.Middlewares
/// 用户访问接口日志中间件
///
///
+ ///
///
- public static IApplicationBuilder UseRecordAccessLogsMildd(this IApplicationBuilder app)
+ public static IApplicationBuilder UseRecordAccessLogsMildd(this IApplicationBuilder app,string dataSources)
{
- return app.UseMiddleware();
+ return app.UseMiddleware(dataSources);
}
}
diff --git a/CoreCms.Net.Middlewares/RecordAccessLogsMildd.cs b/CoreCms.Net.Middlewares/RecordAccessLogsMildd.cs
index f0b34197..7dbb1c54 100644
--- a/CoreCms.Net.Middlewares/RecordAccessLogsMildd.cs
+++ b/CoreCms.Net.Middlewares/RecordAccessLogsMildd.cs
@@ -3,15 +3,24 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.IdentityModel.Tokens.Jwt;
using System.IO;
+using System.Linq;
+using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
-using CoreCms.Net.Auth.HttpContextUser;
using CoreCms.Net.Configuration;
+using CoreCms.Net.Filter;
+using CoreCms.Net.IServices;
using CoreCms.Net.Loging;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.ViewModels.Basics;
using CoreCms.Net.Utility.Extensions;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace CoreCms.Net.Middlewares
{
@@ -21,103 +30,143 @@ namespace CoreCms.Net.Middlewares
///
public class RecordAccessLogsMildd
{
- ///
- ///
- ///
private readonly RequestDelegate _next;
- private readonly IHttpContextUser _user;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly ISysUserOperationLogServices _sysUserOperationLogServices;
- private readonly ILogger _logger;
private readonly Stopwatch _stopwatch;
+ private readonly string _dataSources;
+
+
///
/// 构造
///
- ///
- ///
- ///
- public RecordAccessLogsMildd(RequestDelegate next, IHttpContextUser user, ILogger logger)
+ public RecordAccessLogsMildd(RequestDelegate next, IHttpContextAccessor httpContextAccessor, ISysUserOperationLogServices sysUserOperationLogServices, string dataSources)
{
_next = next;
- _user = user;
- _logger = logger;
+ _httpContextAccessor = httpContextAccessor;
+ _dataSources = dataSources;
+ _sysUserOperationLogServices = sysUserOperationLogServices;
_stopwatch = new Stopwatch();
}
public async Task InvokeAsync(HttpContext context)
{
- if (AppSettingsConstVars.MiddlewareRecordAccessLogsEnabled)
+ //用户访问记录-是否开启
+ var middlewareRecordAccessLogsEnabled = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabled;
+ //是否开启记录到文件模式
+ var middlewareRecordAccessLogsEnabledFileMode = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabledFileMode;
+ //是否开启记录到数据库模式
+ var middlewareRecordAccessLogsEnabledDbMode = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabledDbMode;
+
+ if (middlewareRecordAccessLogsEnabled && (middlewareRecordAccessLogsEnabledFileMode || middlewareRecordAccessLogsEnabledDbMode))
{
- var api = context.Request.Path.ObjectToString().TrimEnd('/').ToLower();
+ var request = context.Request;
+ var api = request.Path.ObjectToString().TrimEnd('/').ToLower();
var ignoreApis = AppSettingsConstVars.MiddlewareRecordAccessLogsIgnoreApis;
// 过滤,只有接口
- if (api.Contains("api") && !ignoreApis.Contains(api))
+ if (api.Contains("api") && !ignoreApis.ToLower().Contains(api))
{
_stopwatch.Restart();
- var userAccessModel = new UserAccessModel();
+ var uLog = new SysUserOperationLog();
- HttpRequest request = context.Request;
-
- userAccessModel.API = api;
- userAccessModel.User = _user.Name;
- userAccessModel.IP = IPLogMildd.GetClientIp(context);
- userAccessModel.BeginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- userAccessModel.RequestMethod = request.Method;
- userAccessModel.Agent = request.Headers["User-Agent"].ObjectToString();
-
-
- // 获取请求body内容
- if (request.Method.ToLower().Equals("post") || request.Method.ToLower().Equals("put"))
+ if (_httpContextAccessor.HttpContext != null)
{
- // 启用倒带功能,就可以让 Request.Body 可以再次读取
- request.EnableBuffering();
+ var authenticate = await _httpContextAccessor.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
+ if (authenticate.Succeeded && authenticate.Principal != null)
+ {
+ //账号
+ uLog.userName = authenticate.Principal.Identities.First().FindFirst(ClaimTypes.Name)?.Value;
+ //昵称
+ uLog.userNickName = authenticate.Principal.Identities.First().FindFirst(ClaimTypes.GivenName)?.Value;
+ //用户序列
+ uLog.userId = authenticate.Principal.Identities.First().FindFirst(JwtRegisteredClaimNames.Jti)!.Value.ObjectToInt(0);
+ }
- Stream stream = request.Body;
- byte[] buffer = new byte[request.ContentLength.Value];
- stream.Read(buffer, 0, buffer.Length);
- userAccessModel.RequestData = Encoding.UTF8.GetString(buffer);
+ var adminLog = AdminsControllerPermission.GetCacheCoreCmsActionPermission();
- request.Body.Position = 0;
+ var curLog = adminLog.FirstOrDefault(p => p.path.ToLower() == _httpContextAccessor.HttpContext.Request.Path.Value.ToLower());
+ if (curLog != null)
+ {
+ uLog.actionName = curLog.actionName;
+ uLog.actionDescription = curLog.description;
+ uLog.controllerName = curLog.controllerName;
+ uLog.controllerDescription = curLog.controllerDescription;
+ }
+ uLog.apiPath = _httpContextAccessor.HttpContext.Request.Path.Value;
+ uLog.statusCode = _httpContextAccessor.HttpContext.Response.StatusCode;
}
- else if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))
+ else
{
- userAccessModel.RequestData = HttpUtility.UrlDecode(request.QueryString.ObjectToString(), Encoding.UTF8);
+ uLog.apiPath = api;
+ }
+
+ uLog.ip = IPLogMildd.GetClientIp(context);
+ uLog.beginTime = DateTime.Now;
+ uLog.requestMethod = request.Method;
+ uLog.agent = request.Headers["User-Agent"].ObjectToString();
+ uLog.dataSources = _dataSources;
+
+ switch (request.Method.ToLower())
+ {
+ // 获取请求body内容
+ case "post":
+ case "put":
+ {
+ // 启用倒带功能,就可以让 Request.Body 可以再次读取
+ request.EnableBuffering();
+ var stream = request.Body;
+ if (request.ContentLength != null)
+ {
+ byte[] buffer = new byte[request.ContentLength.Value];
+ var read = await stream.ReadAsync(buffer);
+ uLog.requestData = Encoding.UTF8.GetString(buffer);
+ }
+ request.Body.Position = 0;
+ break;
+ }
+ case "get":
+ case "delete":
+ uLog.requestData = HttpUtility.UrlDecode(request.QueryString.ObjectToString(), Encoding.UTF8);
+ break;
}
// 获取Response.Body内容
var originalBodyStream = context.Response.Body;
- using (var responseBody = new MemoryStream())
+ await using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
-
await _next(context);
-
- var responseBodyData = await GetResponse(context.Response);
-
+ uLog.responseBodyData = await GetResponse(context.Response);
await responseBody.CopyToAsync(originalBodyStream);
}
-
- var dt = DateTime.Now;
-
// 响应完成记录时间和存入日志
- context.Response.OnCompleted(() =>
+ context.Response.OnCompleted(async () =>
{
_stopwatch.Stop();
- userAccessModel.OPTime = _stopwatch.ElapsedMilliseconds + "ms";
-
- // 自定义log输出
- var requestInfo = JsonConvert.SerializeObject(userAccessModel);
- Parallel.For(0, 1, e =>
+ uLog.opTime = _stopwatch.ElapsedMilliseconds + "ms";
+ uLog.endTime = DateTime.Now;
+ uLog.createTime = DateTime.Now;
+ //写入文件
+ if (middlewareRecordAccessLogsEnabledFileMode)
{
- LogLockHelper.OutSql2Log("RecordAccessLogs", "RecordAccessLogs" + dt.ToString("yyyy-MM-dd-HH"), new string[] { requestInfo + "," }, false);
- });
-
- return Task.CompletedTask;
+ // 自定义log输出
+ var requestInfo = JsonConvert.SerializeObject(uLog);
+ Parallel.For(0, 1, e =>
+ {
+ LogLockHelper.OutSql2Log("RecordAccessLogs", "RecordAccessLogs" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new[] { requestInfo + "," }, false);
+ });
+ }
+ //写入数据库
+ if (middlewareRecordAccessLogsEnabledDbMode)
+ {
+ await _sysUserOperationLogServices.InsertAsync(uLog);
+ }
});
-
}
else
{
@@ -145,18 +194,5 @@ namespace CoreCms.Net.Middlewares
}
}
- public class UserAccessModel
- {
- public string User { get; set; }
- public string IP { get; set; }
- public string API { get; set; }
- public string BeginTime { get; set; }
- public string OPTime { get; set; }
- public string RequestMethod { get; set; }
- public string RequestData { get; set; }
- public string Agent { get; set; }
-
- }
-
}
diff --git a/CoreCms.Net.Middlewares/RequRespLogMildd.cs b/CoreCms.Net.Middlewares/RequRespLogMildd.cs
index 649a101a..627654e1 100644
--- a/CoreCms.Net.Middlewares/RequRespLogMildd.cs
+++ b/CoreCms.Net.Middlewares/RequRespLogMildd.cs
@@ -48,7 +48,7 @@ namespace CoreCms.Net.Middlewares
if (AppSettingsConstVars.MiddlewareRequestResponseLogEnabled)
{
// 过滤,只有接口
- if (context.Request.Path.Value.Contains("api") || context.Request.Path.Value.Contains("Api"))
+ if (context.Request.Path.Value != null && (context.Request.Path.Value.Contains("api") || context.Request.Path.Value.Contains("Api")))
{
context.Request.EnableBuffering();
Stream originalBody = context.Response.Body;
@@ -57,18 +57,16 @@ namespace CoreCms.Net.Middlewares
// 存储请求数据
await RequestDataLog(context);
- using (var ms = new MemoryStream())
- {
- context.Response.Body = ms;
+ await using var ms = new MemoryStream();
+ context.Response.Body = ms;
- await _next(context);
+ await _next(context);
- // 存储响应数据
- ResponseDataLog(context.Response, ms);
+ // 存储响应数据
+ ResponseDataLog(ms);
- ms.Position = 0;
- await ms.CopyToAsync(originalBody);
- }
+ ms.Position = 0;
+ await ms.CopyToAsync(originalBody);
}
catch (Exception)
{
@@ -91,7 +89,7 @@ namespace CoreCms.Net.Middlewares
}
}
- private async Task RequestDataLog(HttpContext context)
+ private static async Task RequestDataLog(HttpContext context)
{
var request = context.Request;
var sr = new StreamReader(request.Body);
@@ -100,9 +98,9 @@ namespace CoreCms.Net.Middlewares
if (!string.IsNullOrEmpty(content))
{
- Parallel.For(0, 1, e =>
+ Parallel.For(0, 1, _ =>
{
- LogLockHelper.OutSql2Log("RequestResponseLog", "RequestResponseLog" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new string[] { "Request Data:", content });
+ LogLockHelper.OutSql2Log("RequestResponseLog", "RequestResponseLog" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new[] { "Request Data:", content });
});
@@ -110,18 +108,15 @@ namespace CoreCms.Net.Middlewares
}
}
- private void ResponseDataLog(HttpResponse response, MemoryStream ms)
+ private static void ResponseDataLog(Stream ms)
{
ms.Position = 0;
- var ResponseBody = new StreamReader(ms).ReadToEnd();
- // 去除 Html
- var reg = "<[^>]+>";
- var isHtml = Regex.IsMatch(ResponseBody, reg);
- if (!string.IsNullOrEmpty(ResponseBody))
+ var responseBody = new StreamReader(ms).ReadToEnd();
+ if (!string.IsNullOrEmpty(responseBody))
{
- Parallel.For(0, 1, e =>
+ Parallel.For(0, 1, _ =>
{
- LogLockHelper.OutSql2Log("RequestResponseLog", "RequestResponseLog" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new string[] { "Response Data:", ResponseBody });
+ LogLockHelper.OutSql2Log("RequestResponseLog", "RequestResponseLog" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new[] { "Response Data:", responseBody });
});
}
}
diff --git a/CoreCms.Net.Model/Entities/System/SysUserOperationLog.cs b/CoreCms.Net.Model/Entities/System/SysUserOperationLog.cs
new file mode 100644
index 00000000..629878c4
--- /dev/null
+++ b/CoreCms.Net.Model/Entities/System/SysUserOperationLog.cs
@@ -0,0 +1,272 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:52:14
+ * Description: 暂无
+ ***********************************************************************/
+
+using SqlSugar;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace CoreCms.Net.Model.Entities
+{
+ ///
+ /// 用户操作日志
+ ///
+ public partial class SysUserOperationLog
+ {
+ ///
+ /// 构造函数
+ ///
+ public SysUserOperationLog()
+ {
+ }
+
+ ///
+ /// 序列
+ ///
+ [Display(Name = "序列")]
+
+ [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.Int32 id { get; set; }
+
+
+ ///
+ /// 用户登录账号
+ ///
+ [Display(Name = "用户登录账号")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String userName { get; set; }
+
+
+ ///
+ /// 用户登录昵称
+ ///
+ [Display(Name = "用户登录昵称")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String userNickName { get; set; }
+
+
+ ///
+ /// 用户序列
+ ///
+ [Display(Name = "用户序列")]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.Int32 userId { get; set; }
+
+
+ ///
+ /// IP地址
+ ///
+ [Display(Name = "IP地址")]
+
+
+ [StringLength(maximumLength:150,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String ip { get; set; }
+
+
+ ///
+ /// 请求地址
+ ///
+ [Display(Name = "请求地址")]
+
+
+ [StringLength(maximumLength:150,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String apiPath { get; set; }
+
+
+ ///
+ /// 开始时间
+ ///
+ [Display(Name = "开始时间")]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.DateTime beginTime { get; set; }
+
+
+ ///
+ /// 结束时间
+ ///
+ [Display(Name = "结束时间")]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.DateTime endTime { get; set; }
+
+
+ ///
+ /// 耗时
+ ///
+ [Display(Name = "耗时")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String opTime { get; set; }
+
+
+ ///
+ /// 请求方式
+ ///
+ [Display(Name = "请求方式")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String requestMethod { get; set; }
+
+
+ ///
+ /// 请求数据
+ ///
+ [Display(Name = "请求数据")]
+
+
+
+
+
+ public System.String requestData { get; set; }
+
+
+ ///
+ /// 返回数据
+ ///
+ [Display(Name = "返回数据")]
+
+
+
+
+
+ public System.String responseBodyData { get; set; }
+
+
+ ///
+ /// 代理渠道
+ ///
+ [Display(Name = "代理渠道")]
+
+
+ [StringLength(maximumLength:1000,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String agent { get; set; }
+
+
+ ///
+ /// 动作方法名称
+ ///
+ [Display(Name = "动作方法名称")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String actionName { get; set; }
+
+
+ ///
+ /// 动作方法描述
+ ///
+ [Display(Name = "动作方法描述")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String actionDescription { get; set; }
+
+
+ ///
+ /// 控制器名称
+ ///
+ [Display(Name = "控制器名称")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String controllerName { get; set; }
+
+
+ ///
+ /// 控制器名称
+ ///
+ [Display(Name = "控制器名称")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String controllerDescription { get; set; }
+
+
+ ///
+ /// 状态码
+ ///
+ [Display(Name = "状态码")]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.Int32 statusCode { get; set; }
+
+
+ ///
+ /// 创建时间
+ ///
+ [Display(Name = "创建时间")]
+
+ [Required(ErrorMessage = "请输入{0}")]
+
+
+
+ public System.DateTime createTime { get; set; }
+
+
+ ///
+ /// 数据来源
+ ///
+ [Display(Name = "数据来源")]
+
+
+ [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
+
+
+ public System.String dataSources { get; set; }
+
+
+ }
+}
diff --git a/CoreCms.Net.Repository/System/SysUserOperationLogRepository.cs b/CoreCms.Net.Repository/System/SysUserOperationLogRepository.cs
new file mode 100644
index 00000000..57dd7bf1
--- /dev/null
+++ b/CoreCms.Net.Repository/System/SysUserOperationLogRepository.cs
@@ -0,0 +1,119 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:27:47
+ * Description: 暂无
+ ***********************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using CoreCms.Net.Caching.Manual;
+using CoreCms.Net.Configuration;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.ViewModels.Basics;
+using CoreCms.Net.IRepository;
+using CoreCms.Net.IRepository.UnitOfWork;
+using CoreCms.Net.Model.ViewModels.UI;
+using SqlSugar;
+
+namespace CoreCms.Net.Repository
+{
+ ///
+ /// 用户操作日志 接口实现
+ ///
+ public class SysUserOperationLogRepository : BaseRepository, ISysUserOperationLogRepository
+ {
+ private readonly IUnitOfWork _unitOfWork;
+ public SysUserOperationLogRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
+ {
+ _unitOfWork = unitOfWork;
+ }
+
+ #region 重写根据条件查询分页数据
+ ///
+ /// 重写根据条件查询分页数据
+ ///
+ /// 判断集合
+ /// 排序方式
+ /// 当前页面索引
+ /// 分布大小
+ ///
+ /// 是否使用WITH(NOLOCK)
+ ///
+ public new async Task> QueryPageAsync(Expression> predicate,
+ Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1,
+ int pageSize = 20, bool blUseNoLock = false)
+ {
+ RefAsync totalCount = 0;
+ List page;
+ if (blUseNoLock)
+ {
+ page = await DbClient.Queryable()
+ .OrderByIF(orderByExpression != null, orderByExpression, orderByType)
+ .WhereIF(predicate != null, predicate).Select(p => new SysUserOperationLog
+ {
+ id = p.id,
+ userName = p.userName,
+ userNickName = p.userNickName,
+ userId = p.userId,
+ ip = p.ip,
+ apiPath = p.apiPath,
+ beginTime = p.beginTime,
+ endTime = p.endTime,
+ opTime = p.opTime,
+ requestMethod = p.requestMethod,
+ //requestData = p.requestData,
+ //responseBodyData = p.responseBodyData,
+ agent = p.agent,
+ actionName = p.actionName,
+ actionDescription = p.actionDescription,
+ controllerName = p.controllerName,
+ controllerDescription = p.controllerDescription,
+ statusCode = p.statusCode,
+ createTime = p.createTime,
+ dataSources = p.dataSources,
+
+ }).With(SqlWith.NoLock).ToPageListAsync(pageIndex, pageSize, totalCount);
+ }
+ else
+ {
+ page = await DbClient.Queryable()
+ .OrderByIF(orderByExpression != null, orderByExpression, orderByType)
+ .WhereIF(predicate != null, predicate).Select(p => new SysUserOperationLog
+ {
+ id = p.id,
+ userName = p.userName,
+ userNickName = p.userNickName,
+ userId = p.userId,
+ ip = p.ip,
+ apiPath = p.apiPath,
+ beginTime = p.beginTime,
+ endTime = p.endTime,
+ opTime = p.opTime,
+ requestMethod = p.requestMethod,
+ //requestData = p.requestData,
+ //responseBodyData = p.responseBodyData,
+ agent = p.agent,
+ actionName = p.actionName,
+ actionDescription = p.actionDescription,
+ controllerName = p.controllerName,
+ controllerDescription = p.controllerDescription,
+ statusCode = p.statusCode,
+ createTime = p.createTime,
+ dataSources = p.dataSources,
+
+ }).ToPageListAsync(pageIndex, pageSize, totalCount);
+ }
+ var list = new PageList(page, pageIndex, pageSize, totalCount);
+ return list;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/CoreCms.Net.Services/System/SysUserOperationLogServices.cs b/CoreCms.Net.Services/System/SysUserOperationLogServices.cs
new file mode 100644
index 00000000..fb4b7efe
--- /dev/null
+++ b/CoreCms.Net.Services/System/SysUserOperationLogServices.cs
@@ -0,0 +1,62 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:27:47
+ * Description: 暂无
+ ***********************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using CoreCms.Net.Configuration;
+using CoreCms.Net.IRepository;
+using CoreCms.Net.IRepository.UnitOfWork;
+using CoreCms.Net.IServices;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.ViewModels.Basics;
+using CoreCms.Net.Model.ViewModels.UI;
+using SqlSugar;
+
+
+namespace CoreCms.Net.Services
+{
+ ///
+ /// 用户操作日志 接口实现
+ ///
+ public class SysUserOperationLogServices : BaseServices, ISysUserOperationLogServices
+ {
+ private readonly ISysUserOperationLogRepository _dal;
+ private readonly IUnitOfWork _unitOfWork;
+
+ public SysUserOperationLogServices(IUnitOfWork unitOfWork, ISysUserOperationLogRepository dal)
+ {
+ this._dal = dal;
+ base.BaseDal = dal;
+ _unitOfWork = unitOfWork;
+ }
+
+ #region 重写根据条件查询分页数据
+ ///
+ /// 重写根据条件查询分页数据
+ ///
+ /// 判断集合
+ /// 排序方式
+ /// 当前页面索引
+ /// 分布大小
+ ///
+ /// 是否使用WITH(NOLOCK)
+ ///
+ public new async Task> QueryPageAsync(Expression> predicate,
+ Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1,
+ int pageSize = 20, bool blUseNoLock = false)
+ {
+ return await _dal.QueryPageAsync(predicate, orderByExpression, orderByType, pageIndex, pageSize, blUseNoLock);
+ }
+ #endregion
+
+ }
+}
diff --git a/CoreCms.Net.Web.Admin/Controllers/Com/ToolsController.cs b/CoreCms.Net.Web.Admin/Controllers/Com/ToolsController.cs
index 873db2c8..007437e4 100644
--- a/CoreCms.Net.Web.Admin/Controllers/Com/ToolsController.cs
+++ b/CoreCms.Net.Web.Admin/Controllers/Com/ToolsController.cs
@@ -345,7 +345,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
public AdminUiCallBack GetAllControllerAndActionByAssembly()
{
var jm = new AdminUiCallBack();
- var data = AdminsControllerPermission.GetAllControllerAndActionByAssembly();
+ var data = AdminsControllerPermission.GetCacheCoreCmsControllerPermission();
jm.data = data.OrderBy(u => u.name).ToList();
jm.code = 0;
jm.msg = "获取成功";
diff --git a/CoreCms.Net.Web.Admin/Controllers/System/SysUserOperationLogController.cs b/CoreCms.Net.Web.Admin/Controllers/System/SysUserOperationLogController.cs
new file mode 100644
index 00000000..f654fd4a
--- /dev/null
+++ b/CoreCms.Net.Web.Admin/Controllers/System/SysUserOperationLogController.cs
@@ -0,0 +1,350 @@
+/***********************************************************************
+ * Project: CoreCms
+ * ProjectName: 核心内容管理系统
+ * Web: https://www.corecms.net
+ * Author: 大灰灰
+ * Email: jianweie@163.com
+ * CreateTime: 2022/4/10 0:27:47
+ * Description: 暂无
+ ***********************************************************************/
+
+
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using CoreCms.Net.Configuration;
+using CoreCms.Net.Model.Entities;
+using CoreCms.Net.Model.Entities.Expression;
+using CoreCms.Net.Model.FromBody;
+using CoreCms.Net.Model.ViewModels.UI;
+using CoreCms.Net.Filter;
+using CoreCms.Net.Loging;
+using CoreCms.Net.IServices;
+using CoreCms.Net.Utility.Helper;
+using CoreCms.Net.Utility.Extensions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using NPOI.HSSF.UserModel;
+using SqlSugar;
+
+namespace CoreCms.Net.Web.Admin.Controllers
+{
+ ///
+ /// 用户操作日志
+ ///
+ [Description("用户操作日志")]
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [RequiredErrorForAdmin]
+ [Authorize]
+ public class SysUserOperationLogController : ControllerBase
+ {
+ private readonly IWebHostEnvironment _webHostEnvironment;
+ private readonly ISysUserOperationLogServices _sysUserOperationLogServices;
+
+ ///
+ /// 构造函数
+ ///
+ public SysUserOperationLogController(IWebHostEnvironment webHostEnvironment
+ ,ISysUserOperationLogServices sysUserOperationLogServices
+ )
+ {
+ _webHostEnvironment = webHostEnvironment;
+ _sysUserOperationLogServices = sysUserOperationLogServices;
+ }
+
+ #region 获取列表============================================================
+ // POST: Api/SysUserOperationLog/GetPageList
+ ///
+ /// 获取列表
+ ///
+ ///
+ [HttpPost]
+ [Description("获取列表")]
+ public async Task GetPageList()
+ {
+ var jm = new AdminUiCallBack();
+ var pageCurrent = Request.Form["page"].FirstOrDefault().ObjectToInt(1);
+ var pageSize = Request.Form["limit"].FirstOrDefault().ObjectToInt(30);
+ var where = PredicateBuilder.True();
+ //获取排序字段
+ var orderField = Request.Form["orderField"].FirstOrDefault();
+
+ Expression> orderEx = orderField switch
+ {
+ "id" => p => p.id,"userName" => p => p.userName,"userNickName" => p => p.userNickName,"userId" => p => p.userId,"ip" => p => p.ip,"apiPath" => p => p.apiPath,"beginTime" => p => p.beginTime,"endTime" => p => p.endTime,"opTime" => p => p.opTime,"requestMethod" => p => p.requestMethod,"requestData" => p => p.requestData,"responseBodyData" => p => p.responseBodyData,"agent" => p => p.agent,"actionName" => p => p.actionName,"actionDescription" => p => p.actionDescription,"controllerName" => p => p.controllerName,"controllerDescription" => p => p.controllerDescription,"statusCode" => p => p.statusCode,"createTime" => p => p.createTime,"dataSources" => p => p.dataSources,
+ _ => p => p.id
+ };
+
+ //设置排序方式
+ var orderDirection = Request.Form["orderDirection"].FirstOrDefault();
+ var orderBy = orderDirection switch
+ {
+ "asc" => OrderByType.Asc,
+ "desc" => OrderByType.Desc,
+ _ => OrderByType.Desc
+ };
+ //查询筛选
+
+ // int
+ var id = Request.Form["id"].FirstOrDefault().ObjectToInt(0);
+ if (id > 0)
+ {
+ where = where.And(p => p.id == id);
+ }
+ //用户登录账号 nvarchar
+ var userName = Request.Form["userName"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(userName))
+ {
+ where = where.And(p => p.userName.Contains(userName));
+ }
+ //用户登录昵称 nvarchar
+ var userNickName = Request.Form["userNickName"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(userNickName))
+ {
+ where = where.And(p => p.userNickName.Contains(userNickName));
+ }
+ //用户序列 nvarchar
+ var userId = Request.Form["userId"].FirstOrDefault().ObjectToInt(0);
+ if (userId > 0)
+ {
+ where = where.And(p => p.id == id);
+ }
+ //IP地址 nvarchar
+ var ip = Request.Form["ip"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(ip))
+ {
+ where = where.And(p => p.ip.Contains(ip));
+ }
+ //请求地址 nvarchar
+ var apiPath = Request.Form["apiPath"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(apiPath))
+ {
+ where = where.And(p => p.apiPath.Contains(apiPath));
+ }
+ //开始时间 datetime
+ var beginTime = Request.Form["beginTime"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(beginTime))
+ {
+ if (beginTime.Contains("到"))
+ {
+ var dts = beginTime.Split("到");
+ var dtStart = dts[0].Trim().ObjectToDate();
+ where = where.And(p => p.beginTime > dtStart);
+ var dtEnd = dts[1].Trim().ObjectToDate();
+ where = where.And(p => p.beginTime < dtEnd);
+ }
+ else
+ {
+ var dt = beginTime.ObjectToDate();
+ where = where.And(p => p.beginTime > dt);
+ }
+ }
+ //结束时间 datetime
+ var endTime = Request.Form["endTime"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(endTime))
+ {
+ if (endTime.Contains("到"))
+ {
+ var dts = endTime.Split("到");
+ var dtStart = dts[0].Trim().ObjectToDate();
+ where = where.And(p => p.endTime > dtStart);
+ var dtEnd = dts[1].Trim().ObjectToDate();
+ where = where.And(p => p.endTime < dtEnd);
+ }
+ else
+ {
+ var dt = endTime.ObjectToDate();
+ where = where.And(p => p.endTime > dt);
+ }
+ }
+ //耗时 nvarchar
+ var opTime = Request.Form["opTime"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(opTime))
+ {
+ where = where.And(p => p.opTime.Contains(opTime));
+ }
+ //请求方式 nvarchar
+ var requestMethod = Request.Form["requestMethod"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(requestMethod))
+ {
+ where = where.And(p => p.requestMethod.Contains(requestMethod));
+ }
+ //请求数据 nvarchar
+ var requestData = Request.Form["requestData"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(requestData))
+ {
+ where = where.And(p => p.requestData.Contains(requestData));
+ }
+ //返回数据 nvarchar
+ var responseBodyData = Request.Form["responseBodyData"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(responseBodyData))
+ {
+ where = where.And(p => p.responseBodyData.Contains(responseBodyData));
+ }
+ //代理渠道 nvarchar
+ var agent = Request.Form["agent"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(agent))
+ {
+ where = where.And(p => p.agent.Contains(agent));
+ }
+ //动作方法名称 nvarchar
+ var actionName = Request.Form["actionName"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(actionName))
+ {
+ where = where.And(p => p.actionName.Contains(actionName));
+ }
+ //动作方法描述 nvarchar
+ var actionDescription = Request.Form["actionDescription"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(actionDescription))
+ {
+ where = where.And(p => p.actionDescription.Contains(actionDescription));
+ }
+ //控制器名称 nvarchar
+ var controllerName = Request.Form["controllerName"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(controllerName))
+ {
+ where = where.And(p => p.controllerName.Contains(controllerName));
+ }
+ //控制器名称 nvarchar
+ var controllerDescription = Request.Form["controllerDescription"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(controllerDescription))
+ {
+ where = where.And(p => p.controllerDescription.Contains(controllerDescription));
+ }
+ //状态码 int
+ var statusCode = Request.Form["statusCode"].FirstOrDefault().ObjectToInt(0);
+ if (statusCode > 0)
+ {
+ where = where.And(p => p.statusCode == statusCode);
+ }
+ //创建时间 datetime
+ var createTime = Request.Form["createTime"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(createTime))
+ {
+ if (createTime.Contains("到"))
+ {
+ var dts = createTime.Split("到");
+ var dtStart = dts[0].Trim().ObjectToDate();
+ where = where.And(p => p.createTime > dtStart);
+ var dtEnd = dts[1].Trim().ObjectToDate();
+ where = where.And(p => p.createTime < dtEnd);
+ }
+ else
+ {
+ var dt = createTime.ObjectToDate();
+ where = where.And(p => p.createTime > dt);
+ }
+ }
+ //数据来源 nvarchar
+ var dataSources = Request.Form["dataSources"].FirstOrDefault();
+ if (!string.IsNullOrEmpty(dataSources))
+ {
+ where = where.And(p => p.dataSources.Contains(dataSources));
+ }
+ //获取数据
+ var list = await _sysUserOperationLogServices.QueryPageAsync(where, orderEx, orderBy, pageCurrent, pageSize, true);
+ //返回数据
+ jm.data = list;
+ jm.code = 0;
+ jm.count = list.TotalCount;
+ jm.msg = "数据调用成功!";
+ return jm;
+ }
+ #endregion
+
+ #region 首页数据============================================================
+ // POST: Api/SysUserOperationLog/GetIndex
+ ///
+ /// 首页数据
+ ///
+ ///
+ [HttpPost]
+ [Description("首页数据")]
+ public AdminUiCallBack GetIndex()
+ {
+ //返回数据
+ var jm = new AdminUiCallBack { code = 0 };
+ return jm;
+ }
+ #endregion
+
+ #region 删除数据============================================================
+ // POST: Api/SysUserOperationLog/DoDelete/10
+ ///
+ /// 单选删除
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Description("单选删除")]
+ public async Task DoDelete([FromBody]FMIntId entity)
+ {
+ var jm = new AdminUiCallBack();
+
+ var model = await _sysUserOperationLogServices.ExistsAsync(p => p.id == entity.id, true);
+ if (!model)
+ {
+ jm.msg = GlobalConstVars.DataisNo;
+ return jm;
+ }
+ var bl = await _sysUserOperationLogServices.DeleteByIdAsync(entity.id);
+ jm.code = bl ? 0 : 1;
+ jm.msg = bl ? GlobalConstVars.DeleteSuccess : GlobalConstVars.DeleteFailure;
+ return jm;
+ }
+ #endregion
+
+ #region 批量删除============================================================
+ // POST: Api/SysUserOperationLog/DoBatchDelete/10,11,20
+ ///
+ /// 批量删除
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Description("批量删除")]
+ public async Task DoBatchDelete([FromBody]FMArrayIntIds entity)
+ {
+ var jm = new AdminUiCallBack();
+
+ var bl = await _sysUserOperationLogServices.DeleteByIdsAsync(entity.id);
+ jm.code = bl ? 0 : 1;
+ jm.msg = bl ? GlobalConstVars.DeleteSuccess : GlobalConstVars.DeleteFailure;
+ return jm;
+ }
+
+ #endregion
+
+ #region 预览数据============================================================
+ // POST: Api/SysUserOperationLog/GetDetails/10
+ ///
+ /// 预览数据
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Description("预览数据")]
+ public async Task GetDetails([FromBody]FMIntId entity)
+ {
+ var jm = new AdminUiCallBack();
+
+ var model = await _sysUserOperationLogServices.QueryByIdAsync(entity.id, false);
+ if (model == null)
+ {
+ jm.msg = "不存在此信息";
+ return jm;
+ }
+ jm.code = 0;
+ jm.data = model;
+
+ return jm;
+ }
+ #endregion
+
+ }
+}
diff --git a/CoreCms.Net.Web.Admin/Startup.cs b/CoreCms.Net.Web.Admin/Startup.cs
index 30525909..b6138e72 100644
--- a/CoreCms.Net.Web.Admin/Startup.cs
+++ b/CoreCms.Net.Web.Admin/Startup.cs
@@ -174,7 +174,7 @@ namespace CoreCms.Net.Web.Admin
// ¼뷵 (עȨޣȻд)
app.UseRequestResponseLog();
// ûʼ¼(ŵ㣬Ȼ쳣ᱨΪܷ)(עȨޣȻд)
- app.UseRecordAccessLogsMildd();
+ app.UseRecordAccessLogsMildd(GlobalEnumVars.CoreShopSystemCategory.Admin.ToString());
// ¼ip (עȨޣȻд)
app.UseIpLogMildd();
// signalr
diff --git a/CoreCms.Net.Web.Admin/appsettings.json b/CoreCms.Net.Web.Admin/appsettings.json
index 79cc340c..9aae3722 100644
--- a/CoreCms.Net.Web.Admin/appsettings.json
+++ b/CoreCms.Net.Web.Admin/appsettings.json
@@ -46,8 +46,10 @@
},
//记录用户方访问数据
"RecordAccessLogs": {
- "Enabled": false,
- "IgnoreApis": "/api/Home/GetNav,/api/Home/GetIds4Users"
+ "Enabled": true, //是否开启记录操作日志功能。
+ "EnabledFileMode": false, //是否开启记录到文件功能。(影响效率,接口不建议开启)
+ "EnabledDbMode": true, //是否开启记录到数据库模式。(影响效率,接口不建议开启)
+ "IgnoreApis": "/api/tools/getuserinfo,/api/tools/getNavs,/api/CodeGenerator/CodeGenDown" //使用小写逗号分隔
},
//记录IP请求数据
"IPLog": {
diff --git a/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/details.html b/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/details.html
new file mode 100644
index 00000000..3d27b00c
--- /dev/null
+++ b/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/details.html
@@ -0,0 +1,207 @@
+
+
\ No newline at end of file
diff --git a/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/index.html b/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/index.html
new file mode 100644
index 00000000..cef9d48f
--- /dev/null
+++ b/CoreCms.Net.Web.Admin/wwwroot/views/system/sysuseroperationlog/index.html
@@ -0,0 +1,247 @@
+用户操作日志
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CoreCms.Net.Web.WebApi/Controllers/AgentController.cs b/CoreCms.Net.Web.WebApi/Controllers/AgentController.cs
index 37bbbf17..e842b021 100644
--- a/CoreCms.Net.Web.WebApi/Controllers/AgentController.cs
+++ b/CoreCms.Net.Web.WebApi/Controllers/AgentController.cs
@@ -278,10 +278,10 @@ namespace CoreCms.Net.Web.WebApi.Controllers
jm.status = true;
jm.data = new
{
- count = first + second,
+ count = first + monthFirst,
first,
second,
- monthCount = monthFirst + monthSecond,
+ monthCount = second + monthSecond,
monthFirst,
monthSecond
};
diff --git a/CoreCms.Net.Web.WebApi/Startup.cs b/CoreCms.Net.Web.WebApi/Startup.cs
index c83893a1..c6268658 100644
--- a/CoreCms.Net.Web.WebApi/Startup.cs
+++ b/CoreCms.Net.Web.WebApi/Startup.cs
@@ -181,7 +181,7 @@ namespace CoreCms.Net.Web.WebApi
// ¼뷵 (עȨޣȻд)
app.UseRequestResponseLog();
// ûʼ¼(ŵ㣬Ȼ쳣ᱨΪܷ)(עȨޣȻд)
- app.UseRecordAccessLogsMildd();
+ app.UseRecordAccessLogsMildd(GlobalEnumVars.CoreShopSystemCategory.Api.ToString());
// ¼ip (עȨޣȻд)
app.UseIpLogMildd();
diff --git a/CoreCms.Net.Web.WebApi/appsettings.json b/CoreCms.Net.Web.WebApi/appsettings.json
index 79cc340c..0a7c0094 100644
--- a/CoreCms.Net.Web.WebApi/appsettings.json
+++ b/CoreCms.Net.Web.WebApi/appsettings.json
@@ -46,8 +46,10 @@
},
//记录用户方访问数据
"RecordAccessLogs": {
- "Enabled": false,
- "IgnoreApis": "/api/Home/GetNav,/api/Home/GetIds4Users"
+ "Enabled": true, //是否开启记录操作日志功能。
+ "EnabledFileMode": false, //是否开启记录到文件功能。(影响效率,接口不建议开启)
+ "EnabledDbMode": false, //是否开启记录到数据库模式。(影响效率,接口不建议开启)
+ "IgnoreApis": "/api/tools/getuserinfo,/api/tools/getNavs,/api/CodeGenerator/CodeGenDown" //使用小写逗号分隔
},
//记录IP请求数据
"IPLog": {
diff --git a/数据库/MySql/20220410/1、创建表SysUserOperationLog.sql b/数据库/MySql/20220410/1、创建表SysUserOperationLog.sql
new file mode 100644
index 00000000..f9eafbab
--- /dev/null
+++ b/数据库/MySql/20220410/1、创建表SysUserOperationLog.sql
@@ -0,0 +1,52 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : rm-wz92918pm46bsbc37mo.mysql.rds.aliyuncs.com
+ Source Server Type : MySQL
+ Source Server Version : 50732
+ Source Host : rm-wz92918pm46bsbc37mo.mysql.rds.aliyuncs.com:3306
+ Source Schema : coreshop
+
+ Target Server Type : MySQL
+ Target Server Version : 50732
+ File Encoding : 65001
+
+ Date: 10/04/2022 02:24:03
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for SysUserOperationLog
+-- ----------------------------
+DROP TABLE IF EXISTS `SysUserOperationLog`;
+CREATE TABLE `SysUserOperationLog` (
+ `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '序列',
+ `userName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户登录账号',
+ `userNickName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户登录昵称',
+ `userId` int(11) NULL DEFAULT NULL COMMENT '用户序列',
+ `ip` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'IP地址',
+ `apiPath` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求地址',
+ `beginTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '开始时间',
+ `endTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '结束时间',
+ `opTime` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '耗时',
+ `requestMethod` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求方式',
+ `requestData` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求数据',
+ `responseBodyData` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '返回数据',
+ `agent` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '代理渠道',
+ `actionName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '动作方法名称',
+ `actionDescription` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '动作方法描述',
+ `controllerName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '控制器名称',
+ `controllerDescription` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '控制器名称',
+ `statusCode` int(11) NULL DEFAULT NULL COMMENT '状态码',
+ `createTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
+ `dataSources` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据来源',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of SysUserOperationLog
+-- ----------------------------
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/数据库/MySql/20220410/2、添加菜单.sql b/数据库/MySql/20220410/2、添加菜单.sql
new file mode 100644
index 00000000..803d316b
--- /dev/null
+++ b/数据库/MySql/20220410/2、添加菜单.sql
@@ -0,0 +1,24 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Schema : coreshop
+
+ Target Server Type : MySQL
+ Target Server Version : 50732
+ File Encoding : 65001
+
+ Date: 10/04/2022 02:25:27
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+-- ----------------------------
+-- Records of SysMenu
+-- ----------------------------
+INSERT INTO `SysMenu` VALUES (1381, 111, 'sysuseroperationlog', '用户操作日志', '', 'system/sysuseroperationlog/index', '', 0, 400, '', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+INSERT INTO `SysMenu` VALUES (1382, 111, 'GetPageList', '获取列表', NULL, NULL, '/Api/SysUserOperationLog/GetPageList', 1, 0, 'SysUserOperationLog:GetPageList', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+INSERT INTO `SysMenu` VALUES (1383, 111, 'GetIndex', '首页数据', NULL, NULL, '/Api/SysUserOperationLog/GetIndex', 1, 1, 'SysUserOperationLog:GetIndex', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+INSERT INTO `SysMenu` VALUES (1384, 111, 'DoDelete', '单选删除', NULL, NULL, '/Api/SysUserOperationLog/DoDelete', 1, 2, 'SysUserOperationLog:DoDelete', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+INSERT INTO `SysMenu` VALUES (1385, 111, 'DoBatchDelete', '批量删除', NULL, NULL, '/Api/SysUserOperationLog/DoBatchDelete', 1, 3, 'SysUserOperationLog:DoBatchDelete', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+INSERT INTO `SysMenu` VALUES (1386, 111, 'GetDetails', '预览数据', NULL, NULL, '/Api/SysUserOperationLog/GetDetails', 1, 4, 'SysUserOperationLog:GetDetails', NULL, NULL, 0, 0, '2022-04-10 02:06:29', NULL);
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/数据库/MySql/20220410/coreshop完整数据库脚本.rar b/数据库/MySql/20220410/coreshop完整数据库脚本.rar
new file mode 100644
index 00000000..cf7ac07f
Binary files /dev/null and b/数据库/MySql/20220410/coreshop完整数据库脚本.rar differ
diff --git a/数据库/MySql/数据库更新日志.txt b/数据库/MySql/数据库更新日志.txt
index b6d4b224..35375b68 100644
--- a/数据库/MySql/数据库更新日志.txt
+++ b/数据库/MySql/数据库更新日志.txt
@@ -1,3 +1,6 @@
+2022-04-10
+【新增】表【SysUserOperationLog】用户操作日志记录
+
2022-03-29
【新增】表【CoreCmsInvoice】 新增 【fileUrl】发票下载地址字段
diff --git a/数据库/SqlServer/20220410/1、创建数据库脚本.sql b/数据库/SqlServer/20220410/1、创建数据库脚本.sql
new file mode 100644
index 00000000..bfb07aa9
--- /dev/null
+++ b/数据库/SqlServer/20220410/1、创建数据库脚本.sql
@@ -0,0 +1,105 @@
+/****** Object: Table [dbo].[SysUserOperationLog] Script Date: 2022/4/10 2:03:44 ******/
+SET ANSI_NULLS ON
+GO
+
+SET QUOTED_IDENTIFIER ON
+GO
+
+CREATE TABLE [dbo].[SysUserOperationLog](
+ [id] [int] IDENTITY(1,1) NOT NULL,
+ [userName] [nvarchar](50) NULL,
+ [userNickName] [nvarchar](50) NULL,
+ [userId] [int] NOT NULL,
+ [ip] [nvarchar](150) NULL,
+ [apiPath] [nvarchar](150) NULL,
+ [beginTime] [datetime] NOT NULL,
+ [endTime] [datetime] NOT NULL,
+ [opTime] [nvarchar](50) NULL,
+ [requestMethod] [nvarchar](50) NULL,
+ [requestData] [nvarchar](max) NULL,
+ [responseBodyData] [nvarchar](max) NULL,
+ [agent] [nvarchar](1000) NULL,
+ [actionName] [nvarchar](50) NULL,
+ [actionDescription] [nvarchar](50) NULL,
+ [controllerName] [nvarchar](50) NULL,
+ [controllerDescription] [nvarchar](50) NULL,
+ [statusCode] [int] NOT NULL,
+ [createTime] [datetime] NOT NULL,
+ [dataSources] [nvarchar](50) NULL,
+ CONSTRAINT [PK_SysUserOperationLog] PRIMARY KEY CLUSTERED
+(
+ [id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[SysUserOperationLog] ADD CONSTRAINT [DF_SysUserOperationLog_userId] DEFAULT ((0)) FOR [userId]
+GO
+
+ALTER TABLE [dbo].[SysUserOperationLog] ADD CONSTRAINT [DF_SysUserOperationLog_statusCode] DEFAULT ((0)) FOR [statusCode]
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'id'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'û¼˺' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'userName'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'û¼dz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'userNickName'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'û' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'userId'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'IPַ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'ip'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ַ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'apiPath'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʼʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'beginTime'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'endTime'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'opTime'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʽ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'requestMethod'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'requestData'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'responseBodyData'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'agent'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'actionName'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'actionDescription'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'controllerName'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'controllerDescription'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'״̬' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'statusCode'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'createTime'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Դ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog', @level2type=N'COLUMN',@level2name=N'dataSources'
+GO
+
+EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'û־' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'SysUserOperationLog'
+GO
+
+
diff --git a/数据库/SqlServer/20220410/20220410完整数据库带演示商品.rar b/数据库/SqlServer/20220410/20220410完整数据库带演示商品.rar
new file mode 100644
index 00000000..bd3388fb
Binary files /dev/null and b/数据库/SqlServer/20220410/20220410完整数据库带演示商品.rar differ
diff --git a/数据库/SqlServer/20220410/2、添加菜单脚本.sql b/数据库/SqlServer/20220410/2、添加菜单脚本.sql
new file mode 100644
index 00000000..95551718
Binary files /dev/null and b/数据库/SqlServer/20220410/2、添加菜单脚本.sql differ
diff --git a/数据库/SqlServer/数据库更新日志.txt b/数据库/SqlServer/数据库更新日志.txt
index 0091b255..605569c5 100644
--- a/数据库/SqlServer/数据库更新日志.txt
+++ b/数据库/SqlServer/数据库更新日志.txt
@@ -1,3 +1,6 @@
+2022-04-10
+【新增】表【SysUserOperationLog】用户操作日志记录
+
2022-03-29
【新增】表【CoreCmsInvoice】 新增 【fileUrl】发票下载地址字段