refactor: separate different routes codes apart

This commit is contained in:
Emil Zhai 2022-12-04 08:24:11 +00:00
parent 31302003d4
commit eee11fc919
No known key found for this signature in database
GPG Key ID: 780B385DB72F1EBD
5 changed files with 671 additions and 617 deletions

View File

@ -8,279 +8,18 @@ $access = new Access_Core();
<div class="main">
<div class="body container">
<div class="typecho-page-title">
<h2><?= $access->title;?></h2>
<h2><?= $access->title;?></h2>
</div>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<div class="col-mb-12">
<ul class="typecho-option-tabs fix-tabs clearfix">
<li<?=($access->action == 'overview' ? ' class="current"' : '')?>><a href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&action=overview'); ?>"><?php _e('访问概览'); ?></a></li>
<li<?=($access->action == 'logs' ? ' class="current"' : '')?>><a href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&action=logs'); ?>"><?php _e('访问日志'); ?></a></li>
<li><a href="<?php $options->adminUrl('options-plugin.php?config=Access') ?>"><?php _e('插件设置'); ?></a></li>
</ul>
</div>
<?php if($access->action == 'logs'):?>
<div class="col-mb-12 typecho-list">
<div class="typecho-list-operate clearfix">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a data-action="delete" href="javascript:;"><?php _e('删除'); ?></a></li>
</ul>
</div>
</div>
<form method="get" class="search-form">
<div class="search" role="search">
<?php if ($request->get('filter', 'all') != 'all'): ?>
<a href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&action=logs'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="hidden" value="<?= $request->get('panel'); ?>" name="panel" />
<?php if(isset($request->page)): ?>
<input type="hidden" value="<?= $request->get('page'); ?>" name="page" />
<?php endif; ?>
<select name="filter">
<option <?php if($request->filter == 'all'): ?> selected="true"<?php endif; ?>value="all"><?php _e('所有'); ?></option>
<option <?php if($request->filter == 'ip'): ?> selected="true"<?php endif; ?>value="ip"><?php _e('按IP'); ?></option>
<option <?php if($request->filter == 'post'): ?> selected="true"<?php endif; ?>value="post"><?php _e('按文章'); ?></option>
<option <?php if($request->filter == 'path'): ?> selected="true"<?php endif; ?>value="path"><?php _e('按路由'); ?></option>
</select>
<select style="<?php if(!in_array($request->get('filter', 'all'), ['ip', 'path'])): ?>display: none<?php endif; ?>" name="fuzzy">
<option <?php if($request->fuzzy != '1'): ?> selected="true"<?php endif; ?>value=""><?php _e('精确匹配'); ?></option>
<option <?php if($request->fuzzy == '1'): ?> selected="true"<?php endif; ?>value="1"><?php _e('模糊匹配'); ?></option>
</select>
<input style="<?php if($request->get('filter', 'all') != 'ip'): ?>display: none<?php endif; ?>" type="text" class="text-s" placeholder="" value="<?= htmlspecialchars($request->ip ?: ''); ?>" name="ip" />
<select style="<?php if($request->get('filter', 'all') != 'post'): ?>display: none<?php endif; ?>" name="cid">
<?php foreach ($access->logs['cidList'] as $content):?>
<option <?php if($request->cid == $content['cid']): ?> selected="true"<?php endif; ?>value="<?= $content['cid'];?>"><?= $content['title'];?> (<?= $content['count'];?>)</option>
<?php endforeach;?>
</select>
<input style="<?php if($request->get('filter', 'all') != 'path'): ?>display: none<?php endif; ?>" type="text" class="text-s" placeholder="" value="<?= htmlspecialchars($request->path ?: ''); ?>" name="path" />
<select name="type">
<option <?php if($request->type == 1): ?> selected="true"<?php endif; ?>value="1"><?php _e('默认(仅人类)'); ?></option>
<option <?php if($request->type == 2): ?> selected="true"<?php endif; ?>value="2"><?php _e('仅爬虫'); ?></option>
<option <?php if($request->type == 3): ?> selected="true"<?php endif; ?>value="3"><?php _e('所有'); ?></option>
</select>
<input type="hidden" name="page" value="1">
<button type="button" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
</div><!-- end .typecho-list-operate -->
<form method="post" class="operate-form">
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="5%"/>
<col width="28%"/>
<col width="25%"/>
<col width="18%"/>
<col width="16%"/>
<col width="20%"/>
<col width="18%"/>
</colgroup>
<thead>
<tr>
<th> </th>
<th><?php _e('受访地址'); ?></th>
<th><?php _e('UA'); ?></th>
<th><?php _e('IP地址'); ?></th>
<th><?php _e('IP属地'); ?></th>
<th><?php _e('Referer'); ?></th>
<th><?php _e('日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if(!empty($access->logs['list'])): ?>
<?php foreach ($access->logs['list'] as $log): ?>
<tr id="<?= $log['id']; ?>" data-id="<?= $log['id']; ?>">
<td><input type="checkbox" data-id="<?= $log['id']; ?>" value="<?= $log['id']; ?>" name="id[]"/></td>
<td><a target="_self" href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&filter=path&path=' . $log['path'] . '&type='. $request->type); ?>"><?= urldecode(str_replace("%23", "#", $log['url'])); ?></a></td>
<td><a data-action="ua" href="#" title="<?= $log['ua'];?>"><?= $log['display_name']; ?></a></td>
<td><a data-action="ip" data-ip="<?= $log['ip'] ?>" href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&filter=ip&ip=' . $log['ip'] . '&type='. $request->type); ?>"><?= $log['ip']; ?></td>
<td><?= $log['ip_loc'] ?></td>
<td><a target="_blank" data-action="referer" href="<?= $log['referer']; ?>"><?= $log['referer']; ?></a></td>
<td><?= date('Y-m-d H:i:s', $log['time']); ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6"><h6 class="typecho-list-table-title"><?php _e('当前无日志'); ?></h6></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</form><!-- end .operate-form -->
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a data-action="delete" href="javascript:;"><?php _e('删除'); ?></a></li>
</ul>
</div>
</div>
<?php if($access->logs['rows'] > 1): ?>
<ul class="typecho-pager">
<?= $access->logs['page']; ?>
</ul>
<?php endif; ?>
</form>
</div><!-- end .typecho-list-operate -->
</div><!-- end .typecho-list -->
<?php elseif($access->action == 'overview'):?>
<div class="col-mb-12 typecho-list">
<h4 class="typecho-list-table-title">访问数表格</h4>
<div class="typecho-table-wrap" id="tbl-count">
<table class="typecho-list-table">
<colgroup>
<col width="10%"/>
<col width="30%"/>
<col width="25%"/>
<col width=""/>
</colgroup>
<thead>
<tr>
<th> </th>
<th><?php _e('浏览量(PV)'); ?></th>
<th><?php _e('访客数(UV)'); ?></th>
<th><?php _e('IP数'); ?></th>
</tr>
</thead>
<tbody>
<tr name="count-today">
<td>今日</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
<tr name="count-yesterday">
<td>昨日</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
<tr name="count-total">
<td>总计</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="col-mb-12 col-4">
<h4 class="typecho-list-table-title">来源域名</h4>
<div class="typecho-table-wrap">
<table class="typecho-list-table" id="tbl-referer-domain">
<colgroup>
<col width="15%"/>
<col width="15%"/>
<col width="70%"/>
</colgroup>
<thead>
<tr>
<th>排名</th>
<th>次数</th>
<th>来源域名</th>
</tr>
</thead>
<tbody>
<tr>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-mb-12 col-8">
<h4 class="typecho-list-table-title">来源页</h4>
<div class="typecho-table-wrap">
<table class="typecho-list-table" id="tbl-referer-url">
<colgroup>
<col width="15%"/>
<col width="15%"/>
<col width="70%"/>
</colgroup>
<thead>
<tr>
<th>排名</th>
<th>次数</th>
<th>来源URL</th>
</tr>
</thead>
<tbody>
<tr>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">文章浏览分析</h4>
<div class="typecho-table-wrap" id="pie-article">loading...</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">访客地域分析</h4>
<div class="typecho-table-wrap">
<ul class="typecho-option-tabs clearfix">
<li><button id="btn-china" class="btn btn-s primary">国内</button></li>
<li><button id="btn-inter" class="btn btn-s">国际</button><li>
</ul>
<div class="typecho-table-wrap" id="bar-location">loading...</div>
</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">今日图表</h4>
<div class="typecho-table-wrap" id="chart-today"></div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">昨日图表</h4>
<div class="typecho-table-wrap" id="chart-yesterday"></div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">当月图表</h4>
<div class="typecho-table-wrap" id="chart-month"></div>
</div>
</div>
<!-- end .typecho-list -->
<?php endif;?>
<?php include("routes/{$access->action}/index.php") ?>
</div>
<!-- end .typecho-page-main -->
</div>
</div>
@ -288,358 +27,5 @@ $access = new Access_Core();
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
?>
<script type="text/javascript">
$(document).ready(function() {
$('a[data-action="ua"]').click(function() {
swal({
icon: 'info',
title: 'User-Agent',
text: $(this).attr('title').trim()
});
});
$('.dropdown-menu a[data-action="delete"]').click(function() {
swal({
title: '你确定?',
text: '你确认要删除这些记录吗?',
icon: 'warning',
buttons: {
cancel: '算啦',
confirm: '是的'
}
}).then((value) => {
if(value === true) {
let ids = [];
$('.typecho-list-table input[type="checkbox"]').each(function(index, elem) {
if (elem.checked) {
ids.push($(elem).data('id'));
}
});
if(ids.length != 0) {
$.ajax({
url: '/access/log/delete',
method: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(ids),
success: function(data) {
if (data.code == 0) {
swal({
icon: 'success',
title: '删除成功',
text: '所选记录已删除'
});
$.each(ids, function(index, elem) {
$('.typecho-list-table tbody tr[data-id="' + elem + '"]').fadeOut(500).remove();
});
} else {
swal({
icon: 'error',
title: '错误',
text: '删除出错啦'
});
}
},
error: function(xhr, status, error) {
swal({
icon: 'error',
title: '错误',
text: '请求错误 code: '+xhr.status
});
}
});
} else {
return swal({
icon: 'warning',
title: '错误',
text: '你并没有勾选任何内容'
});
}
}
});
var $this = $(this);
$this.parents('.dropdown-menu').hide().prev().removeClass('active');
});
var $form = $('form.search-form');
var $ipInput = $form.find('input[name="ip"]');
var $cidSelect = $form.find('select[name="cid"]');
var $pathInput = $form.find('input[name="path"]');
var $filterSelect = $form.find('select[name="filter"]');
var $fuzzySelect = $form.find('select[name="fuzzy"]');
$filterSelect.on('change', function() {
$ipInput.removeAttr('placeholder').val('').hide();
$cidSelect.hide();
$pathInput.removeAttr('placeholder').val('').hide();
$fuzzySelect.hide();
switch ($filterSelect.val()) {
case 'ip':
$ipInput.attr('placeholder', '输入ip').show();
$fuzzySelect.show();
break;
case 'post':
$cidSelect.show();
break;
case 'path':
$pathInput.attr('placeholder', '输入路由').show();
$fuzzySelect.show();
break;
}
});
$fuzzySelect.on('change', function(e) {
if (e.target.value === '1') {
$ipInput.val($ipInput.val().replace(/%/u, '\\%'));
$pathInput.val($ipInput.val().replace(/%/u, '\\%'));
} else {
$ipInput.val($ipInput.val().replace(/\\%/u, '%'));
$pathInput.val($ipInput.val().replace(/\\%/u, '%'));
}
})
$form.find('button[type="button"]').on('click', function() {
$form.submit();
});
});
</script>
<script src="<?php $options->pluginUrl('Access/page/sweetalert.min.js')?>"></script>
<?php if($access->action == 'overview'):?>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/highcharts.js')?>"></script>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/modules/exporting.js')?>"></script>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/modules/accessibility.js')?>"></script>
<script type="text/javascript">
// html转义
htmlEncode = function(target) {
return target.replace(/[<>&"]/g, function(c){
return {'<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;'}[c];
});
}
// 输出图表
printChart = function(target, title, data, avg=null) {
let pv = [], uv = [], ip = [], time = [];
for(let i = 0;i < data.length;i++)
pv.push(data[i].pv), uv.push(data[i].uv), ip.push(data[i].ip), time.push(data[i].time);
const chart = Highcharts.chart(target, {
title: {text: title, x: -20},
subtitle: {text: 'Generate By AccessPlugin', x: -20},
xAxis: {categories: time, title: {text: '时间', align: 'high'}},
yAxis: {
title: {text: '数量'},
plotLines: (avg !== null) ? [
// 平均值
{
value: avg.pv,
width: 1,
color: '#F7A35C'
}, {
value: avg.uv,
width: 1,
color: '#90ED7D'
}, {
value: avg.ip,
width: 1,
color: '#7CB5ED'
}
] : null
},
tooltip: {valueSuffix: ''},
plotOptions: {line: {dataLabels: {enabled: true}}},
series: [
{
name: 'PV浏览',
data: pv,
color: '#F7A35C'
}, {
name: 'UV访客',
data: uv,
color: '#90ED7D'
}, {
name: 'IP地址',
data: ip,
color: '#7CB5ED'
}
]
});
}
// 输出饼图
printPie = function(target, title, data) {
let value = [];
// 生成统计row
for(let i = 0;i < data.length;i++)
value.push({name: data[i].title, y: data[i].count, cid: data[i].cid})
// 计算最大比例并选中
let maxKey = 0;
for(let i = 0;i < value.length;i++) {
if(value[i].y >= value[maxKey].y)
maxKey = i;
}
if(value.length)
value[maxKey].sliced = true;
const chart = Highcharts.chart(target, {
chart: {type: 'pie'},
title: {text: title},
subtitle: {text: 'Generate By AccessPlugin'},
tooltip: {pointFormat: '<b>阅读数: {point.y}<br>占比: {point.percentage:.1f}%<br>cid={point.cid}</b>'},
accessibility: {point: {valueSuffix: '%'}},
plotOptions: {pie: {allowPointSelect: true, cursor: 'pointer', dataLabels: {enabled: true, format: '<b>{point.name}</b>: {point.y}'}}},
series: [{colorByPoint: true, data: value}]
})
}
// 输出条形统计图
printBar = function(target, title, data) {
let values = [],
areas = [];
for(let i = 0;i < data.length;i++)
areas.push(data[i].area), values.push(data[i].count);
return Highcharts.chart(target, {
chart: {type: 'bar'},
title: {text: title, x: -20},
subtitle: {text: 'Generate By AccessPlugin', x: -20},
xAxis: {categories: areas, title: {text: '地域'}},
yAxis: {title: {text: '访问次数', align: 'high'}},
plotOptions: {bar: {dataLabels: {enabled: true}, colorByPoint: true}},
legend: {enabled: false},
series: [{name: '访问量', data: values}]
});
}
updateBar = function(target, title, data) {
let values = [],
areas = [];
for(let i = 0;i < data.length;i++)
areas.push(data[i].area), values.push(data[i].count);
target.update({
title: {text: title},
xAxis: {categories: areas, title: {text: '地域'}},
series: [{name: '访问量', data: values}]
}, true, false, {duration: 800});
}
// 显示来源统计表
printRefererTable = function(target, data) {
let tbl = $('#'+target+' tbody');
tbl.children().remove(); // 清空表格
for(let i = 0;i < data.length;i++) {
tbl.append('<tr><td>'+(i+1)+'</td><td>'+data[i].count+'</td><td>'+htmlEncode(data[i].value)+'</td><td></td></tr>');
}
}
// 拉取统计数据
getStatisticData = function(rpc, params=null, callback) {
$.ajax({
url: '/access/statistic/view',
method: 'get',
dataType: 'json',
data: {rpc: rpc, ...params},
async: true,
success: function(data) {
if(data.code === 0)
callback(data.data);
else
console.log('rpc='+rpc+'数据获取错误 code='+data.code+' msg='+data.message);
},
error: function(xhr, status, error) {
console.log('rpc='+rpc+' API拉取错误 '+error.toString());
}
})
}
// 挂接format方法
Date.prototype.format = function(fmt) {
var o = {
'%Y+': this.getFullYear(), // 年
'%m+': this.getMonth() + 1, //月份
'%d+': this.getDate(), //日
'%H+': this.getHours(), //小时
'%M+': this.getMinutes(), //分
'%S+': this.getSeconds(), //秒
'%Q+': Math.floor((this.getMonth() + 3) / 3), //季度
'%s+': this.getMilliseconds() //毫秒
};
for(var k in o)
if(new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1,
(RegExp.$1.length == 2) ?
o[k] : (('00' + o[k]).substr(('' + o[k]).length))
);
return fmt;
}
$().ready(function() {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// 今日计数统计数据
getStatisticData('count', {type: 'day', time: today.format('%Y-%mm-%dd')} ,function(data) {
let row = $('#tbl-count tr[name="count-today"] td');
row.eq(1).text(data.count.pv), row.eq(2).text(data.count.uv), row.eq(3).text(data.count.ip);
});
// 昨日计数统计数据
getStatisticData('count', {type: 'day', time: yesterday.format('%Y-%mm-%dd')} ,function(data) {
let row = $('#tbl-count tr[name="count-yesterday"] td');
row.eq(1).text(data.count.pv), row.eq(2).text(data.count.uv), row.eq(3).text(data.count.ip);
});
// 总计数统计数据
getStatisticData('count', {type: 'total'} ,function(data) {
let row = $('#tbl-count tr[name="count-total"] td');
row.eq(1).text(data.count.pv), row.eq(2).text(data.count.uv), row.eq(3).text(data.count.ip);
});
// 来源域名统计
getStatisticData('referer', {type: 'domain', pn: 1, ps: 10} ,function(data) {
printRefererTable('tbl-referer-domain', data);
});
// 来源页统计
getStatisticData('referer', {type: 'url', pn: 1, ps: 10} ,function(data) {
printRefererTable('tbl-referer-url', data);
});
// 文章浏览比例统计
getStatisticData('article', {ps: 10} ,function(data) {
printPie('pie-article', '最受欢迎的文章', data);
});
// 浏览地域分析图
getStatisticData('location', {cate: 'china', ps: 10} ,function(data) {
const chartBar = printBar('bar-location', '国内访问地域分析', data);
// 国际按钮
$('#btn-inter').click(function(){
$('#btn-inter').addClass('primary');
$('#btn-china').removeClass('primary');
getStatisticData('location', {cate: 'inter', ps: 10} ,function(data) {
updateBar(chartBar, '国际访问地域分析', data)
});
});
// 国内按钮
$('#btn-china').click(function(){
$('#btn-china').addClass('primary');
$('#btn-inter').removeClass('primary');
getStatisticData('location', {cate: 'china', ps: 10} ,function(data) {
updateBar(chartBar, '国内访问地域分析', data)
});
});
});
// 当天访问图表
getStatisticData('chart', {type: 'day', time: today.format('%Y-%mm-%dd')} ,function(data) {
printChart('chart-today', data.dst+' 统计', data.chart, data.avg);
});
// 昨天访问图表
getStatisticData('chart', {type: 'day', time: yesterday.format('%Y-%mm-%dd')} ,function(data) {
printChart('chart-yesterday', data.dst+' 统计', data.chart, data.avg);
});
// 当月访问图表
getStatisticData('chart', {type: 'month', time: today.format('%Y-%mm')} ,function(data) {
printChart('chart-month', data.dst+' 统计', data.chart, data.avg);
});
});
</script>
<?php endif;?>
<?php
include 'footer.php';
?>

