feat: 增加访问日志查询界面功能

This commit is contained in:
Argo-Tianyi 2022-01-17 19:08:40 +08:00
parent 7fd4a83b52
commit df6098f1dc
10 changed files with 299 additions and 7 deletions

View File

@ -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>

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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; }
}

View File

@ -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>

View File

@ -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; }
}
}

View File

@ -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
};
}
}

View File

@ -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>

View File

@ -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);
}
}

View File

@ -91,6 +91,7 @@ namespace BootstrapAdmin.Web.Shared
{
_ = Task.Run(async () =>
{
// TODO: 可考虑加入队列中,通过任务管理定时插入提高效率
var clientInfo = await WebClientService.GetClientInfo();
TraceService.Log(new Trace
{