erp-backend/app/Models/OperationLog.php
2026-04-01 17:07:04 +08:00

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,
];
}
}