11 Commits
dev ... v8.1.4

Author SHA1 Message Date
wolfcode
08fb6ef4d0 feat(log): 新增支持删除部分日志 add function to delete logs older than specified months
- Add deleteMonthLog functionality to log system
- Create new route and controller method for handling log deletion
- Implement frontend UI and logic for selecting and confirming log deletion-Add necessary database queries to safely delete logs
2025-02-19 11:23:46 +08:00
wolfcode
32d94bb3e0 feat(log): 新增支持删除部分日志 add function to delete logs older than specified months
- Add deleteMonthLog functionality to log system
- Create new route and controller method for handling log deletion
- Implement frontend UI and logic for selecting and confirming log deletion-Add necessary database queries to safely delete logs
2025-02-19 11:07:06 +08:00
wolfcode
d93483d9bf Update README.md 2025-02-18 13:44:24 +08:00
wolfcode
973e9cb24c feat(orm): upgrade think-orm to version 4.0 and add BaseEntity class
- Upgrade topthink/think-orm from ^3.0 to ^4.0 in composer.json
- Add new BaseEntity class in app/common/entity to handle common entity options
2025-02-14 16:12:12 +08:00
wolfcode
b510042323 Update Goods.php 2025-02-14 11:42:40 +08:00
wolfcode
b55dd8f67a feat(auth): add support for ignoring node authentication via annotation
- Add checkNodeAnnotationAttrAuth method to AuthService for annotation-based auth control
- Update checkAuth method to use the new annotation check-Modify Goods controller to use NodeAnnotation for specifying auth requirements
- Remove unused library imports in config-admin.js
2025-02-14 11:36:07 +08:00
wolfcode
8e488fb46c 🚀 Layui v2.9.21 2025-02-10 10:40:14 +08:00
wolfcode
d99e168583 Update Install.php 2025-01-15 09:54:11 +08:00
wolfcode
d6bb1456fa build(dependencies): update composer dependencies and adjust view rendering
- Update topthink/think-view dependency to version ^2.0
- Modify view rendering in Install controller to use empty template path
2025-01-15 09:45:07 +08:00
wolfcode
91eac36371 refactor(view): remove redundant template path generation
- Remove unnecessary code that generates a template path based on the request pathinfo
- Simplify the render function by removing the conditional block that sets the template path
2025-01-15 09:28:15 +08:00
wolfcode
1e4486989a refactor(admin): improve login check middleware
- Rename $ignoreAuth to $ignoreLogin for better clarity
- Update comments for better code readability
- Modify Login controller to use $ignoreLogin instead of $ignoreAuth
2025-01-14 10:09:58 +08:00
18 changed files with 182 additions and 43 deletions

View File

