feat(#IWOOT): 增加网站分析页面

#Comment
comment #IWOOT

#Issue
close https://gitee.com/LongbowEnterprise/dashboard/issues?id=IWOOT
This commit is contained in:
Argo Zhang 2019-05-25 14:52:14 +08:00
parent 0587bf6bde
commit 471aee2938
29 changed files with 50496 additions and 23 deletions

Binary file not shown.

View File

@ -128,6 +128,12 @@ namespace Bootstrap.Admin.Controllers
/// <returns></returns>
public ActionResult Online() => View(new NavigatorBarModel(this));
/// <summary>
/// 网站分析统计
/// </summary>
/// <returns></returns>
public ActionResult Analyse() => View(new NavigatorBarModel(this));
/// <summary>
/// 用于测试ExceptionFilter
/// </summary>

View File

@ -0,0 +1,76 @@
using Bootstrap.DataAccess;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Bootstrap.Admin.Controllers.Api
{
/// <summary>
///
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class AnalyseController : ControllerBase
{
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet()]
public ActionResult<AnalyseData> Get([FromQuery]string logType)
{
var ret = new AnalyseData();
if (logType.Equals("LoginUsers", StringComparison.OrdinalIgnoreCase))
{
var loginUsers = LoginHelper.RetrieveAll(null, null, null);
var temp = loginUsers.GroupBy(usr => usr.LoginTime.ToString("yyyy-MM-dd"));
var max = temp.Any() ? temp.Max(g => g.Count()) : 1;
ret.Polylines = temp.Select((g, index) =>
{
ret.Datas.Add(new KeyValuePair<string, string>(g.Key, g.Count().ToString()));
return $"{index * 2},{Math.Round(g.Count() * 28.0 / max, 2)}";
});
}
if (logType.Equals("trace", StringComparison.OrdinalIgnoreCase))
{
var loginUsers = TraceHelper.RetrieveAll(null, null, null);
var temp = loginUsers.GroupBy(usr => usr.LogTime.ToString("yyyy-MM-dd"));
var max = temp.Any() ? temp.Max(g => g.Count()) : 1;
ret.Polylines = temp.Select((g, index) =>
{
ret.Datas.Add(new KeyValuePair<string, string>(g.Key, g.Count().ToString()));
return $"{index * 5},{Math.Round(g.Count() * 28.0 / max, 2)}";
});
}
if (logType.Equals("log", StringComparison.OrdinalIgnoreCase))
{
var loginUsers = LogHelper.RetrieveAll(null, null, null);
var temp = loginUsers.GroupBy(usr => usr.LogTime.ToString("yyyy-MM-dd"));
var max = temp.Any() ? temp.Max(g => g.Count()) : 1;
ret.Polylines = temp.Select((g, index) =>
{
ret.Datas.Add(new KeyValuePair<string, string>(g.Key, g.Count().ToString()));
return $"{index * 5},{Math.Round(g.Count() * 28.0 / max, 2)}";
});
}
return ret;
}
/// <summary>
///
/// </summary>
public class AnalyseData
{
/// <summary>
///
/// </summary>
public IEnumerable<string> Polylines { get; set; }
/// <summary>
///
/// </summary>
public List<KeyValuePair<string, string>> Datas { get; set; } = new List<KeyValuePair<string, string>>();
}
}
}

View File