119
page/routes/logs/index.js Normal file
View File

@ -0,0 +1,119 @@
$(document).ready(function () {
$('a[data-action="ua"]').click(function () {
swal({
icon: "info",
title: "User-Agent",
text: $(this).attr("title").trim(),
});
});
$('.dropdown-menu a[data-action="delete"]').click(function () {
swal({
title: "你确定?",
text: "你确认要删除这些记录吗?",
icon: "warning",
buttons: {
cancel: "算啦",
confirm: "是的",
},
}).then((value) => {
if (value === true) {
let ids = [];
$('.typecho-list-table input[type="checkbox"]').each(function (
index,
elem
) {
if (elem.checked) {
ids.push($(elem).data("id"));
}
});
if (ids.length != 0) {
$.ajax({
url: "/access/log/delete",
method: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify(ids),
success: function (data) {
if (data.code == 0) {
swal({
icon: "success",
title: "删除成功",
text: "所选记录已删除",
});
$.each(ids, function (index, elem) {
$('.typecho-list-table tbody tr[data-id="' + elem + '"]')
.fadeOut(500)
.remove();
});
} else {
swal({
icon: "error",
title: "错误",
text: "删除出错啦",
});
}
},
error: function (xhr, status, error) {
swal({
icon: "error",
title: "错误",
text: "请求错误 code: " + xhr.status,
});
},
});
} else {
return swal({
icon: "warning",
title: "错误",
text: "你并没有勾选任何内容",
});
}
}
});
var $this = $(this);
$this.parents(".dropdown-menu").hide().prev().removeClass("active");
});
var $form = $("form.search-form");
var $ipInput = $form.find('input[name="ip"]');
var $cidSelect = $form.find('select[name="cid"]');
var $pathInput = $form.find('input[name="path"]');
var $filterSelect = $form.find('select[name="filter"]');
var $fuzzySelect = $form.find('select[name="fuzzy"]');
$filterSelect.on("change", function () {
$ipInput.removeAttr("placeholder").val("").hide();
$cidSelect.hide();
$pathInput.removeAttr("placeholder").val("").hide();
$fuzzySelect.hide();
switch ($filterSelect.val()) {
case "ip":
$ipInput.attr("placeholder", "输入ip").show();
$fuzzySelect.show();
break;
case "post":
$cidSelect.show();
break;
case "path":
$pathInput.attr("placeholder", "输入路由").show();
$fuzzySelect.show();
break;
}
});
$fuzzySelect.on("change", function (e) {
if (e.target.value === "1") {
$ipInput.val($ipInput.val().replace(/%/u, "\\%"));
$pathInput.val($ipInput.val().replace(/%/u, "\\%"));
} else {
$ipInput.val($ipInput.val().replace(/\\%/u, "%"));
$pathInput.val($ipInput.val().replace(/\\%/u, "%"));
}
});
$form.find('button[type="button"]').on("click", function () {
$form.submit();
});
});