@@ -1,5 +1,5 @@
<div align="center" dir="auto"> <div align="center" dir="auto">
<img alt="log" src="/public/static/common/images/logo-8.png" /> <img alt="log" src="public/static/common/images/logo-8.png" />
<p> <p>
<img src="https://img.shields.io/badge/php-%3E=8.1.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php"> <img src="https://img.shields.io/badge/php-%3E=8.1.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php">
@@ -21,11 +21,11 @@
## 项目介绍 ## 项目介绍
> `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.0+ PHP 最低版本要求不低于 8.1 > `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.1+ PHP 最低版本要求不低于 8.1
> >
> 2025年起 `PHP` 版本要求提升到 `8.1+`, 如果需要 `8.0` 到分支 `v8.0` 中下载 > 2025年起 `PHP` 版本要求提升到 `8.1+`, 如果需要 `8.0` 到分支 `v8.0` 中下载
> >
> ThinkPHP v8.0+ 和 Layui v2.9.x 的快速开发的后台管理系统。 > ThinkPHP v8.1+ 和 Layui v2.9.x 的快速开发的后台管理系统。
> >
> 项目地址:[http://easyadmin8.top](http://easyadmin8.top) > 项目地址:[http://easyadmin8.top](http://easyadmin8.top)
> >

View File

@@ -14,7 +14,7 @@ use think\Response;
class Login extends AdminController class Login extends AdminController
{ {
protected bool $ignoreAuth = true; protected bool $ignoreLogin = true;
public function initialize(): void public function initialize(): void
{ {

View File

@@ -87,6 +87,45 @@ class Log extends AdminController
return Excel::exportData($list, $header, $fileName, 'xlsx'); return Excel::exportData($list, $header, $fileName, 'xlsx');
} }
#[NodeAnnotation(title: '删除指定日志', auth: true)]
public function deleteMonthLog(Request $request)
{
if (!$request->isAjax()) {
return $this->fetch();
}
if ($this->isDemo) $this->error('演示环境下不允许操作');
$monthsAgo = $request->param('month/d', 0);
if ($monthsAgo < 1) $this->error('月份错误');
$currentDate = new \DateTime();
$currentDate->modify("-$monthsAgo months");
$dbPrefix = env('DB_PREFIX');
$dbLike = "{$dbPrefix}system_log_";
$tables = Db::query("SHOW TABLES LIKE '$dbLike%'");
$threshold = date('Ym', strtotime("-$monthsAgo month"));
$tableNames = [];
try {
foreach ($tables as $table) {
$tableName = current($table);
if (!preg_match("/^$dbLike\d{6}$/", $tableName)) continue;
$datePart = substr($tableName, -6);
$issetTable = Db::query("SHOW TABLES LIKE '$tableName'");
if (!$issetTable) continue;
if ($datePart - $threshold <= 0) {
Db::execute("DROP TABLE `$tableName`");
$tableNames[] = $tableName;
}
}
}catch (PDOException) {
}
if (empty($tableNames)) $this->error('没有需要删除的表');
$this->success('操作成功 - 共删除 ' . count($tableNames) . ' 张表<br/>' . implode('<br>', $tableNames));
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOG)] #[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOG)]
#[NodeAnnotation(title: '框架日志', auth: true, ignore: NodeAnnotation::IGNORE_NODE)] #[NodeAnnotation(title: '框架日志', auth: true, ignore: NodeAnnotation::IGNORE_NODE)]
public function record(): Json|string public function record(): Json|string

0
app/admin/entity/.keep Normal file
View File

12
app/admin/entity/Test.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace app\admin\entity;
use app\common\entity\BaseEntity;
/**
* ThinkORM 4.0 实体模型案例
* 可与 Model 并存 或者 单独使用
* @package app\admin\entity
*/
class Test extends BaseEntity {}

View File

@@ -25,9 +25,10 @@ class CheckLogin
$controllerClass = 'app\\admin\\controller\\' . $controller; $controllerClass = 'app\\admin\\controller\\' . $controller;
$classObj = new ReflectionClass($controllerClass); $classObj = new ReflectionClass($controllerClass);
$properties = $classObj->getDefaultProperties(); $properties = $classObj->getDefaultProperties();
$ignoreAuth = $properties['ignoreAuth'] ?? false; // 整个控制器是否忽略登录
$ignoreLogin = $properties['ignoreLogin'] ?? false;
$adminUserInfo = session('admin'); $adminUserInfo = session('admin');
if (!$ignoreAuth) { if (!$ignoreLogin) {
$noNeedCheck = $properties['noNeedCheck'] ?? []; $noNeedCheck = $properties['noNeedCheck'] ?? [];
if (in_array($action, $noNeedCheck)) { if (in_array($action, $noNeedCheck)) {
return $next($request); return $next($request);
@@ -37,7 +38,8 @@ class CheckLogin
foreach ($attributes as $attribute) { foreach ($attributes as $attribute) {
$annotation = $attribute->newInstance(); $annotation = $attribute->newInstance();
$_ignore = (array)$annotation->ignore; $_ignore = (array)$annotation->ignore;
if (in_array('LOGIN', (array)$_ignore)) return $next($request); // 控制器中的某个方法忽略登录
if (in_array('LOGIN', $_ignore)) return $next($request);
} }
if (empty($adminUserInfo)) { if (empty($adminUserInfo)) {
return redirect(__url('login/index')); return redirect(__url('login/index'));

View File

@@ -0,0 +1,23 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<div class="layui-input-group">
<div class="layui-input-prefix layui-input-split">删除</div>
<label>
<input type="number" name="month" lay-affix="number" placeholder="" min="1" class="layui-input" value="3">
</label>
<div class="layui-input-suffix layui-input-split">个月前的日志</div>
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="button" class="layui-btn" lay-submit lay-filter="submit">提交</button>
</div>
</form>
</div>

View File

@@ -2,6 +2,7 @@
<div class="layuimini-main"> <div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide" <table id="currentTable" class="layui-table layui-hide"
data-auth-record="{:auth('system.log/record')}" data-auth-record="{:auth('system.log/record')}"
data-auth-deleteMonthLog="{:auth('system.log/deleteMonthLog')}"
lay-filter="currentTable"> lay-filter="currentTable">
</table> </table>
</div> </div>

View File

@@ -133,9 +133,6 @@ class AdminController extends BaseController
{ {
if ($layout) View::instance()->engine()->layout('/layout/default'); if ($layout) View::instance()->engine()->layout('/layout/default');
View::assign($vars); View::assign($vars);
if (empty($template)) {
$template = strtolower(str_replace('.', '/', $this->request->pathinfo()));
}
return View::fetch($template); return View::fetch($template);
} }

View File

@@ -0,0 +1,22 @@
<?php
namespace app\common\entity;
use think\Entity;
use think\model\type\DateTime;
class BaseEntity extends Entity
{
protected function getOptions(): array
{
return [
'type' => [
'create_time' => DateTime::class,
'update_time' => DateTime::class,
'delete_time' => DateTime::class,
],
];
}
}

View File

@@ -2,6 +2,7 @@
namespace app\common\service; namespace app\common\service;
use app\admin\service\annotation\NodeAnnotation;
use app\common\constants\AdminConstant; use app\common\constants\AdminConstant;
use think\facade\Db; use think\facade\Db;
@@ -106,9 +107,30 @@ class AuthService
if (in_array($node, $this->adminNode)) { if (in_array($node, $this->adminNode)) {
return true; return true;
} }
if ($this->checkNodeAnnotationAttrAuth($node)) return true;
return false; return false;
} }
protected function checkNodeAnnotationAttrAuth(string $node): bool
{
$bool = false;
$controller = request()->controller();
try {
$controllerExplode = explode('.', $controller);
[$_name, $_controller] = $controllerExplode;
$nodeExplode = explode('/', $node);
$action = end($nodeExplode);
$reflectionClass = new \ReflectionClass("app\admin\controller\\{$_name}\\{$_controller}");
$attributes = $reflectionClass->getMethod($action)->getAttributes(NodeAnnotation::class);
foreach ($attributes as $attribute) {
$annotation = $attribute->newInstance();
$bool = $annotation->auth === false;
}
}catch (\Throwable) {
}
return $bool;
}
/** /**
* 获取当前节点 * 获取当前节点
* @return string * @return string

View File

@@ -41,7 +41,7 @@ class Install extends BaseController
]; ];
$currentHost = '://'; $currentHost = '://';
$result = compact('errorInfo', 'currentHost', 'isInstall', 'envInfo'); $result = compact('errorInfo', 'currentHost', 'isInstall', 'envInfo');
return view('index/install/index', $result); return view('index@install/index', $result);
} }
if ($errorInfo) $this->error($errorInfo); if ($errorInfo) $this->error($errorInfo);
$charset = 'utf8mb4'; $charset = 'utf8mb4';

View File

@@ -22,9 +22,9 @@
"require": { "require": {
"php": ">=8.1.0", "php": ">=8.1.0",
"topthink/framework": "^8.0", "topthink/framework": "^8.0",
"topthink/think-orm": "^3.0", "topthink/think-orm": "^4.0",
"topthink/think-multi-app": "^1.1.0", "topthink/think-multi-app": "^1.1.0",
"topthink/think-view": "2.0.0", "topthink/think-view": "^2.0",
"topthink/think-captcha": "^3.0", "topthink/think-captcha": "^3.0",
"topthink/think-filesystem": "^2.0", "topthink/think-filesystem": "^2.0",
"aliyuncs/oss-sdk-php": "^2.6", "aliyuncs/oss-sdk-php": "^2.6",

View File

@@ -40,7 +40,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
}) })
}, function (res) { }, function (res) {
let data = res.data let data = res.data
if (data.is_ga_code) { if (data?.is_ga_code || false) {
let elem = $('#gaCode') let elem = $('#gaCode')
elem.removeClass('layui-hide'); elem.removeClass('layui-hide');
elem.find('input').focus() elem.find('input').focus()

View File

@@ -6,6 +6,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
table_render_id: 'currentTableRenderId', table_render_id: 'currentTableRenderId',
index_url: 'system.log/index', index_url: 'system.log/index',
export_url: 'system.log/export', export_url: 'system.log/export',
deleteMonthLog_url: 'system.log/deleteMonthLog',
}; };
return { return {
@@ -23,8 +24,15 @@ define(["jquery", "easy-admin"], function ($, ea) {
class: 'layui-btn layui-btn-sm', class: 'layui-btn layui-btn-sm',
icon: 'fa fa-book', icon: 'fa fa-book',
extend: 'data-width="95%" data-height="95%"' extend: 'data-width="95%" data-height="95%"'
}, }, {
] text: '删除部分日志',
url: 'system.log/deleteMonthLog',
method: 'open',
auth: 'deleteMonthLog',
class: 'layui-btn layui-btn-sm layui-btn-danger',
icon: 'fa fa-remove',
extend: 'data-width="35%" data-height="42%"'
},]
], ],
cols: [[ cols: [[
{field: 'id', width: 80, title: 'ID', search: false}, {field: 'id', width: 80, title: 'ID', search: false},
@@ -65,5 +73,20 @@ define(["jquery", "easy-admin"], function ($, ea) {
}); });
ea.listen(); ea.listen();
}, },
deleteMonthLog: function () {
layui.form.on('submit(submit)', function (data) {
let field = data.field
let options = {
url: ea.url(init.deleteMonthLog_url),
data: field,
}
ea.msg.confirm('确认执行该操作?重要数据请先做好相关备份!', function () {
ea.request.post(options, function (rs) {
let msg = rs.msg || '未知~'
layer.msg(msg.replace(/\n/g, '<br>'), {shade: 0.3, shadeClose: true, time: 2000})
})
})
})
}
}; };
}); });

View File

@@ -5,11 +5,9 @@ require.config({
baseUrl: BASE_URL, baseUrl: BASE_URL,
paths: { paths: {
"jquery": ["plugs/jquery-3.4.1/jquery-3.4.1.min"], "jquery": ["plugs/jquery-3.4.1/jquery-3.4.1.min"],
"jquery-particleground": ["plugs/jq-module/jquery.particleground.min"],
"echarts": ["plugs/echarts/echarts.min"], "echarts": ["plugs/echarts/echarts.min"],
"echarts-theme": ["plugs/echarts/echarts-theme"], "echarts-theme": ["plugs/echarts/echarts-theme"],
"easy-admin": ["plugs/easy-admin/easy-admin"], "easy-admin": ["plugs/easy-admin/easy-admin"],
"layuiall": ["plugs/layui-v2.x/layui.all"],
"layui": ["plugs/layui-v2.x/layui"], "layui": ["plugs/layui-v2.x/layui"],
"miniAdmin": ["plugs/lay-module/layuimini/miniAdmin"], "miniAdmin": ["plugs/lay-module/layuimini/miniAdmin"],
"miniMenu": ["plugs/lay-module/layuimini/miniMenu"], "miniMenu": ["plugs/lay-module/layuimini/miniMenu"],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long