19 Commits

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
wolfcode
f9f25b76dd Merge branch 'main' of https://github.com/easyadmin8/EasyAdmin8 2025-01-12 18:13:17 +08:00
wolfcode
7603cdfa7e feat(admin): add middleware annotation for login exemption
- Add MiddlewareAnnotation to CheckLogin middleware for login exemption
- Implement IGNORE_LOGIN constant in MiddlewareAnnotation
- Use MiddlewareAnnotation in Goods controller for login exemption

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2025-01-12 18:12:28 +08:00
wolfcode
2e0cc85966 build(deps): update topthink/think-view to 2.0.0
- Change topthink/think-view dependency from ^2.0 to 2.0.0
- This update specifies an exact version to ensure compatibility and stability
2025-01-09 11:48:38 +08:00
wolfcode
5814fed0da Update Install.php 2025-01-09 11:32:25 +08:00
wolfcode
40f7ee82cd refactor(install): update view path delimiter
- Change the view path delimiter from '/' to '@' for the installation view
- This modification ensures consistency with the naming convention used in other parts of the application
2025-01-09 11:21:02 +08:00
wolfcode
936cb56c7f Update public.css 2025-01-08 21:38:48 +08:00
wolfcode
2d1940522c fix(View): automatically determine the template path if it is empty
- Add logic to automatically set the template path based on the controller and action if not explicitly defined
- Improve consistency in the 'iframeOpenTop' configuration by adding missing commas
2025-01-08 14:35:54 +08:00
wolfcode
264cf56ae4 fix(View): automatically determine the template path if it is empty
- Add logic to automatically set the template path based on the controller and action if not explicitly defined
- Improve consistency in the 'iframeOpenTop' configuration by adding missing commas
2025-01-08 14:25:54 +08:00
21 changed files with 199 additions and 39 deletions

View File

@@ -1,5 +1,5 @@
<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>
<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` 中下载
>
> ThinkPHP v8.0+ 和 Layui v2.9.x 的快速开发的后台管理系统。
> ThinkPHP v8.1+ 和 Layui v2.9.x 的快速开发的后台管理系统。
>
> 项目地址:[http://easyadmin8.top](http://easyadmin8.top)
>

View File

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

View File

@@ -4,6 +4,7 @@ namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\admin\model\MallGoods;
use app\admin\service\annotation\MiddlewareAnnotation;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
@@ -66,4 +67,9 @@ class Goods extends AdminController
return $this->fetch();
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOGIN)]
public function no_check_login(Request $request): string
{
return '这里演示方法不需要经过登录验证';
}
}

View File

@@ -87,6 +87,45 @@ class Log extends AdminController
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)]
#[NodeAnnotation(title: '框架日志', auth: true, ignore: NodeAnnotation::IGNORE_NODE)]
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

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

View File

@@ -10,6 +10,9 @@ final class MiddlewareAnnotation
/** 过滤日志 */
const IGNORE_LOG = 'LOG';
/** 免登录 */
const IGNORE_LOGIN = 'LOGIN';
public function __construct(public string $type = '', public string|array $ignore = '')
{
}

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">
<table id="currentTable" class="layui-table layui-hide"
data-auth-record="{:auth('system.log/record')}"
data-auth-deleteMonthLog="{:auth('system.log/deleteMonthLog')}"
lay-filter="currentTable">
</table>
</div>

View File

@@ -249,7 +249,7 @@ class AdminController extends BaseController
'version' => env('APP_DEBUG') ? time() : ConfigService::getVersion(),
'adminUploadUrl' => url('ajax/upload', [], false),
'adminEditor' => sysConfig('site', 'editor_type') ?: 'wangEditor',
'iframeOpenTop' => sysConfig('site', 'iframe_open_top') ?: 0,
'iframeOpenTop' => sysConfig('site', 'iframe_open_top') ?: 0,
];
View::assign($data);
}

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;
use app\admin\service\annotation\NodeAnnotation;
use app\common\constants\AdminConstant;
use think\facade\Db;
@@ -52,7 +53,7 @@ class AuthService
/***
* 构造方法
* AuthService constructor.
* @param null $adminId
* @param null $adminId
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
@@ -68,7 +69,7 @@ class AuthService
/**
* 检测检测权限
* @param null $node
* @param null $node
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
@@ -87,7 +88,7 @@ class AuthService
// 判断是否需要获取当前节点
if (empty($node)) {
$node = $this->getCurrentNode();
} else {
}else {
$node = $this->parseNodeStr($node);
}
// 判断是否加入节点控制,优先获取缓存信息
@@ -106,9 +107,30 @@ class AuthService
if (in_array($node, $this->adminNode)) {
return true;
}
if ($this->checkNodeAnnotationAttrAuth($node)) return true;
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
@@ -130,25 +152,25 @@ class AuthService
{
$nodeList = [];
$adminInfo = Db::name($this->config['system_admin'])
->where([
'id' => $this->adminId,
'status' => 1,
])->find();
->where([
'id' => $this->adminId,
'status' => 1,
])->find();
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
$buildAuthSql = Db::name($this->config['system_auth'])
->distinct(true)
->whereIn('id', $adminInfo['auth_ids'])
->field('id')
->buildSql(true);
->distinct(true)
->whereIn('id', $adminInfo['auth_ids'])
->field('id')
->buildSql(true);
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
->distinct(true)
->where("auth_id IN {$buildAuthSql}")
->field('node_id')
->buildSql(true);
->distinct(true)
->where("auth_id IN {$buildAuthSql}")
->field('node_id')
->buildSql(true);
$nodeList = Db::name($this->config['system_node'])
->distinct(true)
->where("id IN {$buildAuthNodeSql}")
->column('node');
->distinct(true)
->where("id IN {$buildAuthNodeSql}")
->column('node');
}
return $nodeList;
}
@@ -162,7 +184,7 @@ class AuthService
public function getNodeList()
{
return Db::name($this->config['system_node'])
->column('id,node,title,type,is_auth', 'node');
->column('id,node,title,type,is_auth', 'node');
}
/**
@@ -177,13 +199,13 @@ class AuthService
public function getAdminInfo()
{
return Db::name($this->config['system_admin'])
->where('id', $this->adminId)
->find();
->where('id', $this->adminId)
->find();
}
/**
* 驼峰转下划线规则
* @param string $node
* @param string $node
* @return string
*/
public function parseNodeStr($node)

View File

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

View File

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

View File

@@ -516,4 +516,5 @@ table样式
.wangEditor_div {
z-index: 99999;
border: 1px solid var(--w-e-textarea-slight-border-color);
}

View File

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

View File

@@ -6,6 +6,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
table_render_id: 'currentTableRenderId',
index_url: 'system.log/index',
export_url: 'system.log/export',
deleteMonthLog_url: 'system.log/deleteMonthLog',
};
return {
@@ -23,8 +24,15 @@ define(["jquery", "easy-admin"], function ($, ea) {
class: 'layui-btn layui-btn-sm',
icon: 'fa fa-book',
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: [[
{field: 'id', width: 80, title: 'ID', search: false},
@@ -65,5 +73,20 @@ define(["jquery", "easy-admin"], function ($, ea) {
});
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,
paths: {
"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-theme": ["plugs/echarts/echarts-theme"],
"easy-admin": ["plugs/easy-admin/easy-admin"],
"layuiall": ["plugs/layui-v2.x/layui.all"],
"layui": ["plugs/layui-v2.x/layui"],
"miniAdmin": ["plugs/lay-module/layuimini/miniAdmin"],
"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