You've already forked think-plugs-recorder
388 lines
10 KiB
Markdown
388 lines
10 KiB
Markdown
# ThinkAdmin 操作记录插件
|
|
|
|
基于 ThinkAdmin v6.1 的操作记录插件,提供完整的用户操作追踪功能,支持手动记录和自动记录,包含丰富的视图展示功能。
|
|
|
|
## 功能特性
|
|
|
|
### 核心功能
|
|
- ✅ **灵活记录**: 支持手动记录和自动记录两种模式
|
|
- ✅ **完整追踪**: 记录操作类型、用户信息、数据信息、时间等
|
|
- ✅ **关联数据**: 支持记录操作数据和关联数据
|
|
- ✅ **视图集成**: 提供模板函数,可在视图中直接调用
|
|
- ✅ **多种样式**: 支持列表、卡片、时间线等多种展示样式
|
|
- ✅ **自动清理**: 支持定期清理过期记录
|
|
|
|
### 记录内容
|
|
- 操作类型:创建、读取、更新、删除、导出、登录、登出等
|
|
- 操作说明:具体的操作描述
|
|
- 用户信息:用户ID、用户昵称
|
|
- 数据信息:操作的数据类型和ID
|
|
- 关联信息:关联的数据类型和ID(可选)
|
|
- 请求信息:请求方法、URL、IP地址、用户代理
|
|
- 额外数据:JSON格式的扩展信息
|
|
|
|
## 安装配置
|
|
|
|
### 1. 数据库迁移
|
|
```bash
|
|
# 运行数据库迁移脚本
|
|
php think migrate:run
|
|
```
|
|
|
|
### 2. 插件发布
|
|
```bash
|
|
# 发布插件资源
|
|
php think xadmin:publish --migrate
|
|
```
|
|
|
|
### 3. 配置文件
|
|
在 `config/` 目录下创建 `recorder.php` 配置文件:
|
|
|
|
```php
|
|
<?php
|
|
return [
|
|
// 是否启用操作记录
|
|
'enabled' => true,
|
|
|
|
// 自动记录配置
|
|
'auto_record' => [
|
|
'enabled' => true,
|
|
'exclude_operations' => ['读取'], // 排除的操作类型
|
|
'exclude_controllers' => [], // 排除的控制器
|
|
],
|
|
|
|
// 记录保留天数
|
|
'retention_days' => 90,
|
|
|
|
// 敏感操作标记
|
|
'sensitive_operations' => ['删除', '导出'],
|
|
|
|
// 视图组件配置
|
|
'view' => [
|
|
'default_limit' => 10,
|
|
'date_format' => 'Y-m-d H:i:s',
|
|
'theme' => 'default',
|
|
'show_user' => true,
|
|
'show_ip' => false,
|
|
'compact_mode' => false,
|
|
]
|
|
];
|
|
```
|
|
|
|
### 4. 注册中间件(可选)
|
|
在 `app/middleware.php` 中注册中间件实现自动记录:
|
|
|
|
```php
|
|
<?php
|
|
return [
|
|
// 其他中间件...
|
|
\jerryyan\recorder\middleware\RecorderMiddleware::class,
|
|
];
|
|
```
|
|
|
|
### 5. 控制器方法注释(推荐)
|
|
中间件支持读取控制器方法注释来获取准确的操作类型,详见 [控制器注释示例](CONTROLLER_ANNOTATION_EXAMPLE.md):
|
|
|
|
```php
|
|
/**
|
|
* @operation 创建用户
|
|
*/
|
|
public function save()
|
|
{
|
|
// 保存用户逻辑
|
|
}
|
|
|
|
/**
|
|
* @recorder 审核用户申请
|
|
*/
|
|
public function audit()
|
|
{
|
|
// 审核逻辑
|
|
}
|
|
```
|
|
|
|
## 使用方法
|
|
|
|
### 1. 手动记录操作
|
|
|
|
```php
|
|
use jerryyan\recorder\service\RecorderService;
|
|
|
|
// 基础记录
|
|
RecorderService::record([
|
|
'operation_type' => '创建',
|
|
'operation_desc' => '创建新用户',
|
|
'data_type' => 'user',
|
|
'data_id' => '123'
|
|
]);
|
|
|
|
// 完整记录
|
|
RecorderService::record([
|
|
'operation_type' => '更新',
|
|
'operation_desc' => '修改用户信息',
|
|
'user_id' => 1,
|
|
'user_nickname' => '管理员',
|
|
'data_type' => 'user',
|
|
'data_id' => '123',
|
|
'related_type' => 'department',
|
|
'related_id' => '456',
|
|
'extra_data' => ['old_name' => '张三', 'new_name' => '李四']
|
|
]);
|
|
|
|
// 自动记录(自动获取当前用户和请求信息)
|
|
RecorderService::autoRecord([
|
|
'operation_type' => '导出',
|
|
'operation_desc' => '导出用户列表',
|
|
'data_type' => 'user'
|
|
]);
|
|
```
|
|
|
|
### 2. 查询操作记录
|
|
|
|
```php
|
|
use jerryyan\recorder\service\RecorderService;
|
|
|
|
// 查询用户操作记录
|
|
$userRecords = RecorderService::getUserRecords(123, [
|
|
'limit' => 10,
|
|
'operation_type' => '创建'
|
|
]);
|
|
|
|
// 查询数据操作记录
|
|
$dataRecords = RecorderService::getDataRecords('user', '123');
|
|
|
|
// 复杂查询
|
|
$records = RecorderService::query([
|
|
'user_id' => 123,
|
|
'operation_type' => ['创建', '更新'],
|
|
'data_type' => 'user',
|
|
'start_time' => '2024-01-01',
|
|
'end_time' => '2024-12-31',
|
|
'keyword' => '用户管理'
|
|
]);
|
|
|
|
// 获取统计数据
|
|
$stats = RecorderService::getStats([
|
|
'start_time' => '2024-01-01',
|
|
'end_time' => '2024-12-31'
|
|
]);
|
|
```
|
|
|
|
### 3. 视图中调用
|
|
|
|
**注意**: 如果提示函数未定义,请参考 [模板函数使用指南](TEMPLATE_FUNCTIONS_GUIDE.md) 解决。
|
|
|
|
首先确保函数已正确注册:
|
|
```bash
|
|
# 更新Composer自动加载
|
|
composer dump-autoload
|
|
```
|
|
|
|
#### 3.1 获取记录数据
|
|
```html
|
|
<!-- 获取用户操作记录 -->
|
|
{assign name="records" value=":recorder_get_records(['user_id' => $user_id, 'limit' => 5])" /}
|
|
|
|
<!-- 遍历显示 -->
|
|
{volist name="records" id="record"}
|
|
<div>
|
|
{$record.operation_type} - {$record.operation_desc} - {$record.created_at}
|
|
</div>
|
|
{/volist}
|
|
```
|
|
|
|
#### 3.2 渲染HTML组件
|
|
```html
|
|
<!-- 默认列表样式 -->
|
|
<div class="user-actions">
|
|
<h4>操作记录</h4>
|
|
{:recorder_render_list(['user_id' => $user_id], ['limit' => 10])}
|
|
</div>
|
|
|
|
<!-- 卡片样式 -->
|
|
{:recorder_render_list(['data_type' => 'order'], ['theme' => 'card', 'show_user' => true])}
|
|
|
|
<!-- 时间线样式 -->
|
|
{:recorder_render_timeline(['data_type' => 'project', 'data_id' => $project_id])}
|
|
|
|
<!-- 单条记录 -->
|
|
{:recorder_render_item($record, ['show_extra' => true])}
|
|
```
|
|
|
|
#### 3.3 配置选项
|
|
```html
|
|
<!-- 带完整配置的记录列表 -->
|
|
{assign name="options" value="[
|
|
'limit' => 20,
|
|
'show_user' => true,
|
|
'show_ip' => false,
|
|
'date_format' => 'Y-m-d H:i:s',
|
|
'theme' => 'card',
|
|
'compact' => false,
|
|
'css_class' => 'my-custom-class'
|
|
]" /}
|
|
|
|
{:recorder_render_list(['user_id' => $user_id], $options)}
|
|
```
|
|
|
|
#### 3.4 备用方案(如果函数未注册)
|
|
```html
|
|
<!-- 使用类静态方法替代函数 -->
|
|
{assign name="records" value=":jerryyan\recorder\helper\ViewHelper::getRecords(['user_id' => $user_id])" /}
|
|
|
|
<!-- 渲染列表 -->
|
|
{:jerryyan\recorder\helper\ViewHelper::renderList(['user_id' => $user_id], ['limit' => 10])}
|
|
|
|
<!-- 渲染时间线 -->
|
|
{:jerryyan\recorder\helper\ViewHelper::renderTimeline(['data_type' => 'order', 'data_id' => $order_id])}
|
|
```
|
|
|
|
### 4. 模型事件自动记录
|
|
|
|
```php
|
|
use jerryyan\recorder\service\RecorderService;
|
|
|
|
class User extends \think\admin\Model
|
|
{
|
|
// 创建后自动记录
|
|
protected static function onAfterInsert($user)
|
|
{
|
|
RecorderService::autoRecord([
|
|
'operation_type' => '创建',
|
|
'operation_desc' => '创建用户:' . $user->username,
|
|
'data_type' => 'user',
|
|
'data_id' => $user->id
|
|
]);
|
|
}
|
|
|
|
// 更新后自动记录
|
|
protected static function onAfterUpdate($user)
|
|
{
|
|
RecorderService::autoRecord([
|
|
'operation_type' => '更新',
|
|
'operation_desc' => '更新用户:' . $user->username,
|
|
'data_type' => 'user',
|
|
'data_id' => $user->id
|
|
]);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. 数据管理
|
|
|
|
```php
|
|
use jerryyan\recorder\service\RecorderService;
|
|
|
|
// 导出记录
|
|
$filepath = RecorderService::export([
|
|
'start_time' => '2024-01-01',
|
|
'end_time' => '2024-12-31'
|
|
]);
|
|
|
|
// 清理过期记录
|
|
$deletedCount = RecorderService::cleanup(90); // 清理90天前的记录
|
|
```
|
|
|
|
## 视图样式
|
|
|
|
插件提供多种内置样式:
|
|
|
|
### 1. 默认列表样式
|
|
简洁的列表展示,适合在管理页面中使用。
|
|
|
|
### 2. 卡片样式
|
|
美观的卡片布局,适合在首页或仪表板中展示。
|
|
|
|
### 3. 时间线样式
|
|
时间线形式展示,清晰展示操作的时间顺序。
|
|
|
|
### 4. 紧凑样式
|
|
紧凑的显示模式,适合空间有限的场景。
|
|
|
|
## 数据库结构
|
|
|
|
插件使用单表存储所有操作记录:
|
|
|
|
```sql
|
|
CREATE TABLE `jl_recorder_log` (
|
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
|
|
`operation_type` varchar(50) NOT NULL DEFAULT '' COMMENT '操作类型',
|
|
`operation_desc` varchar(500) NOT NULL DEFAULT '' COMMENT '操作说明',
|
|
`user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '操作用户ID',
|
|
`user_nickname` varchar(100) NOT NULL DEFAULT '' COMMENT '操作用户昵称',
|
|
`data_type` varchar(100) NOT NULL DEFAULT '' COMMENT '操作数据类型',
|
|
`data_id` varchar(100) NOT NULL DEFAULT '' COMMENT '操作数据ID',
|
|
`related_type` varchar(100) NOT NULL DEFAULT '' COMMENT '关联数据类型',
|
|
`related_id` varchar(100) NOT NULL DEFAULT '' COMMENT '关联数据ID',
|
|
`request_method` varchar(10) NOT NULL DEFAULT '' COMMENT '请求方法',
|
|
`request_url` varchar(500) NOT NULL DEFAULT '' COMMENT '请求URL',
|
|
`request_ip` varchar(50) NOT NULL DEFAULT '' COMMENT '请求IP',
|
|
`user_agent` varchar(500) NOT NULL DEFAULT '' COMMENT '用户代理',
|
|
`extra_data` text COMMENT '额外数据(JSON格式)',
|
|
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_user_id` (`user_id`),
|
|
KEY `idx_operation_type` (`operation_type`),
|
|
KEY `idx_data_type_id` (`data_type`, `data_id`),
|
|
KEY `idx_created_at` (`created_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='操作记录表';
|
|
```
|
|
|
|
## 性能优化
|
|
|
|
1. **索引优化**: 针对常用查询条件建立了合适的数据库索引
|
|
2. **异步记录**: 记录操作不会影响主业务的性能
|
|
3. **数据限制**: 自动限制存储数据的长度,避免过大数据影响性能
|
|
4. **定期清理**: 支持自动清理过期记录,保持表的性能
|
|
|
|
## 安全考虑
|
|
|
|
1. **数据脱敏**: 自动过滤敏感信息如密码、密钥等
|
|
2. **权限控制**: 基于ThinkAdmin的权限系统
|
|
3. **只读模式**: 操作记录支持只读模式,防止恶意修改
|
|
4. **错误隔离**: 记录失败不会影响主业务逻辑
|
|
|
|
## 常见问题
|
|
|
|
### Q: 插件安装后没有生效怎么办?
|
|
A: 检查以下几点:
|
|
1. 确认数据库迁移是否成功执行
|
|
2. 检查配置文件是否正确
|
|
3. 确认插件是否已经正确注册
|
|
|
|
### Q: 如何自定义操作类型?
|
|
A: 操作类型由代码直接控制,可以使用任意中文字符串作为操作类型。
|
|
|
|
### Q: 如何实现自定义的视图样式?
|
|
A: 可以通过以下方式:
|
|
1. 在配置中指定自定义CSS类
|
|
2. 创建自定义模板文件
|
|
3. 修改内置的CSS样式
|
|
|
|
### Q: 记录过多会影响性能吗?
|
|
A: 插件已经进行了性能优化:
|
|
1. 使用了合适的数据库索引
|
|
2. 支持定期清理过期记录
|
|
3. 异步记录不影响主业务
|
|
|
|
## 更新日志
|
|
|
|
### v1.0.0 (2024-12-12)
|
|
- 🎉 初始版本发布
|
|
- ✅ 支持手动和自动操作记录
|
|
- ✅ 提供完整的视图展示功能
|
|
- ✅ 支持多种展示样式
|
|
- ✅ 包含中间件自动记录功能
|
|
|
|
## 许可证
|
|
|
|
WTFPL
|
|
|
|
## 作者
|
|
|
|
Jerry Yan (792602257@qq.com)
|
|
|
|
## 技术支持
|
|
|
|
如有问题,请提交 Issue 或联系作者。 |