@ -30,7 +30,7 @@ namespace Bootstrap.Admin.Query
/// <returns></returns>
public QueryData<Log> RetrieveData()
{
var data = LogHelper.Retrieves(this, OperateTimeStart, OperateTimeEnd, OperateType);
var data = LogHelper.RetrievePages(this, OperateTimeStart, OperateTimeEnd, OperateType);
var ret = new QueryData<Log>();
ret.total = data.TotalItems;
ret.rows = data.Items;

View File

@ -30,6 +30,7 @@ namespace Bootstrap.Admin.Query
/// <returns></returns>
public QueryData<LoginUser> RetrieveData()
{
if (string.IsNullOrEmpty(Order)) Order = "LoginTime desc";
var data = LoginHelper.RetrievePages(this, StartTime, EndTime, LoginIP);
return new QueryData<LoginUser>
{

View File

@ -0,0 +1,106 @@
@model NavigatorBarModel
@{
ViewBag.Title = "网站分析";
}
@section css {
<environment include="Development">
<link href="~/lib/datetimepicker/css//bootstrap-datetimepicker.css" rel="stylesheet" />
<link href="~/lib/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link href="~/lib/datetimepicker/css//bootstrap-datetimepicker.min.css" rel="stylesheet" />
<link href="~/lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
</environment>
<style>
.card .card-body {
padding-bottom: 15px;
}
.spark {
position: absolute;
}
</style>
}
@section javascript {
<environment include="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
<script src="~/lib/datetimepicker/js/bootstrap-datetimepicker.js"></script>
<script src="~/lib/echart/echarts-all.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.min.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="~/lib/datetimepicker/js/bootstrap-datetimepicker.min.js"></script>
<script src="~/lib/echart/echarts-all.min.js"></script>
</environment>
<script src="~/lib/datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js"></script>
<script src="~/js/analyse.js" asp-append-version="true"></script>
}
<div class="card d-none">
<div class="card-header">查询条件</div>
<div class="card-body">
<form class="form-inline">
<div class="row">
<div class="form-group col-sm-auto">
<label class="control-label" for="txt_operate_start">起始时间</label>
<div class="input-group date">
<input id="txt_operate_start" class="form-control" size="16" type="text" value="@DateTime.Today.ToString("yyyy-MM-dd")" readonly>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-times"></span></div>
</div>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-calendar"></span></div>
</div>
</div>
</div>
<div class="form-group col-sm-auto">
<label class="control-label" for="txt_operate_end">终止时间</label>
<div class="input-group date">
<input id="txt_operate_end" class="form-control" size="16" type="text" value="@DateTime.Today.ToString("yyyy-MM-dd")" readonly>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-times"></span></div>
</div>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-calendar"></span></div>
</div>
</div>
</div>
<div class="form-group col-sm-auto">
<label class="control-label" for="txt_ip">请求IP</label>
<input type="text" class="form-control" id="txt_ip" />
</div>
<div class="form-group col-sm-auto flex-md-fill justify-content-md-end">
<button type="button" id="btn_query" class="btn btn-primary btn-fill"><i class="fa fa-search" aria-hidden="true"></i><span>查询</span></button>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
操作日志
</div>
<div class="card-body">
<div id="log" class="spark"></div>
<div id="logChart" style="height: 200px"></div>
</div>
</div>
<div class="card">
<div class="card-header">
登录日志
</div>
<div class="card-body">
<div id="login" class="spark"></div>
<div id="loginChart" style="height: 200px"></div>
</div>
</div>
<div class="card">
<div class="card-header">
访问日志
</div>
<div class="card-body">
<div id="trace" class="spark"></div>
<div id="traceChart" style="height: 200px"></div>
</div>
</div>

View File

@ -0,0 +1,219 @@
(function ($) {
// sparkline component
'use strict';
var lgbSparkline = function (element, options) {
this.$element = $(element);
this.options = $.extend({}, lgbSparkline.DEFAULTS, options);
this.init();
};
lgbSparkline.VERSION = '1.0';
lgbSparkline.Author = 'argo@163.com';
lgbSparkline.DataKey = "lgb.sparkline";
lgbSparkline.Template = '<span class="d-inline-block tooltipped tooltipped-s" aria-label="Past year of activity">';
lgbSparkline.Template += '<svg width="155" height="30">';
lgbSparkline.Template += ' <defs>';
lgbSparkline.Template += ' <linearGradient id="{0}" x1="0" x2="0" y1="1" y2="0">';
lgbSparkline.Template += ' <stop offset="10%" stop-color="#c6e48b"></stop>';
lgbSparkline.Template += ' <stop offset="33%" stop-color="#7bc96f"></stop>';
lgbSparkline.Template += ' <stop offset="66%" stop-color="#239a3b"></stop>';
lgbSparkline.Template += ' <stop offset="90%" stop-color="#196127"></stop>';
lgbSparkline.Template += ' </linearGradient>';
lgbSparkline.Template += ' <mask id="{1}" x="0" y="0" width="155" height="28">';
lgbSparkline.Template += ' <polyline transform="translate(0, 28) scale(1,-1)" points="" fill="transparent" stroke="#8cc665" stroke-width="2">';
lgbSparkline.Template += ' </polyline>';
lgbSparkline.Template += ' </mask>';
lgbSparkline.Template += ' </defs>';
lgbSparkline.Template += ' <g transform="translate(0, 2.0)">';
lgbSparkline.Template += ' <rect x="0" y="-2" width="155" height="30" style="stroke: none; fill: url(#{0}); mask: url(#{1})"></rect>';
lgbSparkline.Template += ' </g>';
lgbSparkline.Template += '</svg>';
lgbSparkline.Template += '</span>';
lgbSparkline.AllowMethods = /val/;
function Plugin(option) {
var params = $.makeArray(arguments).slice(1);
return this.each(function () {
var $this = $(this);
var data = $this.data(lgbSparkline.DataKey);
var options = typeof option === 'object' && option;
if (!data) $this.data(lgbSparkline.DataKey, data = new lgbSparkline(this, options));
if (!lgbSparkline.AllowMethods.test(option)) return;
if (typeof option === 'string') {
data[option].apply(data, params);
}
});
}
$.fn.lgbSparkline = Plugin;
$.fn.lgbSparkline.Constructor = lgbSparkline;
var _proto = lgbSparkline.prototype;
_proto.init = function () {
var getUID = function (prefix) {
if (!prefix) prefix = 'lgb';
do prefix += ~~(Math.random() * 1000000);
while (document.getElementById(prefix));
return prefix;
};
var that = this;
var element = $.format(lgbSparkline.Template, getUID('gradient'), getUID('spark'))
this.$ctl = $(element).appendTo(this.$element);
};
_proto.val = function (val) {
this.$ctl.find('polyline').attr('points', val);
};
})(jQuery);
$(function () {
$.bc({
url: "api/Analyse?logType=LoginUsers",
callback: function (result) {
console.log(result);
$('#login').lgbSparkline('val', result.Polylines.join(' '));
var op = $.extend(true, {}, option, {
legend: { data: ["登录数量"] },
series: [
{
name: "登录数量",
data: result.Datas.map(function (val, index) {
return val.Value;
})
}
],
xAxis: [
{
data: result.Datas.map(function (val, index) {
return val.Key;
})
}
],
dataZoom: {
start: 50
}
});
var loginChart = echarts.init(document.getElementById('loginChart'));
loginChart.setOption(op);
}
});
$.bc({
url: "api/Analyse?logType=log",
callback: function (result) {
console.log(result);
$('#log').lgbSparkline('val', result.Polylines.join(' '));
var op = $.extend(true, {}, option, {
legend: { data: ["操作数量"] },
series: [
{
name: "操作数量",
data: result.Datas.map(function (val, index) {
return val.Value;
})
}
],
xAxis: [
{
data: result.Datas.map(function (val, index) {
return val.Key;
})
}
]
});
var logChart = echarts.init(document.getElementById('logChart'));
logChart.setOption(op);
}
});
$.bc({
url: "api/Analyse?logType=trace",
callback: function (result) {
console.log(result);
$('#trace').lgbSparkline('val', result.Polylines.join(' '));
var op = $.extend(true, {}, option, {
legend: { data: ["访问数量"] },
series: [
{
name: "访问数量",
data: result.Datas.map(function (val, index) {
return val.Value;
})
}
],
xAxis: [
{
data: result.Datas.map(function (val, index) {
return val.Key;
})
}
]
});
var traceChart = echarts.init(document.getElementById('traceChart'));
traceChart.setOption(op);
}
});
var option = {
title: {
text: '',
subtext: ''
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['日访问量']
},
toolbox: {
show: true,
feature: {
mark: { show: true },
dataZoom: { show: true },
dataView: { show: false },
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
calculable: true,
dataZoom: {
show: true,
realtime: true,
start: 0,
end: 100
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: function () {
var list = [];
for (var i = 1; i <= 30; i++) {
list.push('2013-03-' + i);
}
return list;
}()
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '日访问量',
type: 'line',
data: function () {
var list = [];
for (var i = 1; i <= 30; i++) {
list.push(Math.round(Math.random() * 30));
}
return list;
}()
}
]
};
});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
using MongoDB.Driver;
using PetaPoco;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Bootstrap.DataAccess.MongoDB
@ -19,7 +20,7 @@ namespace Bootstrap.DataAccess.MongoDB
/// <param name="endTime"></param>
/// <param name="opType"></param>
/// <returns></returns>
public override Page<DataAccess.Log> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string opType)
public override Page<DataAccess.Log> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string opType)
{
var filterBuilder = Builders<DataAccess.Log>.Filter;
var filter = filterBuilder.Empty;
@ -62,6 +63,26 @@ namespace Bootstrap.DataAccess.MongoDB
};
}
/// <summary>
///
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="opType"></param>
/// <returns></returns>
public override IEnumerable<DataAccess.Log> RetrieveAll(DateTime? startTime, DateTime? endTime, string opType)
{
var filterBuilder = Builders<DataAccess.Log>.Filter;
var filter = filterBuilder.Empty;
if (startTime.HasValue) filter = filterBuilder.Gte("LogTime", startTime.Value);
if (endTime.HasValue) filter = filterBuilder.Lt("LogTime", endTime.Value.AddDays(1).AddSeconds(-1));
if (!string.IsNullOrEmpty(opType)) filter = filterBuilder.Eq("CRUD", opType);
// sort
var sort = Builders<DataAccess.Log>.Sort.Ascending(t => t.LogTime);
return DbManager.Logs.Find(filter).Sort(sort).ToList();
}
/// <summary>
/// 删除日志信息
/// </summary>

View File

@ -30,7 +30,7 @@ namespace Bootstrap.DataAccess.MongoDB
/// <returns></returns>
public override Page<DataAccess.LoginUser> RetrieveByPages(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
{
var logs = Retrieves(startTime, endTime, ip);
var logs = RetrieveAll(startTime, endTime, ip);
return new Page<DataAccess.LoginUser>()
{
Context = logs,
@ -46,7 +46,7 @@ namespace Bootstrap.DataAccess.MongoDB
/// 获取所有登录数据
/// </summary>
/// <returns></returns>
public override IEnumerable<DataAccess.LoginUser> Retrieves(DateTime? startTime, DateTime? endTime, string ip)
public override IEnumerable<DataAccess.LoginUser> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
{
var filterBuilder = Builders<DataAccess.LoginUser>.Filter;
var filter = filterBuilder.Empty;
@ -56,7 +56,7 @@ namespace Bootstrap.DataAccess.MongoDB
return DbManager.LoginUsers
.Find(filter)
.Sort(Builders<DataAccess.LoginUser>.Sort.Descending(t => t.LoginTime)).ToList();
.Sort(Builders<DataAccess.LoginUser>.Sort.Ascending(t => t.LoginTime)).ToList();
}
}
}

View File

@ -2,6 +2,7 @@ using Longbow.Web.Mvc;
using MongoDB.Driver;
using PetaPoco;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Bootstrap.DataAccess.MongoDB
@ -15,7 +16,7 @@ namespace Bootstrap.DataAccess.MongoDB
///
/// </summary>
/// <returns></returns>
public override Page<DataAccess.Trace> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
public override Page<DataAccess.Trace> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
{
// filter
var filterBuilder = Builders<DataAccess.Trace>.Filter;
@ -65,6 +66,26 @@ namespace Bootstrap.DataAccess.MongoDB
};
}
/// <summary>
///
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="ip"></param>
/// <returns></returns>
public override IEnumerable<DataAccess.Trace> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
{
var filterBuilder = Builders<DataAccess.Trace>.Filter;
var filter = filterBuilder.Empty;
if (startTime.HasValue) filter = filterBuilder.Gt("LogTime", startTime.Value);
if (endTime.HasValue) filter = filterBuilder.Lt("LogTime", endTime.Value.AddDays(1).AddSeconds(-1));
if (!string.IsNullOrEmpty(ip)) filter = filterBuilder.Eq("Ip", ip);
// sort
var sort = Builders<DataAccess.Trace>.Sort.Ascending(t => t.LogTime);
return DbManager.Traces.Find(filter).Sort(sort).ToList();
}
/// <summary>
///
/// </summary>

View File

@ -2,6 +2,7 @@
using Longbow.Web.Mvc;
using PetaPoco;
using System;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@ -15,7 +16,13 @@ namespace Bootstrap.DataAccess
/// </summary>
/// <param name="op"></param>
/// <returns></returns>
public static Page<Log> Retrieves(PaginationOption op, DateTime? startTime, DateTime? endTime, string opType) => DbContextManager.Create<Log>().Retrieves(op, startTime, endTime, opType);
public static Page<Log> RetrievePages(PaginationOption op, DateTime? startTime, DateTime? endTime, string opType) => DbContextManager.Create<Log>().RetrievePages(op, startTime, endTime, opType);
/// <summary>
/// 查询所有日志信息
/// </summary>
/// <returns></returns>
public static IEnumerable<Log> RetrieveAll(DateTime? startTime, DateTime? endTime, string opType) => DbContextManager.Create<Log>().RetrieveAll(startTime, endTime, opType);
/// <summary>
/// 保存新增的日志信息

View File

@ -40,7 +40,7 @@ namespace Bootstrap.DataAccess
/// <returns></returns>
public static IEnumerable<LoginUser> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
{
return DbContextManager.Create<LoginUser>().Retrieves(startTime, endTime, ip);
return DbContextManager.Create<LoginUser>().RetrieveAll(startTime, endTime, ip);
}
}
}

