first commot
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\controller\OperationLog;
|
||||
|
||||
use app\admin\BaseController;
|
||||
use think\facade\Request;
|
||||
use think\response\Json;
|
||||
use app\model\OperationLog;
|
||||
use app\model\AdminUser;
|
||||
|
||||
class OperationLogController extends BaseController
|
||||
{
|
||||
/**
|
||||
* 获取操作日志列表
|
||||
* @return Json
|
||||
*/
|
||||
public function getOperationLogs()
|
||||
{
|
||||
try {
|
||||
$page = Request::param('page/d', 1);
|
||||
$pageSize = Request::param('pageSize/d', 20);
|
||||
$keyword = Request::param('keyword/s', '');
|
||||
$module = Request::param('module/s', '');
|
||||
$action = Request::param('action/s', '');
|
||||
$status = Request::param('status/s', '');
|
||||
$startTime = Request::param('startTime/s', '');
|
||||
$endTime = Request::param('endTime/s', '');
|
||||
|
||||
$query = OperationLog::where('delete_time', null);
|
||||
|
||||
// 关键词搜索(用户姓名、URL)
|
||||
if ($keyword) {
|
||||
$query->where(function ($q) use ($keyword) {
|
||||
$q
|
||||
->whereOr('user_name', 'like', "%{$keyword}%")
|
||||
->whereOr('url', 'like', "%{$keyword}%");
|
||||
});
|
||||
}
|
||||
|
||||
// 模块筛选
|
||||
if ($module) {
|
||||
$query->where('module', $module);
|
||||
}
|
||||
|
||||
// 操作动作筛选
|
||||
if ($action) {
|
||||
$query->where('action', $action);
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if ($status !== '') {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
// 时间范围筛选
|
||||
if ($startTime) {
|
||||
$query->where('create_time', '>=', $startTime);
|
||||
}
|
||||
if ($endTime) {
|
||||
$query->where('create_time', '<=', $endTime);
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
$total = $query->count();
|
||||
|
||||
// 分页查询
|
||||
$list = $query->order('id', 'desc')
|
||||
->page($page, $pageSize)
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
// 获取所有唯一的 user_id
|
||||
$userIds = array_unique(array_column($list, 'user_id'));
|
||||
$userIds = array_filter($userIds); // 过滤掉0和null
|
||||
|
||||
// 批量查询用户信息
|
||||
$users = [];
|
||||
if (!empty($userIds)) {
|
||||
$userList = AdminUser::whereIn('id', $userIds)
|
||||
->where('delete_time', null)
|
||||
->field('id, name')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
// 转换为以 id 为键的数组,方便查找
|
||||
foreach ($userList as $user) {
|
||||
$users[$user['id']] = [
|
||||
'name' => $user['name']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 将用户信息合并到日志列表中
|
||||
foreach ($list as &$item) {
|
||||
if (isset($users[$item['user_id']])) {
|
||||
$item['user_name'] = $users[$item['user_id']]['name'];
|
||||
} else {
|
||||
$item['user_name'] = $item['user_name'] ?? '';
|
||||
}
|
||||
}
|
||||
unset($item); // 释放引用
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'pageSize' => $pageSize
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取操作日志失败: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作日志详情
|
||||
* @param int $id
|
||||
* @return Json
|
||||
*/
|
||||
public function getOperationLogDetail(int $id)
|
||||
{
|
||||
try {
|
||||
$log = OperationLog::where('id', $id)
|
||||
->where('delete_time', null)
|
||||
->find();
|
||||
|
||||
if (!$log) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '操作日志不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
$logData = $log->toArray();
|
||||
$this->logSuccess('操作日志', '查看操作日志详情', $logData);
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $logData
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->logFail('操作日志', '查看操作日志详情', $e->getMessage());
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取操作日志详情失败: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除操作日志
|
||||
* @param int $id
|
||||
* @return Json
|
||||
*/
|
||||
public function deleteOperationLog(int $id)
|
||||
{
|
||||
try {
|
||||
$log = OperationLog::where('id', $id)
|
||||
->where('delete_time', null)
|
||||
->find();
|
||||
|
||||
if (!$log) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '操作日志不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 软删除
|
||||
$log->delete();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '删除成功'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '删除失败: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除操作日志
|
||||
* @return Json
|
||||
*/
|
||||
public function batchDeleteOperationLogs()
|
||||
{
|
||||
try {
|
||||
$ids = Request::param('ids/a', []);
|
||||
|
||||
if (empty($ids)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '请选择要删除的操作日志'
|
||||
]);
|
||||
}
|
||||
|
||||
OperationLog::whereIn('id', $ids)
|
||||
->where('delete_time', null)
|
||||
->delete();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '批量删除成功'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '批量删除失败: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作统计信息(模块、动作等)
|
||||
* @return Json
|
||||
*/
|
||||
public function getOperationStatistics()
|
||||
{
|
||||
try {
|
||||
// 获取模块列表
|
||||
$modules = OperationLog::where('delete_time', null)
|
||||
->group('module')
|
||||
->column('module');
|
||||
|
||||
// 获取动作列表
|
||||
$actions = OperationLog::where('delete_time', null)
|
||||
->group('action')
|
||||
->column('action');
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'modules' => $modules,
|
||||
'actions' => $actions
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取统计信息失败: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\OperationLog;
|
||||
|
||||
use app\model\OperationLog;
|
||||
use think\facade\Request;
|
||||
use think\facade\Session;
|
||||
|
||||
/**
|
||||
* 操作日志记录助手类
|
||||
*/
|
||||
class OperationLogHelper
|
||||
{
|
||||
/**
|
||||
* 记录操作日志
|
||||
* @param string $module 操作模块
|
||||
* @param string $action 操作动作
|
||||
* @param array $requestData 请求数据
|
||||
* @param array $responseData 响应数据
|
||||
* @param int $status 操作状态:1-成功,0-失败
|
||||
* @param string $errorMessage 错误信息
|
||||
* @param float $executionTime 执行时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public static function log(
|
||||
string $module,
|
||||
string $action,
|
||||
array $requestData = [],
|
||||
array $responseData = [],
|
||||
int $status = 1,
|
||||
string $errorMessage = '',
|
||||
float $executionTime = 0.0
|
||||
): bool {
|
||||
try {
|
||||
// 获取用户信息
|
||||
$userInfo = Session::get('user');
|
||||
$userId = $userInfo['id'] ?? 0;
|
||||
$userAccount = $userInfo['account'] ?? '';
|
||||
$userName = $userInfo['name'] ?? '';
|
||||
|
||||
// 获取请求信息
|
||||
$method = Request::method();
|
||||
$url = Request::url(true);
|
||||
$ip = Request::ip();
|
||||
$userAgent = Request::header('user-agent', '');
|
||||
|
||||
// 过滤敏感信息(如密码)
|
||||
$filteredRequestData = self::filterSensitiveData($requestData);
|
||||
|
||||
// 记录日志
|
||||
OperationLog::create([
|
||||
'user_id' => $userId,
|
||||
'user_account' => $userAccount,
|
||||
'user_name' => $userName,
|
||||
'module' => $module,
|
||||
'action' => $action,
|
||||
'method' => $method,
|
||||
'url' => $url,
|
||||
'ip' => $ip,
|
||||
'user_agent' => $userAgent,
|
||||
'request_data' => !empty($filteredRequestData) ? json_encode($filteredRequestData, JSON_UNESCAPED_UNICODE) : null,
|
||||
'response_data' => !empty($responseData) ? json_encode($responseData, JSON_UNESCAPED_UNICODE) : null,
|
||||
'status' => $status,
|
||||
'error_message' => $errorMessage,
|
||||
'execution_time' => $executionTime,
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
// 记录日志失败不应该影响主流程,只记录错误
|
||||
error_log('操作日志记录失败: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤敏感数据
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
private static function filterSensitiveData(array $data): array
|
||||
{
|
||||
$sensitiveKeys = ['password', 'pwd', 'token', 'api_key', 'secret'];
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (in_array(strtolower($key), $sensitiveKeys)) {
|
||||
$data[$key] = '***';
|
||||
} elseif (is_array($value)) {
|
||||
$data[$key] = self::filterSensitiveData($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\OperationLog;
|
||||
|
||||
use think\facade\Request;
|
||||
use app\model\OperationLog;
|
||||
use app\service\JwtService;
|
||||
|
||||
/**
|
||||
* 操作日志记录器(JWT版)
|
||||
*/
|
||||
class OperationLogger
|
||||
{
|
||||
private static function getUserFromToken(): array
|
||||
{
|
||||
return JwtService::getUserFromHeader(Request::header('Authorization', ''));
|
||||
}
|
||||
|
||||
public static function record(
|
||||
string $module,
|
||||
string $action,
|
||||
array $requestData = [],
|
||||
array $responseData = [],
|
||||
int $status = 1,
|
||||
string $errorMessage = '',
|
||||
array $userInfo = []
|
||||
): bool {
|
||||
try {
|
||||
if (empty($userInfo)) {
|
||||
$userInfo = self::getUserFromToken();
|
||||
}
|
||||
|
||||
$userId = $userInfo['id'] ?? 0;
|
||||
$userAccount = $userInfo['account'] ?? '';
|
||||
$userName = $userInfo['name'] ?? '';
|
||||
|
||||
if (empty($requestData)) {
|
||||
$requestData = Request::param();
|
||||
}
|
||||
|
||||
$method = Request::method();
|
||||
$url = Request::url(true);
|
||||
$ip = Request::ip();
|
||||
$userAgent = Request::header('user-agent', '');
|
||||
|
||||
$filteredRequestData = self::filterSensitiveData($requestData);
|
||||
|
||||
OperationLog::create([
|
||||
'user_id' => $userId,
|
||||
'user_account' => $userAccount,
|
||||
'user_name' => $userName,
|
||||
'module' => $module,
|
||||
'action' => $action,
|
||||
'method' => $method,
|
||||
'url' => $url,
|
||||
'ip' => $ip,
|
||||
'user_agent' => $userAgent,
|
||||
'request_data' => !empty($filteredRequestData) ? json_encode($filteredRequestData, JSON_UNESCAPED_UNICODE) : null,
|
||||
'response_data' => !empty($responseData) ? json_encode($responseData, JSON_UNESCAPED_UNICODE) : null,
|
||||
'status' => $status,
|
||||
'error_message' => $errorMessage,
|
||||
'execution_time' => 0.0,
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
error_log('操作日志记录失败: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function success(string $module, string $action, array $responseData = [], array $userInfo = []): bool
|
||||
{
|
||||
return self::record($module, $action, [], $responseData, 1, '', $userInfo);
|
||||
}
|
||||
|
||||
public static function fail(string $module, string $action, string $errorMessage, array $userInfo = []): bool
|
||||
{
|
||||
return self::record($module, $action, [], [], 0, $errorMessage, $userInfo);
|
||||
}
|
||||
|
||||
private static function filterSensitiveData(array $data): array
|
||||
{
|
||||
$sensitiveKeys = ['password', 'pwd', 'token', 'api_key', 'secret'];
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (in_array(strtolower($key), $sensitiveKeys)) {
|
||||
$data[$key] = '***';
|
||||
} elseif (is_array($value)) {
|
||||
$data[$key] = self::filterSensitiveData($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user