217 lines
5.6 KiB
PHP
217 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
class OperationLog extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'user_name',
|
|
'module',
|
|
'action',
|
|
'method',
|
|
'path',
|
|
'ip',
|
|
'user_agent',
|
|
'request_data',
|
|
'response_data',
|
|
'response_code',
|
|
'execution_time',
|
|
'remark',
|
|
];
|
|
|
|
protected $casts = [
|
|
'request_data' => 'array',
|
|
'response_data' => 'array',
|
|
'execution_time' => 'float',
|
|
'created_at' => 'datetime',
|
|
];
|
|
|
|
/**
|
|
* 关联用户
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
/**
|
|
* 记录操作日志
|
|
*/
|
|
public static function log($data)
|
|
{
|
|
return self::create(array_merge([
|
|
'user_id' => auth()->id(),
|
|
'user_name' => auth()->user()->name ?? '系统',
|
|
], $data));
|
|
}
|
|
|
|
/**
|
|
* 记录API请求日志
|
|
*/
|
|
public static function logApiRequest($request, $response, $executionTime)
|
|
{
|
|
$path = $request->path();
|
|
$method = $request->method();
|
|
|
|
// 排除日志查询本身,避免无限递归
|
|
if (strpos($path, 'operation-logs') !== false) {
|
|
return;
|
|
}
|
|
|
|
$data = [
|
|
'module' => self::getModuleFromPath($path),
|
|
'action' => self::getActionFromMethod($method),
|
|
'method' => $method,
|
|
'path' => $path,
|
|
'ip' => $request->ip(),
|
|
'user_agent' => $request->userAgent(),
|
|
'request_data' => self::filterSensitiveData($request->all()),
|
|
'response_data' => self::filterSensitiveData($response->getData(true)),
|
|
'response_code' => $response->getStatusCode(),
|
|
'execution_time' => $executionTime,
|
|
];
|
|
|
|
return self::log($data);
|
|
}
|
|
|
|
/**
|
|
* 根据路径获取模块
|
|
*/
|
|
private static function getModuleFromPath($path)
|
|
{
|
|
$segments = explode('/', $path);
|
|
|
|
if (count($segments) >= 2) {
|
|
$module = $segments[1];
|
|
$modules = [
|
|
'auth' => '认证',
|
|
'goods' => '商品',
|
|
'suppliers' => '供应商',
|
|
'brands' => '品牌',
|
|
'warehouses' => '仓库',
|
|
'purchase-orders' => '采购单',
|
|
'receiving-orders' => '收货单',
|
|
'templates' => '模板',
|
|
'warehouse-bindings' => '仓库绑定',
|
|
'orders' => '订单',
|
|
'shop-auths' => '店铺授权',
|
|
'system-configs' => '系统配置',
|
|
'operation-logs' => '操作日志',
|
|
];
|
|
|
|
return $modules[$module] ?? '其他';
|
|
}
|
|
|
|
return '其他';
|
|
}
|
|
|
|
/**
|
|
* 根据请求方法获取操作
|
|
*/
|
|
private static function getActionFromMethod($method)
|
|
{
|
|
$actions = [
|
|
'GET' => '查询',
|
|
'POST' => '创建',
|
|
'PUT' => '更新',
|
|
'PATCH' => '更新',
|
|
'DELETE' => '删除',
|
|
];
|
|
|
|
return $actions[$method] ?? '其他';
|
|
}
|
|
|
|
/**
|
|
* 过滤敏感数据
|
|
*/
|
|
private static function filterSensitiveData($data)
|
|
{
|
|
if (!is_array($data)) {
|
|
return $data;
|
|
}
|
|
|
|
$sensitiveKeys = [
|
|
'password',
|
|
'password_confirmation',
|
|
'token',
|
|
'access_token',
|
|
'refresh_token',
|
|
'app_key',
|
|
'app_secret',
|
|
'session_key',
|
|
'api_key',
|
|
'secret',
|
|
];
|
|
|
|
foreach ($sensitiveKeys as $key) {
|
|
if (isset($data[$key])) {
|
|
$data[$key] = '***FILTERED***';
|
|
}
|
|
}
|
|
|
|
// 递归处理嵌套数组
|
|
foreach ($data as $key => $value) {
|
|
if (is_array($value)) {
|
|
$data[$key] = self::filterSensitiveData($value);
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 获取操作统计
|
|
*/
|
|
public static function getStatistics($startDate = null, $endDate = null)
|
|
{
|
|
$query = self::query();
|
|
|
|
if ($startDate) {
|
|
$query->where('created_at', '>=', $startDate);
|
|
}
|
|
|
|
if ($endDate) {
|
|
$query->where('created_at', '<=', $endDate);
|
|
}
|
|
|
|
$total = $query->count();
|
|
$success = $query->where('response_code', '<', 400)->count();
|
|
$error = $query->where('response_code', '>=', 400)->count();
|
|
|
|
$modules = $query->selectRaw('module, COUNT(*) as count')
|
|
->groupBy('module')
|
|
->orderBy('count', 'desc')
|
|
->limit(10)
|
|
->get()
|
|
->mapWithKeys(function ($item) {
|
|
return [$item->module => $item->count];
|
|
})
|
|
->toArray();
|
|
|
|
$users = $query->selectRaw('user_name, COUNT(*) as count')
|
|
->groupBy('user_name')
|
|
->orderBy('count', 'desc')
|
|
->limit(10)
|
|
->get()
|
|
->mapWithKeys(function ($item) {
|
|
return [$item->user_name => $item->count];
|
|
})
|
|
->toArray();
|
|
|
|
return [
|
|
'total' => $total,
|
|
'success' => $success,
|
|
'error' => $error,
|
|
'success_rate' => $total > 0 ? round($success / $total * 100, 2) : 0,
|
|
'modules' => $modules,
|
|
'users' => $users,
|
|
];
|
|
}
|
|
} |