View File

@ -4,6 +4,7 @@ using Longbow.Web.Mvc;
using Microsoft.AspNetCore.Http;
using PetaPoco;
using System;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@ -44,6 +45,15 @@ namespace Bootstrap.DataAccess
/// <param name="endTime"></param>
/// <param name="ip"></param>
/// <returns></returns>
public static Page<Trace> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip) => DbContextManager.Create<Trace>().Retrieves(po, startTime, endTime, ip);
public static Page<Trace> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip) => DbContextManager.Create<Trace>().RetrievePages(po, startTime, endTime, ip);
/// <summary>
/// 获得指定IP历史访问记录
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="ip"></param>
/// <returns></returns>
public static IEnumerable<Trace> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip) => DbContextManager.Create<Trace>().RetrieveAll(startTime, endTime, ip);
}
}

View File

@ -1,6 +1,7 @@
using Longbow.Web.Mvc;
using PetaPoco;
using System;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@ -28,18 +29,36 @@ namespace Bootstrap.DataAccess
/// <param name="endTime"></param>
/// <param name="opType"></param>
/// <returns></returns>
public virtual new Page<Log> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string opType)
public virtual new Page<Log> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string opType)
{
var sql = new Sql("select CRUD, UserName, LogTime, Ip, Browser, OS, City, RequestUrl, RequestData from Logs");
if (startTime.HasValue) sql.Append("where LogTime >= @0", startTime.Value);
if (endTime.HasValue) sql.Append("where LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
if (startTime == null && endTime == null) sql.Append("where LogTime > @0", DateTime.Today.AddMonths(0 - DictHelper.RetrieveExceptionsLogPeriod()));
if (!string.IsNullOrEmpty(opType)) sql.Append("where CRUD = @0", opType);
sql.Append($"order by {po.Sort} {po.Order}");
if (startTime.HasValue) sql.Where("LogTime >= @0", startTime.Value);
if (endTime.HasValue) sql.Where("LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
if (startTime == null && endTime == null) sql.Where("LogTime > @0", DateTime.Today.AddMonths(0 - DictHelper.RetrieveExceptionsLogPeriod()));
if (!string.IsNullOrEmpty(opType)) sql.Where("CRUD = @0", opType);
sql.OrderBy($"{po.Sort} {po.Order}");
return DbManager.Create().Page<Log>(po.PageIndex, po.Limit, sql);
}
/// <summary>
///
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="opType"></param>
/// <returns></returns>
public virtual new IEnumerable<Log> RetrieveAll(DateTime? startTime, DateTime? endTime, string opType)
{
var sql = new Sql("select CRUD, UserName, LogTime, Ip, Browser, OS, City, RequestUrl, RequestData from Logs");
if (startTime.HasValue) sql.Where("LogTime >= @0", startTime.Value);
if (endTime.HasValue) sql.Where("LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
if (!string.IsNullOrEmpty(opType)) sql.Where("CRUD = @0", opType);
sql.OrderBy("LogTime");
return DbManager.Create().Fetch<Log>(sql);
}
/// <summary>
/// 删除日志信息
/// </summary>

View File

@ -90,6 +90,14 @@ namespace Bootstrap.DataAccess
/// 获取所有登录数据
/// </summary>
/// <returns></returns>
public virtual IEnumerable<LoginUser> Retrieves(DateTime? startTime, DateTime? endTime, string ip) => DbManager.Create().Fetch<LoginUser>();
public virtual IEnumerable<LoginUser> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
{
var sql = new Sql("select UserName, LoginTime, Ip, Browser, OS, City, Result from LoginLogs");
if (startTime.HasValue) sql.Where("LoginTime >= @0", startTime.Value);
if (endTime.HasValue) sql.Where("LoginTime < @0", endTime.Value.AddDays(1));
if (!string.IsNullOrEmpty(ip)) sql.Where("ip = @0", ip);
sql.OrderBy($"LoginTime");
return DbManager.Create().Fetch<LoginUser>(sql);
}
}
}

View File

@ -1,6 +1,7 @@
using Longbow.Web.Mvc;
using PetaPoco;
using System;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@ -75,7 +76,7 @@ namespace Bootstrap.DataAccess
/// <param name="endTime"></param>
/// <param name="ip"></param>
/// <returns></returns>
public virtual Page<Trace> Retrieves(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
public virtual Page<Trace> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
{
var sql = new Sql("select UserName, LogTime, IP, Browser, OS, City, RequestUrl from Traces");
if (startTime.HasValue) sql.Where("LogTime > @0", startTime.Value);
@ -87,6 +88,24 @@ namespace Bootstrap.DataAccess
return DbManager.Create().Page<Trace>(po.PageIndex, po.Limit, sql);
}
/// <summary>
///
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="ip"></param>
/// <returns></returns>
public virtual IEnumerable<Trace> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
{
var sql = new Sql("select UserName, LogTime, IP, Browser, OS, City, RequestUrl from Traces");
if (startTime.HasValue) sql.Where("LogTime > @0", startTime.Value);
if (endTime.HasValue) sql.Where("LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
if (!string.IsNullOrEmpty(ip)) sql.Where("IP = @0", ip);
sql.OrderBy("LogTime");
return DbManager.Create().Fetch<Trace>(sql);
}
private static void ClearTraces() => System.Threading.Tasks.Task.Run(() =>
{
DbManager.Create().Execute("delete from Traces where LogTime < @0", DateTime.Now.AddMonths(0 - DictHelper.RetrieveAccessLogPeriod()));

View File

@ -623,6 +623,18 @@
"IsResource": NumberInt(0),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b90"),
"ParentId": "0",
"Name": "网站分析",
"Order": NumberInt(145),
"Icon": "fa fa-line-chart",
"Url": "~/Admin/Analyse",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(0),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b9d"),
"ParentId": "0",

View File

@ -98,6 +98,7 @@ INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity - 1, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity - 2, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity, '服务器日志', 10, 'fa fa-fa', 'log', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -98,6 +98,7 @@ INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (c
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 2, 0, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 3, 0, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 1, '服务器日志', 10, 'fa fa-fa', 'log', '0', 2);
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -98,6 +98,7 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid() - 1, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid() - 2, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid(), '服务器日志', 10, 'fa fa-fa', 'log', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -101,6 +101,7 @@ INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VA
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity - 1, N'登录日志', 20, N'fa fa-user-circle-o', N'~/Admin/Logins', N'0')
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity - 2, N'访问日志', 30, N'fa fa-bars', N'~/Admin/Traces', N'0')
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'在线用户', 140, N'fa fa-users', N'~/Admin/Online', N'0')
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'网站分析', 145, N'fa fa-line-chart', N'~/Admin/Analyse', N'0')
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'程序异常', 150, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity, N'服务器日志', 10, N'fa fa-fa', N'log', N'0', 2)
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0')

