diff --git a/Access_Logs.php b/Access_Logs.php new file mode 100644 index 0000000..34c6948 --- /dev/null +++ b/Access_Logs.php @@ -0,0 +1,194 @@ + '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(); + } +} diff --git a/Action.php b/Action.php index 76da50a..2a1dcd4 100644 --- a/Action.php +++ b/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(); # 鉴权 diff --git a/Plugin.php b/Plugin.php index 2ea85d6..f23b4de 100644 --- a/Plugin.php +++ b/Plugin.php @@ -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'); diff --git a/page/components/dayjs/index.js b/page/components/dayjs/index.js new file mode 100644 index 0000000..088a14f --- /dev/null +++ b/page/components/dayjs/index.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){"use strict";var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",f="month",h="quarter",c="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},w=function(t,e){if(p(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},O=v;O.l=S,O.i=p,O.w=function(t,e){return w(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=S(t.locale,null,!0),this.parse(t)}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(O.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.$x=t.x||{},this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return O},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=w(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return w(t)
'},rotatingPlane:{html:'
',setBackground:function(i){e.animationBox.find("*").each(function(c,t){s(t).css("background-color")&&"rgba(0, 0, 0, 0)"!=s(t).css("background-color")&&s(t).css("background-color",i)})}},wave:{html:'
'},wanderingCubes:{html:'
'},spinner:{html:'
'},chasingDots:{html:'
'},threeBounce:{html:'
'},circle:{html:'
',setBackground:function(c){e.animationBox.children().find("*").each(function(t,e){"rgba(0, 0, 0, 0)"!==i.getComputedStyle(e,":before").getPropertyValue("background-color")&&s("body").append(s(""))})}},cubeGrid:{html:'
'},fadingCircle:{html:'
',setBackground:function(c){e.animationBox.children().find("*").each(function(t,e){"rgba(0, 0, 0, 0)"!==i.getComputedStyle(e,":before").getPropertyValue("background-color")&&s("body").append(s(""))})}},foldingCube:{html:'
',setBackground:function(c){e.animationBox.find("*").each(function(t,e){"rgba(0, 0, 0, 0)"!==i.getComputedStyle(e,":before").getPropertyValue("background-color")&&s("body").append(s(""))})}}},this.settings=s.extend({},l,t),this.modal=null,this.modalText=null,this.animationBox=null,this.modalBg=null,this.currenAnimation=null,this.init(),this}var d="loadingModal",l={position:"auto",text:"",color:"#fff",opacity:"0.7",backgroundColor:"rgb(0,0,0)",animation:"doubleBounce"};s.extend(e.prototype,{init:function(){var i=s('
'),c=s('
').css({background: this.settings.backgroundColor}),t=s('
'),e=s('
'),d=s('
');""!==this.settings.text?d.html(this.settings.text):d.hide(),this.currenAnimation=this.animations[this.settings.animation],t.append(this.currenAnimation.html),e.append(t).append(d),i.append(c),i.append(e),"auto"===this.settings.position&&"body"!==this.element.tagName.toLowerCase()?(i.css("position","absolute"),s(this.element).css("position","relative")):"auto"!==this.settings.position&&s(this.element).css("position",this.settings.position),s(this.element).append(i),this.modalBg=c,this.modal=i,this.modalText=d,this.animationBox=t,this.color(this.settings.color),this.backgroundColor(this.settings.backgroundColor),this.opacity(this.settings.opacity)},hide:function(){var s=this.modal;s.removeClass("jquery-loading-modal--visible").addClass("jquery-loading-modal--hidden"),s.css({'opacity':'0'})},backgroundColor:function(s){this.modalBg.css({"background-color":s})},color:function(c){s("[data-custom-style]").remove(),this.modalText.css("color",c),this.currenAnimation.setBackground?this.currenAnimation.setBackground(c):this.animationBox.children().find("*").each(function(t,e){s(e).css("background-color")&&"rgba(0, 0, 0, 0)"!=s(e).css("background-color")&&s(e).css("background-color",c),"rgba(0, 0, 0, 0)"!==i.getComputedStyle(e,":before").getPropertyValue("background-color")&&s("body").append(s(""))})},opacity:function(s){this.modalBg.css({opacity:s})},show:function(){this.modal.show().removeClass("jquery-loading-modal--hidden").addClass("jquery-loading-modal--visible").css({'opacity':this.settings.opacity})},animation:function(s){this.animationBox.html(""),this.currenAnimation=this.animations[s],this.animationBox.append(this.currenAnimation.html)},destroy:function(){s("[data-custom-style]").remove(),this.modal.remove()},text:function(s){this.modalText.html(s)}}),s.fn[d]=function(i){var c=arguments;if(i===t||"object"==typeof i)return this.each(function(){s.data(this,"plugin_"+d)||s.data(this,"plugin_"+d,new e(this,i))});if("string"==typeof i&&"_"!==i[0]&&"init"!==i){var l;return this.each(function(){var t=s.data(this,"plugin_"+d);t instanceof e&&"function"==typeof t[i]&&(l=t[i].apply(t,Array.prototype.slice.call(c,1))),"destroy"===i&&s.data(this,"plugin_"+d,null)}),l!==t?l:this}}}(jQuery,window,document); diff --git a/page/components/object.assgin/index.js b/page/components/object.assgin/index.js new file mode 100644 index 0000000..86d85cf --- /dev/null +++ b/page/components/object.assgin/index.js @@ -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; + }; + })(); + } +})(); diff --git a/page/sweetalert.min.js b/page/components/sweetalert/index.js similarity index 100% rename from page/sweetalert.min.js rename to page/components/sweetalert/index.js diff --git a/page/routes/logs/index.css b/page/routes/logs/index.css new file mode 100644 index 0000000..54c55a9 --- /dev/null +++ b/page/routes/logs/index.css @@ -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; +} diff --git a/page/routes/logs/index.js b/page/routes/logs/index.js index 2a6d40a..42d037f 100644 --- a/page/routes/logs/index.js +++ b/page/routes/logs/index.js @@ -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 = $('', { id: item.id, 'data-id': item.id }); + // id + $td = $(''); + $td.append($('', { + type: 'checkbox', + value: item.id, + name: 'id[]', + 'data-id': item.id, + })); + $tr.append($td); + // url + $td = $(''); + $td.append($('', { + 'data-action': 'search-anchor', + 'data-filter': JSON.stringify({ path: item.path }), + }).text(item.url.replace(/%23/u, '#'))); + $tr.append($td); + // ua + $td = $(''); + $td.append($('', { + title: item.ua, + 'data-action': 'search-anchor', + 'data-filter': JSON.stringify({ ua: item.ua }), + }).text(item.display_name)); + $tr.append($td); + // ip + $td = $(''); + $td.append($('', { + 'data-action': 'search-anchor', + 'data-filter': JSON.stringify({ ip: item.ip }), + }).text(item.ip)); + $tr.append($td); + // ip_loc + $td = $(''); + $td.append($('').text(item.ip_loc)); + $tr.append($td); + // referer + $td = $(''); + $td.append($('', { + 'data-action': 'search-anchor', + 'data-filter': JSON.stringify({ referer: item.referer }), + }).text(item.referer)); + $tr.append($td); + // time + $td = $(''); + $td.append($('').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( + $('
  • ') + .append($('', { class: 'typecho-access-logs-pagination-item', 'data-action': 'prev-page' }) + .text('«') + .click(onPrevPage) + ) + ); + } + for (let index = startPage; index <= stopPage; index++) { + $pagination.append( + $('
  • ', { class: index === res.data.pagination.current ? 'current' : '' }) + .append( + $('', { + 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( + $('
  • ') + .append($('', { 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(); }); diff --git a/page/routes/logs/index.php b/page/routes/logs/index.php index 67028e9..89ec095 100644 --- a/page/routes/logs/index.php +++ b/page/routes/logs/index.php @@ -1,6 +1,5 @@
    -
    @@ -11,44 +10,51 @@
    -
    -
    -
    @@ -56,9 +62,9 @@ - + + - @@ -72,50 +78,46 @@ - logs['list'])): ?> - logs['list'] as $log): ?> - - - - - - - - - - - - + -
    loading
    -
    -
    - -
    - -
    - - -
    +
    + +
    + +
    +
    - - logs['rows'] > 1): ?> -
      - logs['page']; ?> -
    - - +
    + + / + loading +
    +
      - - + + + + + + +