refactor(admin): optimize log data processing and display

- Update log data serialization and deserialization method
- Improve log data display format in the admin interface- Refactor log model initialization and table suffix handling
- Optimize time model configuration for better timestamp management
This commit is contained in:
wolfcode
2025-03-25 18:08:35 +08:00
parent fc202be987
commit 12b38c7bf5
18 changed files with 214 additions and 108 deletions

View File

@@ -213,4 +213,23 @@ class Ajax extends AdminController
return json($config);
}
}
public function composerInfo(): Json
{
$lockFilePath = root_path() . '/composer.lock';
$list = [];
if (file_exists($lockFilePath)) {
$lockFileContent = file_get_contents($lockFilePath);
if ($lockFileContent !== false) {
$lockData = json_decode($lockFileContent, true);
if (!empty($lockData['packages'])) {
foreach ($lockData['packages'] as $package) {
$list[] = ['name' => $package['name'], 'version' => $package['version']];
}
}
}
}
$this->success('success', $list);
}
}

View File

@@ -41,12 +41,12 @@ class Config extends AdminController
if ($group == 'upload') {
$upload_types = config('admin.upload_types');
// 兼容旧版本
$this->model->where('name', 'upload_allow_type')->update(['value' => implode(',', array_keys($upload_types))]);
$this->model->removeOption('where')->where('name', 'upload_allow_type')->update(['value' => implode(',', array_keys($upload_types))]);
}
foreach ($post as $key => $val) {
if (in_array($key, $notAddFields)) continue;
if ($this->model->where('name', $key)->count()) {
$this->model->where('name', $key)->update(['value' => $val,]);
if ($this->model->removeOption('where')->where('name', $key)->count()) {
$this->model->removeOption('where')->where('name', $key)->update(['value' => $val,]);
}else {
$this->model->create(
[
@@ -59,7 +59,7 @@ class Config extends AdminController
TriggerService::updateMenu();
TriggerService::updateSysConfig();
}catch (\Exception $e) {
$this->error('保存失败');
$this->error('保存失败' .$e->getMessage());
}
$this->success('保存成功');
}

View File

@@ -34,7 +34,7 @@ class Log extends AdminController
}
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
$model = $this->model->setMonth($month)->with('admin')->where($where);
$model = $this->model->setSuffix("_$month")->with('admin')->where($where);
try {
$count = $model->count();
$list = $model->page($page, $limit)->order($this->sort)->select();
@@ -60,7 +60,8 @@ class Log extends AdminController
$this->error('演示环境下不允许操作');
}
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
$tableName = $this->model->getName();
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
$tableName = $this->model->setSuffix("_$month")->getName();
$tableName = CommonTool::humpToLine(lcfirst($tableName));
$prefix = config('database.connections.mysql.prefix');
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
@@ -71,15 +72,18 @@ class Log extends AdminController
$header[] = [$comment, $vo['Field']];
}
}
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
$model = $this->model->setMonth($month)->with('admin')->where($where);
$model = $this->model->setSuffix("_$month")->with('admin')->where($where);
try {
$list = $model
->where($where)
->limit(100000)
->limit(10000)
->order('id', 'desc')
->select()
->toArray();
foreach ($list as &$vo) {
$vo['content'] = json_encode($vo['content'], JSON_UNESCAPED_UNICODE);
$vo['response'] = json_encode($vo['response'], JSON_UNESCAPED_UNICODE);
}
}catch (PDOException|DbException $exception) {
$this->error($exception->getMessage());
}

View File

