feat: 增加访问日志查询界面功能
This commit is contained in:
parent
7fd4a83b52
commit
df6098f1dc
|
@ -1,4 +1,7 @@
|
|||
namespace BootstrapAdmin.DataAccess.Models;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -13,36 +16,43 @@ public class Trace
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "登录用户")]
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "操作时间")]
|
||||
public DateTime LogTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "登录主机")]
|
||||
public string? Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "浏览器")]
|
||||
public string? Browser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "操作系统")]
|
||||
public string? OS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "操作地点")]
|
||||
public string? City { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Display(Name = "操作页面")]
|
||||
public string? RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,4 +22,52 @@ class TraceService : ITrace
|
|||
{
|
||||
Database.Insert(trace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageItems"></param>
|
||||
/// <param name="sortList"></param>
|
||||
/// <returns></returns>
|
||||
public (IEnumerable<Trace> Items, int ItemsCount) GetAll(string? searchText, TraceFilter filter, int pageIndex, int pageItems, List<string> sortList)
|
||||
{
|
||||
var sql = new Sql();
|
||||
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
sql.Where("UserName Like @0 or Ip Like @0 or RequestUrl Like @0", $"%{searchText}%");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.UserName))
|
||||
{
|
||||
sql.Where("UserName Like @0", $"%{filter.UserName}%");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.Ip))
|
||||
{
|
||||
sql.Where("Ip Like @0", $"%{filter.Ip}%");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.RequestUrl))
|
||||
{
|
||||
sql.Where("ErrorPage Like @0", $"%{filter.RequestUrl}%");
|
||||
}
|
||||
|
||||
sql.Where("LogTime >= @0 and LogTime <= @1", filter.Star, filter.End);
|
||||
|
||||
if (sortList.Any())
|
||||
{
|
||||
sql.OrderBy(string.Join(", ", sortList));
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.OrderBy("Logtime desc");
|
||||
}
|
||||
|
||||
var data = Database.Page<Trace>(pageIndex, pageItems, sql);
|
||||
return (data.Items, Convert.ToInt32(data.TotalItems));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,15 @@ public interface ITrace
|
|||
/// </summary>
|
||||
/// <param name="trace"></param>
|
||||
public void Log(Trace trace);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageItems"></param>
|
||||
/// <param name="sortList"></param>
|
||||
/// <returns></returns>
|
||||
(IEnumerable<Trace> Items, int ItemsCount) GetAll(string? searchText, TraceFilter filter, int pageIndex, int pageItems, List<string> sortList);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
namespace BootstrapAdmin.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class TraceFilter
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime Star { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? Ip { get; set; }
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<div class="row g-3 form-inline">
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.UserName" ShowLabel="true" />
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<DateTimeRange @bind-Value="Value.LogTime" ShowLabel="true" AllowNull="false" />
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.Ip" ShowLabel="true" />
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.RequestUrl" ShowLabel="true" />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
using BootstrapAdmin.Web.Models;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class TraceSearch
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public TraceSearchModel? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<TraceSearchModel> ValueChanged { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using BootstrapAdmin.DataAccess.Models;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BootstrapAdmin.Web.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 访问日志自定义高级搜索模型
|
||||
/// </summary>
|
||||
public class TraceSearchModel : ITableSearchModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 登录用户
|
||||
/// </summary>
|
||||
[Display(Name = "登录用户")]
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 操作时间
|
||||
/// </summary>
|
||||
[Display(Name = "操作时间")]
|
||||
[NotNull]
|
||||
public DateTimeRangeValue? LogTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 登录主机
|
||||
/// </summary>
|
||||
[Display(Name = "登录主机")]
|
||||
public string? Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 请求网址
|
||||
/// </summary>
|
||||
[Display(Name = "请求网址")]
|
||||
public string? RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TraceSearchModel()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IFilterAction> GetSearchs()
|
||||
{
|
||||
var ret = new List<IFilterAction>();
|
||||
|
||||
if (!string.IsNullOrEmpty(UserName))
|
||||
{
|
||||
ret.Add(new SearchFilterAction(nameof(Trace.UserName), UserName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RequestUrl))
|
||||
{
|
||||
ret.Add(new SearchFilterAction(nameof(Trace.RequestUrl), RequestUrl));
|
||||
}
|
||||
|
||||
if (LogTime != null)
|
||||
{
|
||||
ret.Add(new SearchFilterAction(nameof(Trace.LogTime), LogTime.Start, FilterAction.GreaterThanOrEqual));
|
||||
ret.Add(new SearchFilterAction(nameof(Trace.LogTime), LogTime.End, FilterAction.LessThanOrEqual));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Ip))
|
||||
{
|
||||
ret.Add(new SearchFilterAction(nameof(Trace.Ip), Ip));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void Reset()
|
||||
{
|
||||
UserName = null;
|
||||
RequestUrl = null;
|
||||
Ip = null;
|
||||
LogTime = new DateTimeRangeValue
|
||||
{
|
||||
Start = DateTime.Now.AddDays(-7),
|
||||
End = DateTime.Now
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,7 +1,21 @@
|
|||
@page "/admin/traces"
|
||||
|
||||
<h3>Traces</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
<AdminTable TItem="DataAccess.Models.Trace" IsPagination="true" PageItemsSource="PageItemsSource" SortList="SortList"
|
||||
ShowDefaultButtons="false" ShowExtendButtons="false" CustomerSearchModel="TraceSearchModel"
|
||||
OnQueryAsync="OnQueryAsync">
|
||||
<TableColumns>
|
||||
<TableColumn @bind-Field="context.UserName" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.LogTime" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.Ip" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.City" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.Browser" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.OS" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
<TableColumn @bind-Field="context.RequestUrl" Filterable="true" Searchable="true" Sortable="true"></TableColumn>
|
||||
</TableColumns>
|
||||
<CustomerSearchTemplate>
|
||||
@if (context is TraceSearchModel searchModel)
|
||||
{
|
||||
<TraceSearch @bind-Value="@searchModel"></TraceSearch>
|
||||
}
|
||||
</CustomerSearchTemplate>
|
||||
</AdminTable>
|
||||
|
|
|
@ -1,8 +1,56 @@
|
|||
namespace BootstrapAdmin.Web.Pages.Admin;
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Models;
|
||||
|
||||
namespace BootstrapAdmin.Web.Pages.Admin;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class Traces
|
||||
{
|
||||
private List<int> PageItemsSource { get; } = new List<int> { 20, 40, 80, 100, 200 };
|
||||
|
||||
private TraceSearchModel TraceSearchModel { get; set; } = new();
|
||||
|
||||
private List<string> SortList { get; } = new() { "LogTime desc" };
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ITrace? TraceService { get; set; }
|
||||
|
||||
private Task<QueryData<Trace>> OnQueryAsync(QueryPageOptions options)
|
||||
{
|
||||
var ret = new QueryData<Trace>()
|
||||
{
|
||||
IsSorted = true,
|
||||
IsFiltered = true,
|
||||
IsSearch = true
|
||||
};
|
||||
|
||||
var filter = new TraceFilter
|
||||
{
|
||||
UserName = TraceSearchModel.UserName,
|
||||
RequestUrl = TraceSearchModel.RequestUrl,
|
||||
Ip = TraceSearchModel.Ip,
|
||||
Star = TraceSearchModel.LogTime.Start,
|
||||
End = TraceSearchModel.LogTime.End,
|
||||
};
|
||||
|
||||
var sortList = new List<string>();
|
||||
if (options.SortOrder != SortOrder.Unset && !string.IsNullOrEmpty(options.SortName))
|
||||
{
|
||||
sortList.Add($"{options.SortName} {options.SortOrder}");
|
||||
}
|
||||
else if (options.SortList != null)
|
||||
{
|
||||
sortList.AddRange(options.SortList);
|
||||
}
|
||||
var (Items, ItemsCount) = TraceService.GetAll(options.SearchText, filter, options.PageIndex, options.PageItems, sortList);
|
||||
|
||||
ret.TotalCount = ItemsCount;
|
||||
ret.Items = Items;
|
||||
ret.IsAdvanceSearch = true;
|
||||
return Task.FromResult(ret);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ namespace BootstrapAdmin.Web.Shared
|
|||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
// TODO: 可考虑加入队列中,通过任务管理定时插入提高效率
|
||||
var clientInfo = await WebClientService.GetClientInfo();
|
||||
TraceService.Log(new Trace
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue