mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2025-04-24 02:16:14 +08:00
增加数据日志开关
This commit is contained in:
parent
7e9c209c65
commit
c2a5e46c2a
@ -16,6 +16,7 @@
|
|||||||
namespace app\admin\controller;
|
namespace app\admin\controller;
|
||||||
|
|
||||||
use think\admin\Controller;
|
use think\admin\Controller;
|
||||||
|
use think\admin\service\AdminService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统日志管理
|
* 系统日志管理
|
||||||
@ -42,6 +43,7 @@ class Oplog extends Controller
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$this->title = '系统日志管理';
|
$this->title = '系统日志管理';
|
||||||
|
$this->isSupper = AdminService::instance()->isSuper();
|
||||||
$query = $this->_query($this->table)->like('action,node,content,username,geoip');
|
$query = $this->_query($this->table)->like('action,node,content,username,geoip');
|
||||||
$query->dateBetween('create_at')->order('id desc')->page();
|
$query->dateBetween('create_at')->order('id desc')->page();
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,27 @@ class Plugs extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据变更日志
|
||||||
|
* @login true
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
*/
|
||||||
|
public function oplog()
|
||||||
|
{
|
||||||
|
if (AdminService::instance()->isSuper()) {
|
||||||
|
$data = $this->_vali([
|
||||||
|
'state.in:0,1' => '状态值范围错误!',
|
||||||
|
'state.require' => '状态值不能为空!',
|
||||||
|
]);
|
||||||
|
sysconf('base.oplog_state', $data['state']);
|
||||||
|
$this->success('数据变更日志切换成功!');
|
||||||
|
} else {
|
||||||
|
$this->error('只有超级管理员才能操作!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前运行模式
|
* 当前运行模式
|
||||||
* @login true
|
* @login true
|
||||||
|
@ -17,44 +17,55 @@ use think\admin\service\AdminService;
|
|||||||
use think\admin\service\SystemService;
|
use think\admin\service\SystemService;
|
||||||
use think\helper\Str;
|
use think\helper\Str;
|
||||||
|
|
||||||
/*! 全局操作日志数据 */
|
try {
|
||||||
$GLOBALS['oplogs'] = [];
|
/*! 全局数据变更数据 */
|
||||||
|
$GLOBALS['oplogs'] = [];
|
||||||
/*! 操作日志批量写入 */
|
/*! 数据变更日志开关状态 */
|
||||||
app()->event->listen('HttpEnd', function () {
|
if (intval(sysconf('base.oplog_state'))) {
|
||||||
if (is_array($GLOBALS['oplogs']) && count($GLOBALS['oplogs']) > 0) {
|
/*! 数据变更批量写入 */
|
||||||
foreach (array_chunk($GLOBALS['oplogs'], 100) as $items) {
|
app()->event->listen('HttpEnd', function () {
|
||||||
app()->db->name('SystemOplog')->insertAll($items);
|
if (is_array($GLOBALS['oplogs']) && count($GLOBALS['oplogs']) > 0) {
|
||||||
}
|
foreach (array_chunk($GLOBALS['oplogs'], 100) as $items) {
|
||||||
$GLOBALS['oplogs'] = [];
|
app()->db->name('SystemOplog')->insertAll($items);
|
||||||
if (rand(1, 100) <= 10) {
|
}
|
||||||
$lastdate = date('Y-m-d H:i:s', strtotime('-7days'));
|
$GLOBALS['oplogs'] = [];
|
||||||
app()->db->name('SystemOplog')->where('create_at', '<', $lastdate)->delete();
|
if (rand(1, 100) <= 10) { /*! 清理一周前的日志记录 */
|
||||||
}
|
$lastdate = date('Y-m-d H:i:s', strtotime('-7days'));
|
||||||
|
app()->db->name('SystemOplog')->where('create_at', '<', $lastdate)->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/*! 数据操作SQL语句监听分析 */
|
||||||
|
app()->db->listen(function ($sqlstr) {
|
||||||
|
[$type,] = explode(' ', $sqlstr);
|
||||||
|
if (in_array($type, ['INSERT', 'UPDATE', 'DELETE']) && AdminService::instance()->isLogin()) {
|
||||||
|
[$sqlstr] = explode('GROUP BY', explode('ORDER BY', $sqlstr)[0]);
|
||||||
|
if (preg_match('/^INSERT\s+INTO\s+`(.*?)`\s+SET\s+(.*?)\s*$/i', $sqlstr, $matches)) {
|
||||||
|
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
||||||
|
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 800);
|
||||||
|
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", $matches[2]);
|
||||||
|
}
|
||||||
|
} elseif (preg_match('/^INSERT\s*INTO\s*`(.*?)`\s*\((.*?)\)\s*VALUES\s+\((.*?)\)\s*$/i', $sqlstr, $matches)) {
|
||||||
|
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
||||||
|
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 150);
|
||||||
|
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 800);
|
||||||
|
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", "{$matches[2]} VALUES {$matches[3]}");
|
||||||
|
}
|
||||||
|
} elseif (preg_match('/^UPDATE\s+`(.*?)`\s+SET\s+(.*?)\s+WHERE\s+(.*?)\s*$/i', $sqlstr, $matches)) {
|
||||||
|
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
||||||
|
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 0, 150);
|
||||||
|
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 800);
|
||||||
|
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("更新 {$matches[1]} 数据 {$matches[3]}", $matches[2]);
|
||||||
|
}
|
||||||
|
} elseif (preg_match('/^DELETE\s*FROM\s*`(.*?)`\s*WHERE\s*(.*?)\s*$/i', $sqlstr, $matches)) {
|
||||||
|
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
||||||
|
$matches[2] = str_replace(['`', '\''], '', $matches[2]);
|
||||||
|
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("删除 {$matches[1]} 数据 {$matches[2]}", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
} catch (\Exception $exception) {
|
||||||
|
app()->log->error($exception->getMessage());
|
||||||
/*! 数据操作监听分析 */
|
}
|
||||||
app()->db->listen(function ($sqlstr) {
|
|
||||||
[$type,] = explode(' ', $sqlstr);
|
|
||||||
if (in_array($type, ['INSERT', 'UPDATE', 'DELETE']) && AdminService::instance()->isLogin()) {
|
|
||||||
[$sqlstr] = explode('GROUP BY', explode('ORDER BY', $sqlstr)[0]);
|
|
||||||
if (preg_match('/^INSERT\s+INTO\s+`(.*?)`\s+SET\s+(.*?)\s*$/i', $sqlstr, $matches)) {
|
|
||||||
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
|
||||||
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 200);
|
|
||||||
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", "添加数据:{$matches[2]}");
|
|
||||||
}
|
|
||||||
} elseif (preg_match('/^UPDATE\s+`(.*?)`\s+SET\s+(.*?)\s+WHERE\s+(.*?)\s*$/i', $sqlstr, $matches)) {
|
|
||||||
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
|
||||||
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 0, 200);
|
|
||||||
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 200);
|
|
||||||
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("更新 {$matches[1]} 数据 {$matches[3]}", "更新内容 {$matches[2]}");
|
|
||||||
}
|
|
||||||
} elseif (preg_match('/^DELETE\s*FROM\s*`(.*?)`\s*WHERE\s*(.*?)\s*$/i', $sqlstr, $matches)) {
|
|
||||||
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
|
|
||||||
$matches[2] = str_replace(['`', '\''], '', $matches[2]);
|
|
||||||
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("删除 {$matches[1]} 数据", "删除条件 {$matches[2]}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -16,8 +16,8 @@
|
|||||||
<div class="layui-card-header notselect">
|
<div class="layui-card-header notselect">
|
||||||
<b>运行模式</b><span class="color-desc font-s12 padding-left-5">Run Mode</span>
|
<b>运行模式</b><span class="color-desc font-s12 padding-left-5">Run Mode</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card-body nowrap">
|
<div class="layui-card-body">
|
||||||
<div class="layui-btn-group">
|
<div class="layui-btn-group nowrap">
|
||||||
{if $app->isDebug()}
|
{if $app->isDebug()}
|
||||||
<a class="layui-btn layui-btn-sm layui-btn-active" data-tips-text="当前以开发模式运行中...">以开发模式运行</a>
|
<a class="layui-btn layui-btn-sm layui-btn-active" data-tips-text="当前以开发模式运行中...">以开发模式运行</a>
|
||||||
<a class="layui-btn layui-btn-sm layui-btn-primary" data-tips-text="立即切换到生产模式运行" data-load="{:url('admin/api.plugs/debug')}?state=1">以生产模式运行</a>
|
<a class="layui-btn layui-btn-sm layui-btn-primary" data-tips-text="立即切换到生产模式运行" data-load="{:url('admin/api.plugs/debug')}?state=1">以生产模式运行</a>
|
||||||
@ -27,6 +27,10 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<p><b>开发模式</b>:开发人员或在功能调试时使用,系统异常时会显示详细的错误信息,同时还会记录操作日志及数据库SQL语句信息。</p>
|
||||||
|
<p><b>生产模式</b>:项目正式部署上线后使用,系统异常时统一显示 “{:config('app.error_message')}”,只记录重要的异常日志信息,强烈推荐上线后使用此模式。</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
|
|
||||||
@ -34,8 +38,8 @@
|
|||||||
<div class="layui-card-header notselect">
|
<div class="layui-card-header notselect">
|
||||||
<b>存储引擎</b><span class="color-desc font-s12 padding-left-5">Storage Engine</span>
|
<b>存储引擎</b><span class="color-desc font-s12 padding-left-5">Storage Engine</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card-body nowrap">
|
<div class="layui-card-body">
|
||||||
<div class="layui-btn-group">
|
<div class="layui-btn-group nowrap">
|
||||||
{foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','alioss'=>'阿里云OSS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
|
{foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','alioss'=>'阿里云OSS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
|
||||||
{if auth('storage')}<a data-title="配置{$v}" data-tips-text="切换并配置以{$v}文件" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
|
{if auth('storage')}<a data-title="配置{$v}" data-tips-text="切换并配置以{$v}文件" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
|
||||||
{else}
|
{else}
|
||||||
@ -43,6 +47,11 @@
|
|||||||
{/if}{/foreach}
|
{/if}{/foreach}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<p><b>本地服务器存储</b>:文件直接上传到本地服务器的 `static/upload` 目录,不支持大文件上传,占用服务器磁盘空间,访问时消耗服务器带宽流量。</p>
|
||||||
|
<p><b>七牛云对象存储</b>:文件直接上传到七牛云存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
|
||||||
|
<p><b>阿里云OSS存储</b>:文件直接上传到阿里云OSS存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-card padding-20">
|
<div class="layui-card padding-20">
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
{extend name='main'}
|
{extend name='main'}
|
||||||
|
|
||||||
{block name="button"}
|
{block name="button"}
|
||||||
|
<!--{if isset($isSupper) and $isSupper}-->
|
||||||
|
<div class="layui-form inline-block">
|
||||||
|
<!--{if intval(sysconf('base.oplog_state')) eq 1}-->
|
||||||
|
<input type="checkbox" title="数据变更日志" value="0" checked lay-filter="OplogState">
|
||||||
|
<!--{else}-->
|
||||||
|
<input type="checkbox" title="数据变更日志" value="1" lay-filter="OplogState">
|
||||||
|
<!--{/if}-->
|
||||||
|
<script>
|
||||||
|
form.render(), form.on('checkbox(OplogState)', function (elem) {
|
||||||
|
$.form.load('{:url("admin/api.plugs/oplog")}', {state: elem.value});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<!--{/if}-->
|
||||||
|
|
||||||
<!--{if auth("clear")}-->
|
<!--{if auth("clear")}-->
|
||||||
<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
|
<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
|
||||||
<!--{/if}-->
|
<!--{/if}-->
|
||||||
|
|
||||||
<!--{if auth("remove")}-->
|
<!--{if auth("remove")}-->
|
||||||
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('remove')}" data-confirm="确定要删除日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
|
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('remove')}" data-confirm="确定要删除日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
|
||||||
<!--{/if}-->
|
<!--{/if}-->
|
||||||
@ -36,9 +52,11 @@
|
|||||||
操作账号:<span class="font-w7">{$vo.username|default='-'}</span><br>
|
操作账号:<span class="font-w7">{$vo.username|default='-'}</span><br>
|
||||||
操作节点:<span class="color-desc">{$vo.node|default='-'}</span>
|
操作节点:<span class="color-desc">{$vo.node|default='-'}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class='text-left nowrap'>
|
<td class='text-left nowrap padding-row-0 padding-right-0'>
|
||||||
<p class="color-text layui-elip" style="max-width:550px">{$vo.action|default='-'}</p>
|
<div style="overflow:auto;max-height:58px;padding:5px 0">
|
||||||
<p class="color-desc layui-elip" style="max-width:550px">{$vo.content|default='-'}</p>
|
<p class="color-text layui-elip" style="max-width:550px">{$vo.action|default='-'}</p>
|
||||||
|
<div class="color-desc layui-elip" style="white-space:normal">{$vo.content|default='-'}</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class='text-left nowrap'>
|
<td class='text-left nowrap'>
|
||||||
<p class="color-text">{$vo.geoip|default='-'}</p>
|
<p class="color-text">{$vo.geoip|default='-'}</p>
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -61,11 +61,18 @@ fieldset {
|
|||||||
|
|
||||||
&-group {
|
&-group {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
line-height: 28px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: #009688;
|
background: #009688;
|
||||||
border: 1px solid #009688 !important;
|
border: 1px solid #009688 !important;
|
||||||
|
|
||||||
|
+ .layui-btn {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.layui-btn {
|
.layui-btn {
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
border-width: 0 !important;
|
border-width: 0 !important;
|
||||||
|
|
||||||
+ .layui-btn {
|
+ .layui-btn {
|
||||||
@ -93,6 +100,7 @@ fieldset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! 搜索表单样式 */
|
/*! 搜索表单样式 */
|
||||||
.form-search {
|
.form-search {
|
||||||
.layui-btn {
|
.layui-btn {
|
||||||
@ -257,11 +265,16 @@ label.think-radio, label.think-checkbox {
|
|||||||
line-height: 24px !important
|
line-height: 24px !important
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Layui 样式调整 */
|
|
||||||
.layui-input, .layui-select {
|
.layui-input, .layui-select {
|
||||||
line-height: 38px
|
line-height: 38px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-form-checkbox.layui-form-checked {
|
||||||
|
i {
|
||||||
|
border-color: #5FB878;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.layui-table {
|
.layui-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user