@@ -10,6 +10,9 @@ use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\NodeService;
use app\Request;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
#[ControllerAnnotation(title: '系统节点管理')]
@@ -55,11 +58,11 @@ class Node extends AdminController
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$updateNodeList = $model->removeOption('where')->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']])
&& $model->where('id', $vo['id'])->update(
&& $model->removeOption('where')->where('id', $vo['id'])->update(
[
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
@@ -67,7 +70,7 @@ class Node extends AdminController
);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
$existNodeList = $model->removeOption('where')->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
@@ -76,8 +79,10 @@ class Node extends AdminController
}
}
}
$model->saveAll($nodeList);
TriggerService::updateNode();
if (!empty($nodeList)) {
$model->saveAll($nodeList);
TriggerService::updateNode();
}
}catch (\Exception $e) {
$this->error('节点更新失败');
}

View File

@@ -8,6 +8,11 @@ use app\common\model\TimeModel;
class MallCate extends TimeModel
{
protected $deleteTime = 'delete_time';
protected function getOptions(): array
{
return [
'deleteTime' => 'delete_time',
];
}
}

View File

@@ -8,7 +8,12 @@ use app\common\model\TimeModel;
class SystemAdmin extends TimeModel
{
protected $deleteTime = 'delete_time';
protected function getOptions(): array
{
return [
'deleteTime' => 'delete_time',
];
}
public array $notes = [
'login_type' => [
@@ -17,12 +22,9 @@ class SystemAdmin extends TimeModel
],
];
public function getAuthList()
public function getAuthList(): array
{
$list = (new SystemAuth())
->where('status', 1)
->column('title', 'id');
return $list;
return (new SystemAuth())->removeOption('where')->where('status', 1)->column('title', 'id');
}
}

View File

@@ -3,44 +3,52 @@
namespace app\admin\model;
use app\common\model\TimeModel;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class SystemAuth extends TimeModel
{
protected $deleteTime = 'delete_time';
protected function getOptions(): array
{
return [
'deleteTime' => 'delete_time',
];
}
/**
* 根据角色ID获取授权节点
* @param $authId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getAuthorizeNodeListByAdminId($authId)
public function getAuthorizeNodeListByAdminId($authId): array
{
$checkNodeList = (new SystemAuthNode())
->where('auth_id', $authId)
->column('node_id');
$systemNode = new SystemNode();
$nodelList = $systemNode
$systemNode = new SystemNode();
$nodeList = $systemNode
->where('is_auth', 1)
->field('id,node,title,type,is_auth')
->select()
->toArray();
$newNodeList = [];
foreach ($nodelList as $vo) {
$newNodeList = [];
foreach ($nodeList as $vo) {
if ($vo['type'] == 1) {
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
$vo['checked'] = false;
$vo['title'] = "{$vo['title']}{$vo['node']}";
$children = [];
foreach ($nodelList as $v) {
$vo['title'] = "{$vo['title']}{$vo['node']}";
$children = [];
foreach ($nodeList as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
$v['checked'] = in_array($v['id'], $checkNodeList) ? true : false;
$v['title'] = "{$v['title']}{$v['node']}";
$children[] = $v;
$v['title'] = "{$v['title']}{$v['node']}";
$children[] = $v;
}
}
!empty($children) && $vo['children'] = $children;

View File

@@ -4,24 +4,23 @@ namespace app\admin\model;
use app\admin\service\SystemLogService;
use app\common\model\TimeModel;
use think\model\relation\BelongsTo;
class SystemLog extends TimeModel
{
public function __construct(array $data = [])
{
parent::__construct($data);
$this->name = 'system_log_' . date('Ym');
}
protected array $type = [
'content' => 'json',
'response' => 'json',
];
public function setMonth($month)
protected function init(): void
{
SystemLogService::instance()->detectTable();
$this->name = 'system_log_' . $month;
return $this;
}
public function admin()
public function admin(): BelongsTo
{
return $this->belongsTo('app\admin\model\SystemAdmin', 'admin_id', 'id');
}

View File

@@ -4,31 +4,41 @@ namespace app\admin\model;
use app\common\constants\MenuConstant;
use app\common\model\TimeModel;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class SystemMenu extends TimeModel
{
protected $deleteTime = 'delete_time';
public function getPidMenuList()
protected function getOptions(): array
{
$list = $this->field('id,pid,title')
->where([
['pid', '<>', MenuConstant::HOME_PID],
['status', '=', 1],
])
->select()
->toArray();
return [
'deleteTime' => 'delete_time',
];
}
/**
* @throws ModelNotFoundException
* @throws DbException
* @throws DataNotFoundException
*/
public function getPidMenuList(): array
{
$list = $this->removeOption('where')->field('id,pid,title')->where([
['pid', '<>', MenuConstant::HOME_PID],
['status', '=', 1],
])->select()->toArray();
$pidMenuList = $this->buildPidMenu(0, $list);
$pidMenuList = array_merge([[
return array_merge([[
'id' => 0,
'pid' => 0,
'title' => '顶级菜单',
]], $pidMenuList);
return $pidMenuList;
}
protected function buildPidMenu($pid, $list, $level = 0)
protected function buildPidMenu($pid, $list, $level = 0): array
{
$newList = [];
foreach ($list as $vo) {

View File

@@ -7,22 +7,21 @@ use app\common\model\TimeModel;
class SystemNode extends TimeModel
{
public function getNodeTreeList()
public function getNodeTreeList(): array
{
$list = $this->select()->toArray();
$list = $this->buildNodeTree($list);
return $list;
$list = $this->removeOption('where')->select()->toArray();
return $this->buildNodeTree($list);
}
protected function buildNodeTree($list)
protected function buildNodeTree($list): array
{
$newList = [];
$newList = [];
$repeatString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
foreach ($list as $vo) {
if ($vo['type'] == 1) {
$newList[] = $vo;
foreach ($list as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
if ($v['type'] == 2 && str_contains($v['node'], $vo['node'] . '/')) {
$v['node'] = "{$repeatString}{$repeatString}" . $v['node'];
$newList[] = $v;
}

View File

@@ -7,6 +7,11 @@ use app\common\model\TimeModel;
class SystemQuick extends TimeModel
{
protected $deleteTime = 'delete_time';
protected function getOptions(): array
{
return [
'deleteTime' => 'delete_time',
];
}
}

View File

@@ -151,12 +151,18 @@
<tr>
<td>DEBUG模式</td>
<td>
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-btn-warm':'layui-bg-gray'}">
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-bg-cyan':'layui-bg-gray'}">
{:env('APP_DEBUG')?'开启中':'已关闭'}
</button>
<span class="layui-badge layui-bg-gray">建议线上环境关闭 APP_DEBUG</span>
</td>
</tr>
<tr>
<td>composer信息</td>
<td>
<button type="button" class="layui-btn layui-btn-xs layui-bg-cyan" lay-on="showComposerInfo">点击查看</button>
</td>
</tr>
<tr>
<td>主要特色</td>
<td>

View File

@@ -100,21 +100,21 @@ if (!function_exists('auth')) {
$authService = new AuthService(session('admin.id'));
return $authService->checkNode($node);
}
}
/**
* @param string|null $detail
* @param string $name
* @param string $placeholder
* @return string
*/
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
{
$editor_type = sysConfig('site', 'editor_type');
return match ($editor_type) {
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
'EasyMDE' => "<textarea id='{$name}' class='editor' name='{$name}'>{$detail}</textarea>",
default => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 300px'></div></div>",
};
}
}
/**
* @param string|null $detail
* @param string $name
* @param string $placeholder
* @return string
*/
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
{
$editor_type = sysConfig('site', 'editor_type');
return match ($editor_type) {
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
'EasyMDE' => "<textarea id='{$name}' class='editor' name='{$name}'>{$detail}</textarea>",
default => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 300px'></div></div>",
};
}

View File

@@ -13,28 +13,20 @@ use think\model\concern\SoftDelete;
class TimeModel extends Model
{
/**
* 自动时间戳类型
* @var string
*/
protected $autoWriteTimestamp = true;
/**
* 添加时间
* @var string
*/
protected $createTime = 'create_time';
/**
* 更新时间
* @var string
*/
protected $updateTime = 'update_time';
/**
* 软删除
*/
use SoftDelete;
protected $deleteTime = false;
protected function getOptions(): array
{
return [
'autoWriteTimestamp' => true,
'createTime' => 'create_time',
'updateTime' => 'update_time',
'deleteTime' => false,
];
}
}

View File

@@ -22,7 +22,7 @@
"require": {
"php": ">=8.1.0",
"topthink/framework": "^8.0",
"topthink/think-orm": "4.0.3",
"topthink/think-orm": "^4.0",
"topthink/think-multi-app": "^1.1.0",
"topthink/think-view": "^2.0",
"topthink/think-captcha": "^3.0",

View File

@@ -571,3 +571,22 @@ INSERT INTO `ea_system_uploadfile`
VALUES ('290', 'oss', 'image/jpeg', 'https://lxn-99php.oss-cn-shenzhen.aliyuncs.com/upload/20191111/2c412adf1b30c8be3a913e603c7b6e4a.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
INSERT INTO `ea_system_uploadfile`
VALUES ('296', 'cos', 'image/jpeg', 'https://easyadmin-1251997243.cos.ap-guangzhou.myqcloud.com/upload/20191114/2381eaf81208ac188fa994b6f2579953.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
-- ----------------------------
-- Table structure for ea_system_log
-- ----------------------------
DROP TABLE IF EXISTS `ea_system_log`;
CREATE TABLE `ea_system_log`
(
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int unsigned DEFAULT '0' COMMENT '管理员ID',
`url` varchar(1500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作页面',
`method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '请求方法',
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '日志标题',
`content` json NOT NULL COMMENT '请求数据',
`response` json DEFAULT NULL COMMENT '回调数据',
`ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP',
`useragent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'User-Agent',
`create_time` int DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='后台操作日志表 - 202412';

View File

@@ -140,6 +140,38 @@ define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTh
echartsRecords.resize();
});
})
let util = layui.util;
util.on({
showComposerInfo: function () {
// <div style="padding: 25px;">12313</div>
let html = ``
ea.request.post({
url: ea.url('ajax/composerInfo'),
}, function (success) {
let data = success.data
data.forEach(function (item) {
html += `${item.name} ${item.version}\r\n`
})
html = `<pre class="layui-code code-demo">${html}</pre>`
layer.open({
type: 1,
title: 'composer 信息',
area: ['50%', '90%'],
shade: 0.8,
shadeClose: true,
content: html,
success: function () {
layui.code({elem: '.code-demo', theme: 'dark', lang: 'php'});
}
})
}, function (error) {
console.error(error)
return false;
})
}
})
},
editAdmin: function () {
let form = layui.form

View File

@@ -49,9 +49,10 @@ define(["jquery", "easy-admin"], function ($, ea) {
{field: 'url', minWidth: 150, title: '路由地址', align: "left"},
{
field: 'content', minWidth: 200, title: '请求数据', align: "left", templet: function (res) {
console.log(res.content)
let html = '<div class="layui-colla-item">' +
'<div class="layui-colla-title">点击预览</div>' +
'<div class="layui-colla-content">' + prettyFormat(res.content) + '</div>' +
'<div class="layui-colla-content">' + prettyFormat(JSON.stringify(res.content)) + '</div>' +
'</div>'
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
}
@@ -60,7 +61,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
field: 'response', minWidth: 200, title: '回调数据', align: "left", templet: function (res) {
let html = '<div class="layui-colla-item">' +
'<div class="layui-colla-title">点击预览</div>' +
'<div class="layui-colla-content">' + prettyFormat(res.response) + '</div>' +
'<div class="layui-colla-content">' + prettyFormat(JSON.stringify(res.response)) + '</div>' +
'</div>'
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
}