You've already forked think-plugs-recorder
recorder
This commit is contained in:
320
src/Service.php
320
src/Service.php
@@ -3,13 +3,331 @@
|
||||
namespace jerryyan\recorder;
|
||||
|
||||
use think\admin\Plugin;
|
||||
use jerryyan\recorder\helper\ViewHelper;
|
||||
|
||||
/**
|
||||
* 操作记录插件服务类
|
||||
* Class Service
|
||||
* @package jerryyan\recorder
|
||||
*/
|
||||
class Service extends Plugin
|
||||
{
|
||||
/**
|
||||
* 插件编码
|
||||
* @var string
|
||||
*/
|
||||
protected $appCode = 'recorder';
|
||||
|
||||
/**
|
||||
* 插件名称
|
||||
* @var string
|
||||
*/
|
||||
protected $appName = '操作记录';
|
||||
|
||||
/**
|
||||
* 定义插件菜单
|
||||
* @return array
|
||||
*/
|
||||
public static function menu(): array
|
||||
{
|
||||
return [];
|
||||
// 暂时不提供后台菜单,仅作为服务插件使用
|
||||
return [
|
||||
[
|
||||
'name' => '操作记录',
|
||||
'subs' => [
|
||||
[
|
||||
'name' => '记录查询',
|
||||
'icon' => 'layui-icon layui-icon-search',
|
||||
'node' => 'recorder/index/index'
|
||||
],
|
||||
[
|
||||
'name' => '记录统计',
|
||||
'icon' => 'layui-icon layui-icon-chart',
|
||||
'node' => 'recorder/stats/index'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件服务注册
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// 注册事件监听器
|
||||
$this->registerEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件启动
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// 插件启动时的初始化操作
|
||||
$this->initializePlugin();
|
||||
|
||||
// 注册模板函数
|
||||
$this->registerTemplateFunctions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册模板函数
|
||||
*/
|
||||
protected function registerTemplateFunctions()
|
||||
{
|
||||
try {
|
||||
// 函数已经通过composer autoload的files自动加载
|
||||
// 这里只需要确认函数是否正确加载
|
||||
if (!function_exists('recorder_get_records')) {
|
||||
// 如果通过autoload加载失败,手动加载
|
||||
require_once __DIR__ . '/functions.php';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
trace("注册模板函数失败: " . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册事件监听器
|
||||
*/
|
||||
protected function registerEventListeners()
|
||||
{
|
||||
// 可以在这里注册模型事件监听器,自动记录CRUD操作
|
||||
// 例如:监听模型的增删改事件,自动记录操作日志
|
||||
|
||||
try {
|
||||
// 注册全局模型事件监听
|
||||
\think\facade\Event::listen('think\\model\\concern\\ModelEvent', function($event, $model) {
|
||||
$this->handleModelEvent($event, $model);
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
trace("注册事件监听器失败: " . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理模型事件
|
||||
* @param string $event
|
||||
* @param $model
|
||||
*/
|
||||
protected function handleModelEvent(string $event, $model)
|
||||
{
|
||||
// 根据配置决定是否自动记录模型操作
|
||||
$config = \jerryyan\recorder\service\RecorderService::getConfig('auto_record', []);
|
||||
|
||||
if (!($config['enabled'] ?? false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$operationMap = [
|
||||
'after_insert' => '创建',
|
||||
'after_update' => '更新',
|
||||
'after_delete' => '删除',
|
||||
];
|
||||
|
||||
if (isset($operationMap[$event])) {
|
||||
$operationType = $operationMap[$event];
|
||||
|
||||
// 检查是否排除此操作类型
|
||||
$excludeOperations = $config['exclude_operations'] ?? [];
|
||||
if (in_array($operationType, $excludeOperations)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tableName = $model->getTable();
|
||||
$primaryKey = $model->getPk();
|
||||
$primaryValue = $model->$primaryKey ?? '';
|
||||
|
||||
\jerryyan\recorder\service\RecorderService::autoRecord([
|
||||
'operation_type' => $operationType,
|
||||
'operation_desc' => "{$operationType}{$tableName}记录",
|
||||
'data_type' => $tableName,
|
||||
'data_id' => (string)$primaryValue,
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
trace("自动记录模型操作失败: " . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化插件
|
||||
*/
|
||||
protected function initializePlugin()
|
||||
{
|
||||
// 设置默认配置
|
||||
$this->setDefaultConfig();
|
||||
|
||||
// 检查数据表是否存在
|
||||
$this->checkDatabaseTables();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认配置
|
||||
*/
|
||||
protected function setDefaultConfig()
|
||||
{
|
||||
$defaultConfig = [
|
||||
'enabled' => true,
|
||||
'auto_record' => [
|
||||
'enabled' => false,
|
||||
'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,
|
||||
]
|
||||
];
|
||||
|
||||
// 合并用户配置
|
||||
$userConfig = config('recorder', []);
|
||||
$finalConfig = array_merge($defaultConfig, $userConfig);
|
||||
|
||||
// 更新配置
|
||||
config(['recorder' => $finalConfig]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据表是否存在
|
||||
*/
|
||||
protected function checkDatabaseTables()
|
||||
{
|
||||
try {
|
||||
$db = \think\facade\Db::connect();
|
||||
|
||||
// 检查操作记录表是否存在
|
||||
$tables = $db->query("SHOW TABLES LIKE 'jl_recorder_log'");
|
||||
|
||||
if (empty($tables)) {
|
||||
trace("操作记录表不存在,请运行数据库迁移脚本:php think migrate:run", 'notice');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
trace("检查数据表失败: " . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件版本
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
return 'v1.0.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件描述
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '提供用户操作记录功能,支持手动记录和自动记录,包含完善的查询和视图展示功能';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件作者
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthor(): string
|
||||
{
|
||||
return 'Jerry Yan';
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件安装
|
||||
* @return bool
|
||||
*/
|
||||
public function install(): bool
|
||||
{
|
||||
try {
|
||||
// 运行数据库迁移
|
||||
$this->runMigrations();
|
||||
|
||||
// 初始化配置
|
||||
$this->setDefaultConfig();
|
||||
|
||||
trace("操作记录插件安装成功", 'info');
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
trace("操作记录插件安装失败: " . $e->getMessage(), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载
|
||||
* @return bool
|
||||
*/
|
||||
public function uninstall(): bool
|
||||
{
|
||||
try {
|
||||
// 这里可以添加卸载时的清理操作
|
||||
// 注意:通常不建议自动删除数据表,避免数据丢失
|
||||
|
||||
trace("操作记录插件卸载成功", 'info');
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
trace("操作记录插件卸载失败: " . $e->getMessage(), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行数据库迁移
|
||||
*/
|
||||
protected function runMigrations()
|
||||
{
|
||||
// 这里可以调用Phinx迁移命令
|
||||
// 或者直接执行SQL创建表结构
|
||||
try {
|
||||
// 示例:直接执行建表SQL
|
||||
$sql = $this->getCreateTableSql();
|
||||
\think\facade\Db::execute($sql);
|
||||
} catch (\Exception $e) {
|
||||
trace("执行数据库迁移失败: " . $e->getMessage(), 'error');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取建表SQL
|
||||
* @return string
|
||||
*/
|
||||
protected function getCreateTableSql(): string
|
||||
{
|
||||
return "
|
||||
CREATE TABLE IF NOT EXISTS `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='操作记录表';
|
||||
";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user