121
page/routes/logs/index.php Normal file
View File

@ -0,0 +1,121 @@
<div class="col-mb-12 typecho-list">
<div class="typecho-list-operate clearfix">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a data-action="delete" href="javascript:;"><?php _e('删除'); ?></a></li>
</ul>
</div>
</div>
<form method="get" class="search-form">
<div class="search" role="search">
<?php if ($request->get('filter', 'all') != 'all'): ?>
<a href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&action=logs'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="hidden" value="<?= $request->get('panel'); ?>" name="panel" />
<?php if(isset($request->page)): ?>
<input type="hidden" value="<?= $request->get('page'); ?>" name="page" />
<?php endif; ?>
<select name="filter">
<option <?php if($request->filter == 'all'): ?> selected="true"<?php endif; ?>value="all"><?php _e('所有'); ?></option>
<option <?php if($request->filter == 'ip'): ?> selected="true"<?php endif; ?>value="ip"><?php _e('按IP'); ?></option>
<option <?php if($request->filter == 'post'): ?> selected="true"<?php endif; ?>value="post"><?php _e('按文章'); ?></option>
<option <?php if($request->filter == 'path'): ?> selected="true"<?php endif; ?>value="path"><?php _e('按路由'); ?></option>
</select>
<select style="<?php if(!in_array($request->get('filter', 'all'), ['ip', 'path'])): ?>display: none<?php endif; ?>" name="fuzzy">
<option <?php if($request->fuzzy != '1'): ?> selected="true"<?php endif; ?>value=""><?php _e('精确匹配'); ?></option>
<option <?php if($request->fuzzy == '1'): ?> selected="true"<?php endif; ?>value="1"><?php _e('模糊匹配'); ?></option>
</select>
<input style="<?php if($request->get('filter', 'all') != 'ip'): ?>display: none<?php endif; ?>" type="text" class="text-s" placeholder="" value="<?= htmlspecialchars($request->ip ?: ''); ?>" name="ip" />
<select style="<?php if($request->get('filter', 'all') != 'post'): ?>display: none<?php endif; ?>" name="cid">
<?php foreach ($access->logs['cidList'] as $content):?>
<option <?php if($request->cid == $content['cid']): ?> selected="true"<?php endif; ?>value="<?= $content['cid'];?>"><?= $content['title'];?> (<?= $content['count'];?>)</option>
<?php endforeach;?>
</select>
<input style="<?php if($request->get('filter', 'all') != 'path'): ?>display: none<?php endif; ?>" type="text" class="text-s" placeholder="" value="<?= htmlspecialchars($request->path ?: ''); ?>" name="path" />
<select name="type">
<option <?php if($request->type == 1): ?> selected="true"<?php endif; ?>value="1"><?php _e('默认(仅人类)'); ?></option>
<option <?php if($request->type == 2): ?> selected="true"<?php endif; ?>value="2"><?php _e('仅爬虫'); ?></option>
<option <?php if($request->type == 3): ?> selected="true"<?php endif; ?>value="3"><?php _e('所有'); ?></option>
</select>
<input type="hidden" name="page" value="1">
<button type="button" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
</div>
<form method="post" class="operate-form">
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="5%"/>
<col width="28%"/>
<col width="25%"/>
<col width="18%"/>
<col width="16%"/>
<col width="20%"/>
<col width="18%"/>
</colgroup>
<thead>
<tr>
<th> </th>
<th><?php _e('受访地址'); ?></th>
<th><?php _e('UA'); ?></th>
<th><?php _e('IP地址'); ?></th>
<th><?php _e('IP属地'); ?></th>
<th><?php _e('Referer'); ?></th>
<th><?php _e('日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if(!empty($access->logs['list'])): ?>
<?php foreach ($access->logs['list'] as $log): ?>
<tr id="<?= $log['id']; ?>" data-id="<?= $log['id']; ?>">
<td><input type="checkbox" data-id="<?= $log['id']; ?>" value="<?= $log['id']; ?>" name="id[]"/></td>
<td><a target="_self" href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&filter=path&path=' . $log['path'] . '&type='. $request->type); ?>"><?= urldecode(str_replace("%23", "#", $log['url'])); ?></a></td>
<td><a data-action="ua" href="#" title="<?= $log['ua'];?>"><?= $log['display_name']; ?></a></td>
<td><a data-action="ip" data-ip="<?= $log['ip'] ?>" href="<?php $options->adminUrl('extending.php?panel=' . Access_Plugin::$panel . '&filter=ip&ip=' . $log['ip'] . '&type='. $request->type); ?>"><?= $log['ip']; ?></td>
<td><?= $log['ip_loc'] ?></td>
<td><a target="_blank" data-action="referer" href="<?= $log['referer']; ?>"><?= $log['referer']; ?></a></td>
<td><?= date('Y-m-d H:i:s', $log['time']); ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6"><h6 class="typecho-list-table-title"><?php _e('当前无日志'); ?></h6></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</form>
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a data-action="delete" href="javascript:;"><?php _e('删除'); ?></a></li>
</ul>
</div>
</div>
<?php if($access->logs['rows'] > 1): ?>
<ul class="typecho-pager">
<?= $access->logs['page']; ?>
</ul>
<?php endif; ?>
</form>
</div>
</div>
<script src="<?php $options->pluginUrl('Access/page/sweetalert.min.js')?>"></script>
<script type="text/javascript" defer src="<?php $options->pluginUrl('Access/page/routes/logs/index.js')?>"></script>

View File

@ -0,0 +1,295 @@
// html转义
htmlEncode = function (target) {
return target.replace(/[<>&"]/g, function (c) {
return { "<": "&lt;", ">": "&gt;", "&": "&amp;", '"': "&quot;" }[c];
});
};
// 输出图表
printChart = function (target, title, data, avg = null) {
let pv = [],
uv = [],
ip = [],
time = [];
for (let i = 0; i < data.length; i++)
pv.push(data[i].pv),
uv.push(data[i].uv),
ip.push(data[i].ip),
time.push(data[i].time);
const chart = Highcharts.chart(target, {
title: { text: title, x: -20 },
subtitle: { text: "Generate By AccessPlugin", x: -20 },
xAxis: { categories: time, title: { text: "时间", align: "high" } },
yAxis: {
title: { text: "数量" },
plotLines:
avg !== null
? [
// 平均值
{
value: avg.pv,
width: 1,
color: "#F7A35C",
},
{
value: avg.uv,
width: 1,
color: "#90ED7D",
},
{
value: avg.ip,
width: 1,
color: "#7CB5ED",
},
]
: null,
},
tooltip: { valueSuffix: "" },
plotOptions: { line: { dataLabels: { enabled: true } } },
series: [
{
name: "PV浏览",
data: pv,
color: "#F7A35C",
},
{
name: "UV访客",
data: uv,
color: "#90ED7D",
},
{
name: "IP地址",
data: ip,
color: "#7CB5ED",
},
],
});
};
// 输出饼图
printPie = function (target, title, data) {
let value = [];
// 生成统计row
for (let i = 0; i < data.length; i++)
value.push({ name: data[i].title, y: data[i].count, cid: data[i].cid });
// 计算最大比例并选中
let maxKey = 0;
for (let i = 0; i < value.length; i++) {
if (value[i].y >= value[maxKey].y) maxKey = i;
}
if (value.length) value[maxKey].sliced = true;
const chart = Highcharts.chart(target, {
chart: { type: "pie" },
title: { text: title },
subtitle: { text: "Generate By AccessPlugin" },
tooltip: {
pointFormat:
"<b>阅读数: {point.y}<br>占比: {point.percentage:.1f}%<br>cid={point.cid}</b>",
},
accessibility: { point: { valueSuffix: "%" } },
plotOptions: {
pie: {
allowPointSelect: true,
cursor: "pointer",
dataLabels: { enabled: true, format: "<b>{point.name}</b>: {point.y}" },
},
},
series: [{ colorByPoint: true, data: value }],
});
};
// 输出条形统计图
printBar = function (target, title, data) {
let values = [],
areas = [];
for (let i = 0; i < data.length; i++)
areas.push(data[i].area), values.push(data[i].count);
return Highcharts.chart(target, {
chart: { type: "bar" },
title: { text: title, x: -20 },
subtitle: { text: "Generate By AccessPlugin", x: -20 },
xAxis: { categories: areas, title: { text: "地域" } },
yAxis: { title: { text: "访问次数", align: "high" } },
plotOptions: { bar: { dataLabels: { enabled: true }, colorByPoint: true } },
legend: { enabled: false },
series: [{ name: "访问量", data: values }],
});
};
updateBar = function (target, title, data) {
let values = [],
areas = [];
for (let i = 0; i < data.length; i++)
areas.push(data[i].area), values.push(data[i].count);
target.update(
{
title: { text: title },
xAxis: { categories: areas, title: { text: "地域" } },
series: [{ name: "访问量", data: values }],
},
true,
false,
{ duration: 800 }
);
};
// 显示来源统计表
printRefererTable = function (target, data) {
let tbl = $("#" + target + " tbody");
tbl.children().remove(); // 清空表格
for (let i = 0; i < data.length; i++) {
tbl.append(
"<tr><td>" +
(i + 1) +
"</td><td>" +
data[i].count +
"</td><td>" +
htmlEncode(data[i].value) +
"</td><td></td></tr>"
);
}
};
// 拉取统计数据
getStatisticData = function (rpc, params = null, callback) {
$.ajax({
url: "/access/statistic/view",
method: "get",
dataType: "json",
data: { rpc: rpc, ...params },
async: true,
success: function (data) {
if (data.code === 0) callback(data.data);
else
console.log(
"rpc=" +
rpc +
"数据获取错误 code=" +
data.code +
" msg=" +
data.message
);
},
error: function (xhr, status, error) {
console.log("rpc=" + rpc + " API拉取错误 " + error.toString());
},
});
};
// 挂接format方法
Date.prototype.format = function (fmt) {
var o = {
"%Y+": this.getFullYear(), // 年
"%m+": this.getMonth() + 1, //月份
"%d+": this.getDate(), //日
"%H+": this.getHours(), //小时
"%M+": this.getMinutes(), //分
"%S+": this.getSeconds(), //秒
"%Q+": Math.floor((this.getMonth() + 3) / 3), //季度
"%s+": this.getMilliseconds(), //毫秒
};
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 2 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
);
return fmt;
};
$().ready(function () {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// 今日计数统计数据
getStatisticData(
"count",
{ type: "day", time: today.format("%Y-%mm-%dd") },
function (data) {
let row = $('#tbl-count tr[name="count-today"] td');
row.eq(1).text(data.count.pv),
row.eq(2).text(data.count.uv),
row.eq(3).text(data.count.ip);
}
);
// 昨日计数统计数据
getStatisticData(
"count",
{ type: "day", time: yesterday.format("%Y-%mm-%dd") },
function (data) {
let row = $('#tbl-count tr[name="count-yesterday"] td');
row.eq(1).text(data.count.pv),
row.eq(2).text(data.count.uv),
row.eq(3).text(data.count.ip);
}
);
// 总计数统计数据
getStatisticData("count", { type: "total" }, function (data) {
let row = $('#tbl-count tr[name="count-total"] td');
row.eq(1).text(data.count.pv),
row.eq(2).text(data.count.uv),
row.eq(3).text(data.count.ip);
});
// 来源域名统计
getStatisticData(
"referer",
{ type: "domain", pn: 1, ps: 10 },
function (data) {
printRefererTable("tbl-referer-domain", data);
}
);
// 来源页统计
getStatisticData("referer", { type: "url", pn: 1, ps: 10 }, function (data) {
printRefererTable("tbl-referer-url", data);
});
// 文章浏览比例统计
getStatisticData("article", { ps: 10 }, function (data) {
printPie("pie-article", "最受欢迎的文章", data);
});
// 浏览地域分析图
getStatisticData("location", { cate: "china", ps: 10 }, function (data) {
const chartBar = printBar("bar-location", "国内访问地域分析", data);
// 国际按钮
$("#btn-inter").click(function () {
$("#btn-inter").addClass("primary");
$("#btn-china").removeClass("primary");
getStatisticData("location", { cate: "inter", ps: 10 }, function (data) {
updateBar(chartBar, "国际访问地域分析", data);
});
});
// 国内按钮
$("#btn-china").click(function () {
$("#btn-china").addClass("primary");
$("#btn-inter").removeClass("primary");
getStatisticData("location", { cate: "china", ps: 10 }, function (data) {
updateBar(chartBar, "国内访问地域分析", data);
});
});
});
// 当天访问图表
getStatisticData(
"chart",
{ type: "day", time: today.format("%Y-%mm-%dd") },
function (data) {
printChart("chart-today", data.dst + " 统计", data.chart, data.avg);
}
);
// 昨天访问图表
getStatisticData(
"chart",
{ type: "day", time: yesterday.format("%Y-%mm-%dd") },
function (data) {
printChart("chart-yesterday", data.dst + " 统计", data.chart, data.avg);
}
);
// 当月访问图表
getStatisticData(
"chart",
{ type: "month", time: today.format("%Y-%mm") },
function (data) {
printChart("chart-month", data.dst + " 统计", data.chart, data.avg);
}
);
});