View File

@ -0,0 +1,22 @@
using Xunit;
using static Bootstrap.Admin.Controllers.Api.AnalyseController;
namespace Bootstrap.Admin.Api.SqlServer
{
public class AnalyseTest : ControllerTest
{
public AnalyseTest(BAWebHost factory) : base(factory, "api/Analyse") { }
[Fact]
public async void Get_Ok()
{
var cates = await Client.GetAsJsonAsync<AnalyseData>("?logType=LoginUsers");
Assert.NotNull(cates);
cates = await Client.GetAsJsonAsync<AnalyseData>("?logType=log");
Assert.NotNull(cates);
cates = await Client.GetAsJsonAsync<AnalyseData>("?logType=trace");
Assert.NotNull(cates);
}
}
}

View File

@ -27,6 +27,7 @@ namespace Bootstrap.Admin.Controllers.SqlServer
[InlineData("Online", "在线用户")]
[InlineData("Tasks", "任务管理")]
[InlineData("Mobile", "客户端测试")]
[InlineData("Analyse", "网站分析")]
public async void View_Ok(string view, string text)
{
var r = await Client.GetAsync(view);

View File

@ -36,11 +36,12 @@ namespace Bootstrap.DataAccess.SqlServer
RequestUrl = "~/Home/Index"
};
LogHelper.Save(log);
Assert.NotNull(LogHelper.Retrieves(new PaginationOption() { Limit = 20, Sort = "LogTime", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.Retrieves(new PaginationOption() { Limit = 20, Sort = "CRUD", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.Retrieves(new PaginationOption() { Limit = 20, Sort = "UserName", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.Retrieves(new PaginationOption() { Limit = 20, Sort = "Ip", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.Retrieves(new PaginationOption() { Limit = 20, Sort = "RequestUrl", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.RetrievePages(new PaginationOption() { Limit = 20, Sort = "LogTime", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.RetrievePages(new PaginationOption() { Limit = 20, Sort = "CRUD", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.RetrievePages(new PaginationOption() { Limit = 20, Sort = "UserName", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.RetrievePages(new PaginationOption() { Limit = 20, Sort = "Ip", Order = "desc" }, null, null, null));
Assert.NotNull(LogHelper.RetrievePages(new PaginationOption() { Limit = 20, Sort = "RequestUrl", Order = "desc" }, null, null, null));
Assert.NotEmpty(LogHelper.RetrieveAll(null, null, null));
}
}
}

View File

@ -45,6 +45,7 @@ namespace Bootstrap.DataAccess.SqlServer
Assert.NotEmpty(TraceHelper.Retrieves(new PaginationOption() { Limit = 20, Offset = 0, Order = "desc", Sort = "Browser" }, null, null, null).Items);
Assert.NotEmpty(TraceHelper.Retrieves(new PaginationOption() { Limit = 20, Offset = 0, Order = "desc", Sort = "OS" }, null, null, null).Items);
Assert.NotEmpty(TraceHelper.Retrieves(new PaginationOption() { Limit = 20, Offset = 0, Order = "desc", Sort = "RequestUrl" }, null, null, null).Items);
Assert.NotEmpty(TraceHelper.RetrieveAll(null, null, null));
}
}
}

View File

@ -175,7 +175,7 @@ namespace Bootstrap.DataAccess.SqlServer
[Fact]
public void RetrievePageLoginUsers_Ok()
{
var data = LoginHelper.RetrievePages(new PaginationOption() { Limit = 20, Offset = 0 }, null, null, "");
var data = LoginHelper.RetrievePages(new PaginationOption() { Limit = 20, Offset = 0, Order = "LoginTime" }, null, null, "");
Assert.NotNull(data.Items);
}

Binary file not shown.