mirror of
https://github.com/kokororin/typecho-plugin-Access.git
synced 2025-03-23 16:20:22 +08:00
refactor: 使用动态页面方式重构每次都需要重载的列表页面
This commit is contained in:
parent
7fbbbbd7f4
commit
0a2c0ee97e
194
Access_Logs.php
Normal file
194
Access_Logs.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
if (!defined('__ACCESS_PLUGIN_ROOT__')) {
|
||||
throw new Exception('Bootstrap file not found');
|
||||
}
|
||||
|
||||
class Access_Logs {
|
||||
/**
|
||||
* 允许访问的业务函数名及其对应的允许访问方法
|
||||
* @var string[]
|
||||
*/
|
||||
private static $rpcTypes = [
|
||||
'get' => 'GET',
|
||||
'delete' => 'POST',
|
||||
];
|
||||
|
||||
private $config;
|
||||
private $db;
|
||||
private $request;
|
||||
|
||||
public function __construct($request) {
|
||||
$this->db = Typecho_Db::get();
|
||||
$this->request = $request;
|
||||
$this->config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建过滤器对应的数据库查询语句
|
||||
*
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
private function filterQueryBuilder($query, $filters, $fuzzy)
|
||||
{
|
||||
$ids = array_key_exists('ids', $filters) ? $filters['ids'] : '';
|
||||
$ip = array_key_exists('ip', $filters) ? $filters['ip'] : '';
|
||||
$ua = array_key_exists('ua', $filters) ? $filters['ua'] : '';
|
||||
$cid = array_key_exists('cid', $filters) ? $filters['cid'] : '';
|
||||
$path = array_key_exists('path', $filters) ? $filters['path'] : '';
|
||||
$robot = array_key_exists('robot', $filters) ? $filters['robot'] : '';
|
||||
$compare = $fuzzy === '1' ? ' LIKE ?' : ' = ?';
|
||||
$empty = $fuzzy ? '%' : '';
|
||||
if (!empty($ids) && count($ids) > 0) {
|
||||
$query->where(join(' OR ', array_fill(0, count($ids), 'id = ?')), ...$ids);
|
||||
}
|
||||
if ($ip !== $empty) {
|
||||
$query->where('ip' . $compare, $ip);
|
||||
}
|
||||
if ($ua !== $empty) {
|
||||
$query->where('ua' . $compare, $ua);
|
||||
}
|
||||
if ($cid !== $empty) {
|
||||
$query->where('content_id' . $compare, $cid);
|
||||
}
|
||||
if ($path !== $empty) {
|
||||
$query->where('path' . $compare, $path);
|
||||
}
|
||||
if ($robot !== $empty) {
|
||||
$query->where('robot = ?', $robot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤器,获取详细访问日志数据
|
||||
*
|
||||
* @access private
|
||||
* @return ?array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(): ?array
|
||||
{
|
||||
$resp = [];
|
||||
$filters = array(
|
||||
'ip' => $this->request->get('ip', ''),
|
||||
'ua' => $this->request->get('ua', ''),
|
||||
'cid' => $this->request->get('cid', ''),
|
||||
'path' => $this->request->get('path', ''),
|
||||
'robot' => $this->request->get('robot', ''),
|
||||
);
|
||||
$fuzzy = $this->request->get('fuzzy', '');
|
||||
$pageSize = intval($this->config->pageSize);
|
||||
$pageNum = intval($this->request->get('page', 1));
|
||||
|
||||
$counterQuery = $this->db->select('count(1) AS count')->from('table.access_logs');
|
||||
$dataQuery = $this->db->select()->from('table.access_logs')
|
||||
->order('time', Typecho_Db::SORT_DESC)
|
||||
->offset((max(intval($pageNum), 1) - 1) * $pageSize)
|
||||
->limit($pageSize);
|
||||
|
||||
$this->filterQueryBuilder($dataQuery, $filters, $fuzzy);
|
||||
$this->filterQueryBuilder($counterQuery, $filters, $fuzzy);
|
||||
|
||||
$resp['count'] = $this->db->fetchAll($counterQuery)[0]['count'];
|
||||
$resp['pagination'] = [
|
||||
'size' => $pageSize,
|
||||
'current' => $pageNum,
|
||||
'total' => floor($resp['count'] / $pageSize),
|
||||
];
|
||||
$resp['logs'] = $this->db->fetchAll($dataQuery);
|
||||
foreach ($resp['logs'] as &$row) {
|
||||
$ua = new Access_UA($row['ua']);
|
||||
if ($ua->isRobot()) {
|
||||
$name = $ua->getRobotID();
|
||||
$version = $ua->getRobotVersion();
|
||||
} else {
|
||||
$name = $ua->getBrowserName();
|
||||
$version = $ua->getBrowserVersion();
|
||||
}
|
||||
if ($name == '') {
|
||||
$row['display_name'] = _t('未知');
|
||||
} elseif ($version == '') {
|
||||
$row['display_name'] = $name;
|
||||
} else {
|
||||
$row['display_name'] = $name . ' / ' . $version;
|
||||
}
|
||||
if($row['ip_country'] == '中国') {
|
||||
$row['ip_loc'] = "{$row['ip_province']} {$row['ip_city']}";
|
||||
} else {
|
||||
$row['ip_loc'] = $row['ip_country'];
|
||||
}
|
||||
}
|
||||
|
||||
return $resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤器,删除详细访问日志数据
|
||||
*
|
||||
* @access private
|
||||
* @return ?array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete(): ?array
|
||||
{
|
||||
$resp = [];
|
||||
|
||||
$counterQuery = $this->db->select('count(1) AS count')->from('table.access_logs');
|
||||
$operatorQuery = $this->db->delete('table.access_logs');
|
||||
|
||||
$ids = $this->request->get('ids', '');
|
||||
$ip = $this->request->get('ip', '');
|
||||
$ua = $this->request->get('ua', '');
|
||||
$cid = $this->request->get('cid', '');
|
||||
$path = $this->request->get('path', '');
|
||||
$robot = $this->request->get('robot', '');
|
||||
if ($ids) {
|
||||
$ids = Json::decode($ids, true);
|
||||
if (!is_array($ids)) {
|
||||
throw new Exception('Bad Request', 400);
|
||||
}
|
||||
$this->filterQueryBuilder($counterQuery, ['ids' => $ids], false);
|
||||
$this->filterQueryBuilder($operatorQuery, ['ids' => $ids], false);
|
||||
} else if ($ip || $ua || $cid || $path || $robot) {
|
||||
$filters = array(
|
||||
'ip' => $ip,
|
||||
'ua' => $ua,
|
||||
'cid' => $cid,
|
||||
'path' => $path,
|
||||
'robot' => $robot,
|
||||
);
|
||||
$fuzzy = $this->request->get('fuzzy', '');
|
||||
$this->filterQueryBuilder($counterQuery, $filters, $fuzzy);
|
||||
$this->filterQueryBuilder($operatorQuery, $filters, $fuzzy);
|
||||
} else {
|
||||
throw new Exception('Bad Request', 400);
|
||||
}
|
||||
|
||||
$resp['count'] = $this->db->fetchAll($counterQuery)[0]['count'];
|
||||
$this->db->query($operatorQuery);
|
||||
|
||||
return $resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务调度入口
|
||||
*
|
||||
* @access public
|
||||
* @param string rpcType 调用过程类型
|
||||
* @return ?array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function invoke(string $rpcType): ?array {
|
||||
if(!method_exists($this, $rpcType) || !array_key_exists($rpcType, Access_Logs::$rpcTypes))
|
||||
throw new Exception('Bad Request', 400);
|
||||
$method = Access_Logs::$rpcTypes[$rpcType];
|
||||
if (
|
||||
($method === 'GET' && !$this->request->isGet())
|
||||
|| ($method === 'POST' && !$this->request->isPost())
|
||||
|| ($method === 'PUT' && !$this->request->isPut())
|
||||
) {
|
||||
throw new Exception('Method Not Allowed', 405);
|
||||
}
|
||||
return $this->$rpcType();
|
||||
}
|
||||
}
|
21
Action.php
21
Action.php
@ -62,6 +62,27 @@ class Access_Action extends Typecho_Widget implements Widget_Interface_Do
|
||||
}
|
||||
}
|
||||
|
||||
public function logs() {
|
||||
try {
|
||||
$this->checkAuth(); # 鉴权
|
||||
$rpcType = $this->request->get('rpc'); # 业务类型
|
||||
$logs = new Access_Logs($this->request);
|
||||
$data = $logs->invoke($rpcType); # 进行业务分发并调取数据
|
||||
$errCode = 0;
|
||||
$errMsg = 'ok';
|
||||
} catch (Exception $e) {
|
||||
$data = null;
|
||||
$errCode = $e->getCode();
|
||||
$errMsg = $e->getMessage();
|
||||
}
|
||||
|
||||
$this->response->throwJson([
|
||||
'code' => $errCode,
|
||||
'message' => $errMsg,
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function statistic() {
|
||||
try {
|
||||
$this->checkAuth(); # 鉴权
|
||||
|
@ -25,6 +25,7 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
Helper::addPanel(1, self::$panel, _t('Access控制台'), _t('Access插件控制台'), 'subscriber');
|
||||
Helper::addRoute("access_track_gif", "/access/log/track.gif", "Access_Action", 'writeLogs');
|
||||
Helper::addRoute("access_delete_logs", "/access/log/delete", "Access_Action", 'deleteLogs');
|
||||
Helper::addRoute("access_logs", "/access/logs", "Access_Action", 'logs');
|
||||
Helper::addRoute('access_statistic_view', '/access/statistic/view', 'Access_Action', 'statistic');
|
||||
Typecho_Plugin::factory('Widget_Archive')->beforeRender = array('Access_Plugin', 'backend');
|
||||
Typecho_Plugin::factory('Widget_Archive')->footer = array('Access_Plugin', 'frontend');
|
||||
|
1
page/components/dayjs/index.js
Normal file
1
page/components/dayjs/index.js
Normal file
File diff suppressed because one or more lines are too long
1
page/components/loadingmodal/index.css
Normal file
1
page/components/loadingmodal/index.css
Normal file
File diff suppressed because one or more lines are too long
1
page/components/loadingmodal/index.js
Normal file
1
page/components/loadingmodal/index.js
Normal file
File diff suppressed because one or more lines are too long
33
page/components/object.assgin/index.js
Normal file
33
page/components/object.assgin/index.js
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Object.assign() - Polyfill
|
||||
*
|
||||
* @ref https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
if (typeof Object.assign != "function") {
|
||||
(function () {
|
||||
Object.assign = function (target) {
|
||||
"use strict";
|
||||
if (target === undefined || target === null) {
|
||||
throw new TypeError("Cannot convert undefined or null to object");
|
||||
}
|
||||
|
||||
var output = Object(target);
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var source = arguments[index];
|
||||
if (source !== undefined && source !== null) {
|
||||
for (var nextKey in source) {
|
||||
if (source.hasOwnProperty(nextKey)) {
|
||||
output[nextKey] = source[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
})();
|
||||
}
|
||||
})();
|
79
page/routes/logs/index.css
Normal file
79
page/routes/logs/index.css
Normal file
@ -0,0 +1,79 @@
|
||||
a[data-action="search-anchor"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.typecho-access-logs-search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
background: #f6f6f3;
|
||||
padding: 10px 20px;
|
||||
margin-top: 2px;
|
||||
border: 1px solid #e9e9e6;
|
||||
width: 400px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: ease-in-out opacity 0.3s;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter--visible {
|
||||
pointer-events: unset;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-item {
|
||||
margin: 5px 10px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-item__label {
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-item__content {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-apply {
|
||||
padding: 15px 10px 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-apply > *:not(:last-child) {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.typecho-access-logs-filter-apply__btn {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.typecho-access-logs-pagination-jump {
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.typecho-access-logs-pagination-jump__number {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.typecho-access-logs-pagination-jump__text {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.typecho-access-logs-pagination-jump__total {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.typecho-access-logs-pagination-item {
|
||||
cursor: pointer;
|
||||
}
|
@ -1,4 +1,240 @@
|
||||
$(document).ready(function () {
|
||||
var pageNum = 1;
|
||||
|
||||
function getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
function setPageNum(n) {
|
||||
pageNum = Number.parseInt(n, 10) || 1;
|
||||
}
|
||||
|
||||
function getFilters() {
|
||||
return {
|
||||
fuzzy: $('[name="filter-fuzzy"]').val(),
|
||||
ua: $('[name="filter-ua"]').val(),
|
||||
ip: $('[name="filter-ip"]').val(),
|
||||
cid: $('[name="filter-cid"]').val(),
|
||||
path: $('[name="filter-path"]').val(),
|
||||
robot: $('[name="filter-robot"]').val(),
|
||||
};
|
||||
}
|
||||
|
||||
function setFilters(filters) {
|
||||
$('[name="filter-fuzzy"]').val('fuzzy' in filters ? filters.fuzzy : '');
|
||||
$('[name="filter-ua"]').val('ua' in filters ? filters.ua : '');
|
||||
$('[name="filter-ip"]').val('ip' in filters ? filters.ip : '');
|
||||
$('[name="filter-cid"]').val('cid' in filters ? filters.cid : '');
|
||||
$('[name="filter-path"]').val('path' in filters ? filters.path : '');
|
||||
$('[name="filter-robot"]').val('robot' in filters ? filters.robot : '');
|
||||
}
|
||||
|
||||
function fetchLogs() {
|
||||
var startTime = new Date().valueOf();
|
||||
$('.typecho-list')
|
||||
.loadingModal({ text: '正在获取数据...', backgroundColor: '#292d33' })
|
||||
.loadingModal(
|
||||
'animation',
|
||||
[
|
||||
'doubleBounce',
|
||||
'rotatingPlane',
|
||||
// 'wave',
|
||||
// 'wanderingCubes',
|
||||
'foldingCube',
|
||||
][Math.floor(Math.random() * 3)]
|
||||
)
|
||||
.loadingModal('show');
|
||||
|
||||
$.ajax({
|
||||
url: "/access/logs",
|
||||
method: "get",
|
||||
dataType: "json",
|
||||
data: Object.assign(
|
||||
{ },
|
||||
getFilters(),
|
||||
{ rpc: 'get', page: getPageNum() }
|
||||
),
|
||||
success: function (res) {
|
||||
// make sure loading animation visible for better experience
|
||||
var minDuring = 300;
|
||||
var during = new Date().valueOf() - startTime;
|
||||
if (during < minDuring) {
|
||||
setTimeout(function() { $('.typecho-list').loadingModal('hide'); }, minDuring - during);
|
||||
} else {
|
||||
$('.typecho-list').loadingModal('hide');
|
||||
}
|
||||
if (res.code === 0) {
|
||||
// logs list
|
||||
var $tbody, $tr, $td;
|
||||
$tbody = $('.typecho-list-table tbody');
|
||||
$tbody.html('');
|
||||
$.each(res.data.logs, function(index, item) {
|
||||
$tr = $('<tr />', { id: item.id, 'data-id': item.id });
|
||||
// id
|
||||
$td = $('<td />');
|
||||
$td.append($('<input />', {
|
||||
type: 'checkbox',
|
||||
value: item.id,
|
||||
name: 'id[]',
|
||||
'data-id': item.id,
|
||||
}));
|
||||
$tr.append($td);
|
||||
// url
|
||||
$td = $('<td />');
|
||||
$td.append($('<a />', {
|
||||
'data-action': 'search-anchor',
|
||||
'data-filter': JSON.stringify({ path: item.path }),
|
||||
}).text(item.url.replace(/%23/u, '#')));
|
||||
$tr.append($td);
|
||||
// ua
|
||||
$td = $('<td />');
|
||||
$td.append($('<a />', {
|
||||
title: item.ua,
|
||||
'data-action': 'search-anchor',
|
||||
'data-filter': JSON.stringify({ ua: item.ua }),
|
||||
}).text(item.display_name));
|
||||
$tr.append($td);
|
||||
// ip
|
||||
$td = $('<td />');
|
||||
$td.append($('<a />', {
|
||||
'data-action': 'search-anchor',
|
||||
'data-filter': JSON.stringify({ ip: item.ip }),
|
||||
}).text(item.ip));
|
||||
$tr.append($td);
|
||||
// ip_loc
|
||||
$td = $('<td />');
|
||||
$td.append($('<span />').text(item.ip_loc));
|
||||
$tr.append($td);
|
||||
// referer
|
||||
$td = $('<td />');
|
||||
$td.append($('<a />', {
|
||||
'data-action': 'search-anchor',
|
||||
'data-filter': JSON.stringify({ referer: item.referer }),
|
||||
}).text(item.referer));
|
||||
$tr.append($td);
|
||||
// time
|
||||
$td = $('<td />');
|
||||
$td.append($('<span />').text(dayjs(item.time * 1000).format('YYYY-MM-DD hh:mm:ss')));
|
||||
$tr.append($td);
|
||||
// append row to table body
|
||||
$tbody.append($tr);
|
||||
});
|
||||
// logs pagination
|
||||
$('a[data-action="search-anchor"]').click(onSearchAnchorClick);
|
||||
|
||||
var $pagination;
|
||||
$pagination = $('.typecho-pager');
|
||||
$pagination.html('');
|
||||
|
||||
var startPage, stopPage;
|
||||
if (res.data.pagination.total <= 10 || res.data.pagination.current <= 5) {
|
||||
startPage = 1;
|
||||
stopPage = Math.min(res.data.pagination.total, res.data.pagination.current + 5);
|
||||
} else if (res.data.pagination.total - res.data.pagination.current <= 5) {
|
||||
startPage = res.data.pagination.total - 10;
|
||||
stopPage = res.data.pagination.total;
|
||||
} else {
|
||||
startPage = res.data.pagination.current - 5;
|
||||
stopPage = res.data.pagination.current + 5;
|
||||
}
|
||||
|
||||
if (startPage > 1) {
|
||||
$pagination.append(
|
||||
$('<li />')
|
||||
.append($('<a />', { class: 'typecho-access-logs-pagination-item', 'data-action': 'prev-page' })
|
||||
.text('«')
|
||||
.click(onPrevPage)
|
||||
)
|
||||
);
|
||||
}
|
||||
for (let index = startPage; index <= stopPage; index++) {
|
||||
$pagination.append(
|
||||
$('<li />', { class: index === res.data.pagination.current ? 'current' : '' })
|
||||
.append(
|
||||
$('<a />', {
|
||||
class: 'typecho-access-logs-pagination-item',
|
||||
'data-action': 'goto-page',
|
||||
'data-page': index,
|
||||
})
|
||||
.text(index)
|
||||
.click(onGotoPage)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (stopPage < res.data.pagination.total) {
|
||||
$pagination.append(
|
||||
$('<li />')
|
||||
.append($('<a />', { class: 'typecho-access-logs-pagination-item', 'data-action': 'next-page' })
|
||||
.text('»')
|
||||
.click(onNextPage)
|
||||
)
|
||||
);
|
||||
}
|
||||
$('input[name="page-jump"]').val(res.data.pagination.current);
|
||||
$('.typecho-access-logs-pagination-jump__total').text(res.data.pagination.total);
|
||||
} else {
|
||||
swal({
|
||||
icon: "error",
|
||||
title: "错误",
|
||||
text: "查询出错啦",
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
$('body').loadingModal('hide');
|
||||
swal({
|
||||
icon: "error",
|
||||
title: "错误",
|
||||
text: "请求错误 code: " + xhr.status,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onSearchAnchorClick(e) {
|
||||
setPageNum(1);
|
||||
setFilters(JSON.parse(e.target.getAttribute('data-filter')));
|
||||
$('button[data-action="apply"]').first().click();
|
||||
}
|
||||
|
||||
function onPrevPage() {
|
||||
setPageNum(getPageNum() - 1);
|
||||
fetchLogs();
|
||||
}
|
||||
|
||||
function onGotoPage(e) {
|
||||
setPageNum(e.target.getAttribute('data-page'));
|
||||
fetchLogs();
|
||||
}
|
||||
|
||||
function onNextPage() {
|
||||
setPageNum(getPageNum() + 1);
|
||||
fetchLogs();
|
||||
}
|
||||
|
||||
$('button[data-action="apply"]').click(function() {
|
||||
fetchLogs();
|
||||
$('.typecho-access-logs-filter').removeClass('typecho-access-logs-filter--visible');
|
||||
});
|
||||
|
||||
$('button[data-action="reset"]').click(function() {
|
||||
setPageNum(1);
|
||||
setFilters({ robot: '0' });
|
||||
fetchLogs();
|
||||
$('.typecho-access-logs-filter').removeClass('typecho-access-logs-filter--visible');
|
||||
});
|
||||
|
||||
$('button[data-action="switch-filter"]').click(function() {
|
||||
$('.typecho-access-logs-filter').toggleClass('typecho-access-logs-filter--visible');
|
||||
});
|
||||
|
||||
$('input[name="page-jump"]').on('keypress', function(e) {
|
||||
if (e.which == 13) {
|
||||
setPageNum(e.target.value);
|
||||
fetchLogs();
|
||||
}
|
||||
});
|
||||
|
||||
$('a[data-action="ua"]').click(function () {
|
||||
swal({
|
||||
icon: "info",
|
||||
@ -29,17 +265,19 @@ $(document).ready(function () {
|
||||
});
|
||||
if (ids.length != 0) {
|
||||
$.ajax({
|
||||
url: "/access/log/delete",
|
||||
url: "/access/logs",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(ids),
|
||||
success: function (data) {
|
||||
if (data.code == 0) {
|
||||
data: {
|
||||
rpc: 'delete',
|
||||
ids: JSON.stringify(ids),
|
||||
},
|
||||
success: function (res) {
|
||||
if (res.code == 0) {
|
||||
swal({
|
||||
icon: "success",
|
||||
title: "删除成功",
|
||||
text: "所选记录已删除",
|
||||
text: "成功删除" + res.data.count + "条记录",
|
||||
});
|
||||
$.each(ids, function (index, elem) {
|
||||
$('.typecho-list-table tbody tr[data-id="' + elem + '"]')
|
||||
@ -116,4 +354,6 @@ $(document).ready(function () {
|
||||
$form.find('button[type="button"]').on("click", function () {
|
||||
$form.submit();
|
||||
});
|
||||
|
||||
fetchLogs();
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
<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">
|
||||
@ -11,44 +10,51 @@
|
||||
</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('« 取消筛选'); ?></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 class="search typecho-access-logs-search" role="search">
|
||||
<button data-action="apply" type="button" class="btn btn-s"><?php _e('刷新'); ?></button>
|
||||
<button data-action="switch-filter" type="button" class="btn btn-s"><?php _e('筛选'); ?></button>
|
||||
<div class="typecho-access-logs-filter">
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">匹配方式</label>
|
||||
<select class="typecho-access-logs-filter-item__content" name="filter-fuzzy">
|
||||
<option value=""><?php _e('精确匹配'); ?></option>
|
||||
<option value="1"><?php _e('模糊匹配'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">UA</label>
|
||||
<input class="typecho-access-logs-filter-item__content" type="text" class="text-s" name="filter-ua" autocomplete="off" />
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">IP</label>
|
||||
<input class="typecho-access-logs-filter-item__content" type="text" class="text-s" name="filter-ip" autocomplete="off" />
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">文章ID</label>
|
||||
<select class="typecho-access-logs-filter-item__content" name="filter-cid">
|
||||
<option value=""><?php _e('不限'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">受访地址</label>
|
||||
<input class="typecho-access-logs-filter-item__content" type="text" class="text-s" name="filter-path" autocomplete="off" />
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-item">
|
||||
<label class="typecho-access-logs-filter-item__label">访客类型</label>
|
||||
<select class="typecho-access-logs-filter-item__content" name="filter-robot">
|
||||
<option value="0"><?php _e('默认(仅人类)'); ?></option>
|
||||
<option value="1"><?php _e('仅爬虫'); ?></option>
|
||||
<option value=""><?php _e('所有'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="typecho-access-logs-filter-apply">
|
||||
<button class="btn btn-m typecho-access-logs-filter-apply__btn" data-action="reset" type="button"><?php _e('重 置'); ?></button>
|
||||
<button class="btn btn-m typecho-access-logs-filter-apply__btn" data-action="apply" type="button"><?php _e('应 用'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" class="operate-form">
|
||||
<div class="typecho-table-wrap">
|
||||
<table class="typecho-list-table">
|
||||
<colgroup>
|
||||
@ -56,9 +62,9 @@
|
||||
<col width="28%"/>
|
||||
<col width="25%"/>
|
||||
<col width="18%"/>
|
||||
<col width="16%"/>
|
||||
<col width="14%"/>
|
||||
<col width="20%"/>
|
||||
<col width="20%"/>
|
||||
<col width="18%"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -72,50 +78,46 @@
|
||||
</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>
|
||||
<td colspan="7"><h6 class="typecho-list-table-title">loading</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 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>
|
||||
<span><?php _e('选中项'); ?></span>
|
||||
<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 class="typecho-access-logs-pagination-jump">
|
||||
<input class="text-s typecho-access-logs-pagination-jump__number" type="text" name="page-jump" autocomplete="off" />
|
||||
<span class="typecho-access-logs-pagination-jump__text">/</span>
|
||||
<span class="typecho-access-logs-pagination-jump__total">loading</span>
|
||||
</div>
|
||||
<ul class="typecho-pager"></ul>
|
||||
</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>
|
||||
<script src="<?php $options->pluginUrl('Access/page/components/object.assign/index.js')?>"></script>
|
||||
<script src="<?php $options->pluginUrl('Access/page/components/sweetalert/index.js')?>"></script>
|
||||
<script src="<?php $options->pluginUrl('Access/page/components/dayjs/index.js')?>"></script>
|
||||
<link rel="stylesheet" href="<?php $options->pluginUrl('Access/page/components/loadingmodal/index.css')?>">
|
||||
<script defer src="<?php $options->pluginUrl('Access/page/components/loadingmodal/index.js')?>"></script>
|
||||
<link rel="stylesheet" href="<?php $options->pluginUrl('Access/page/routes/logs/index.css')?>">
|
||||
<script defer src="<?php $options->pluginUrl('Access/page/routes/logs/index.js')?>"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user