View File

@ -0,0 +1,133 @@
<div class="col-mb-12 typecho-list">
<h4 class="typecho-list-table-title">访问数表格</h4>
<div class="typecho-table-wrap" id="tbl-count">
<table class="typecho-list-table">
<colgroup>
<col width="10%"/>
<col width="30%"/>
<col width="25%"/>
<col width=""/>
</colgroup>
<thead>
<tr>
<th> </th>
<th><?php _e('浏览量(PV)'); ?></th>
<th><?php _e('访客数(UV)'); ?></th>
<th><?php _e('IP数'); ?></th>
</tr>
</thead>
<tbody>
<tr name="count-today">
<td>今日</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
<tr name="count-yesterday">
<td>昨日</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
<tr name="count-total">
<td>总计</td>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="col-mb-12 col-4">
<h4 class="typecho-list-table-title">来源域名</h4>
<div class="typecho-table-wrap">
<table class="typecho-list-table" id="tbl-referer-domain">
<colgroup>
<col width="15%"/>
<col width="15%"/>
<col width="70%"/>
</colgroup>
<thead>
<tr>
<th>排名</th>
<th>次数</th>
<th>来源域名</th>
</tr>
</thead>
<tbody>
<tr>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-mb-12 col-8">
<h4 class="typecho-list-table-title">来源页</h4>
<div class="typecho-table-wrap">
<table class="typecho-list-table" id="tbl-referer-url">
<colgroup>
<col width="15%"/>
<col width="15%"/>
<col width="70%"/>
</colgroup>
<thead>
<tr>
<th>排名</th>
<th>次数</th>
<th>来源URL</th>
</tr>
</thead>
<tbody>
<tr>
<td>loading...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">文章浏览分析</h4>
<div class="typecho-table-wrap" id="pie-article">loading...</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">访客地域分析</h4>
<div class="typecho-table-wrap">
<ul class="typecho-option-tabs clearfix">
<li><button id="btn-china" class="btn btn-s primary">国内</button></li>
<li><button id="btn-inter" class="btn btn-s">国际</button><li>
</ul>
<div class="typecho-table-wrap" id="bar-location">loading...</div>
</div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">今日图表</h4>
<div class="typecho-table-wrap" id="chart-today"></div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">昨日图表</h4>
<div class="typecho-table-wrap" id="chart-yesterday"></div>
</div>
<div class="col-mb-12">
<h4 class="typecho-list-table-title">当月图表</h4>
<div class="typecho-table-wrap" id="chart-month"></div>
</div>
</div>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/highcharts.js')?>"></script>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/modules/exporting.js')?>"></script>
<script src="<?php $options->pluginUrl('Access/page/highcharts/js/modules/accessibility.js')?>"></script>
<script type="text/javascript" defer src="<?php $options->pluginUrl('Access/page/routes/overview/index.js')?>"></script>