2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00
2025-08-13 10:39:09 +08:00

ThinkAdmin 操作记录插件

基于 ThinkAdmin v6.1 的操作记录插件,提供完整的用户操作追踪功能,支持手动记录和自动记录,包含丰富的视图展示功能。

功能特性

核心功能

  • 灵活记录: 支持手动记录和自动记录两种模式
  • 完整追踪: 记录操作类型、用户信息、数据信息、时间等
  • 关联数据: 支持记录操作数据和关联数据
  • 视图集成: 提供模板函数,可在视图中直接调用
  • 多种样式: 支持列表、卡片、时间线等多种展示样式
  • 自动清理: 支持定期清理过期记录

记录内容

  • 操作类型:创建、读取、更新、删除、导出、登录、登出等
  • 操作说明:具体的操作描述
  • 用户信息:用户ID、用户昵称
  • 数据信息:操作的数据类型和ID
  • 关联信息:关联的数据类型和ID(可选)
  • 请求信息:请求方法、URL、IP地址、用户代理
  • 额外数据:JSON格式的扩展信息

安装配置

1. 数据库迁移

# 运行数据库迁移脚本
php think migrate:run

2. 插件发布

# 发布插件资源
php think xadmin:publish --migrate

3. 配置文件

config/ 目录下创建 recorder.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
return [
    // 其他中间件...
    \jerryyan\recorder\middleware\RecorderMiddleware::class,
];

5. 控制器方法注释(推荐)

中间件支持读取控制器方法注释来获取准确的操作类型,详见 控制器注释示例

/**
 * @operation 创建用户
 */
public function save()
{
    // 保存用户逻辑
}

/**
 * @recorder 审核用户申请  
 */
public function audit()
{
    // 审核逻辑
}

使用方法

1. 手动记录操作

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. 查询操作记录

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. 视图中调用

注意: 如果提示函数未定义,请参考 模板函数使用指南 解决。

首先确保函数已正确注册:

# 更新Composer自动加载
composer dump-autoload

3.1 获取记录数据

<!-- 获取用户操作记录 -->
{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组件

<!-- 默认列表样式 -->
<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 配置选项

<!-- 带完整配置的记录列表 -->
{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 备用方案(如果函数未注册)

<!-- 使用类静态方法替代函数 -->
{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. 模型事件自动记录

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. 数据管理

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. 紧凑样式

紧凑的显示模式,适合空间有限的场景。

数据库结构

插件使用单表存储所有操作记录:

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 或联系作者。

Description
No description provided
Readme 88 KiB
Languages
PHP 63.6%
HTML 36.4%