368 lines
11 KiB
PHP
368 lines
11 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\OperationLog;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class OperationLogController extends Controller
|
||
{
|
||
/**
|
||
* 操作日志列表
|
||
*/
|
||
public function index(Request $request)
|
||
{
|
||
$query = OperationLog::with('user')->orderBy('created_at', 'desc');
|
||
|
||
// 筛选条件
|
||
if ($request->filled('user_id')) {
|
||
$query->where('user_id', $request->user_id);
|
||
}
|
||
|
||
if ($request->filled('user_name')) {
|
||
$query->where('user_name', 'like', "%{$request->user_name}%");
|
||
}
|
||
|
||
if ($request->filled('module')) {
|
||
$query->where('module', $request->module);
|
||
}
|
||
|
||
if ($request->filled('action')) {
|
||
$query->where('action', $request->action);
|
||
}
|
||
|
||
if ($request->filled('method')) {
|
||
$query->where('method', $request->method);
|
||
}
|
||
|
||
if ($request->filled('path')) {
|
||
$query->where('path', 'like', "%{$request->path}%");
|
||
}
|
||
|
||
if ($request->filled('ip')) {
|
||
$query->where('ip', 'like', "%{$request->ip}%");
|
||
}
|
||
|
||
if ($request->filled('response_code')) {
|
||
if ($request->response_code === 'success') {
|
||
$query->where('response_code', '<', 400);
|
||
} elseif ($request->response_code === 'error') {
|
||
$query->where('response_code', '>=', 400);
|
||
} else {
|
||
$query->where('response_code', $request->response_code);
|
||
}
|
||
}
|
||
|
||
if ($request->filled('keyword')) {
|
||
$keyword = $request->keyword;
|
||
$query->where(function ($q) use ($keyword) {
|
||
$q->where('user_name', 'like', "%{$keyword}%")
|
||
->orWhere('module', 'like', "%{$keyword}%")
|
||
->orWhere('action', 'like', "%{$keyword}%")
|
||
->orWhere('path', 'like', "%{$keyword}%")
|
||
->orWhere('ip', 'like', "%{$keyword}%")
|
||
->orWhere('remark', 'like', "%{$keyword}%");
|
||
});
|
||
}
|
||
|
||
if ($request->filled('date_range')) {
|
||
$dates = explode(',', $request->date_range);
|
||
if (count($dates) === 2) {
|
||
$query->whereBetween('created_at', [$dates[0], $dates[1]]);
|
||
}
|
||
}
|
||
|
||
$perPage = $request->input('limit', 20);
|
||
$logs = $query->paginate($perPage);
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'list' => $logs->items(),
|
||
'total' => $logs->total(),
|
||
'current_page' => $logs->currentPage(),
|
||
'last_page' => $logs->lastPage(),
|
||
],
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 操作日志详情
|
||
*/
|
||
public function show(string $id)
|
||
{
|
||
$log = OperationLog::with('user')->find($id);
|
||
|
||
if (!$log) {
|
||
return response()->json([
|
||
'code' => 404,
|
||
'message' => '日志不存在'
|
||
], 404);
|
||
}
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $log,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 删除操作日志
|
||
*/
|
||
public function destroy(string $id)
|
||
{
|
||
$log = OperationLog::find($id);
|
||
|
||
if (!$log) {
|
||
return response()->json([
|
||
'code' => 404,
|
||
'message' => '日志不存在'
|
||
], 404);
|
||
}
|
||
|
||
try {
|
||
$log->delete();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'message' => '操作日志删除成功'
|
||
]);
|
||
} catch (\Exception $e) {
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '删除失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量删除操作日志
|
||
*/
|
||
public function batchDelete(Request $request)
|
||
{
|
||
$request->validate([
|
||
'log_ids' => 'required|array|min:1',
|
||
'log_ids.*' => 'integer|exists:operation_logs,id',
|
||
]);
|
||
|
||
$successCount = 0;
|
||
$failedLogs = [];
|
||
|
||
try {
|
||
foreach ($request->log_ids as $logId) {
|
||
$log = OperationLog::find($logId);
|
||
|
||
if (!$log) {
|
||
$failedLogs[] = ['id' => $logId, 'reason' => '日志不存在'];
|
||
continue;
|
||
}
|
||
|
||
$log->delete();
|
||
$successCount++;
|
||
}
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'success_count' => $successCount,
|
||
'failed_logs' => $failedLogs,
|
||
],
|
||
'message' => "批量删除成功,成功 {$successCount} 个"
|
||
]);
|
||
} catch (\Exception $e) {
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '批量删除失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清空操作日志
|
||
*/
|
||
public function clear(Request $request)
|
||
{
|
||
$request->validate([
|
||
'days' => 'nullable|integer|min:1|max:365',
|
||
]);
|
||
|
||
try {
|
||
$query = OperationLog::query();
|
||
|
||
if ($request->filled('days')) {
|
||
$date = now()->subDays($request->days);
|
||
$query->where('created_at', '<', $date);
|
||
}
|
||
|
||
$deletedCount = $query->delete();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => ['deleted_count' => $deletedCount],
|
||
'message' => "成功清空 {$deletedCount} 条操作日志"
|
||
]);
|
||
} catch (\Exception $e) {
|
||
return response()->json([
|
||
'code' => 500,
|
||
'message' => '清空失败: ' . $e->getMessage()
|
||
], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取操作统计
|
||
*/
|
||
public function statistics(Request $request)
|
||
{
|
||
$request->validate([
|
||
'start_date' => 'nullable|date',
|
||
'end_date' => 'nullable|date',
|
||
'group_by' => 'nullable|string|in:day,week,month',
|
||
]);
|
||
|
||
$startDate = $request->start_date ?: now()->subDays(30)->toDateString();
|
||
$endDate = $request->end_date ?: now()->toDateString();
|
||
$groupBy = $request->group_by ?: 'day';
|
||
|
||
// 总体统计
|
||
$overallStats = OperationLog::getStatistics($startDate, $endDate);
|
||
|
||
// 时间趋势统计
|
||
$trendQuery = OperationLog::whereBetween('created_at', [$startDate, $endDate]);
|
||
|
||
switch ($groupBy) {
|
||
case 'day':
|
||
$trendQuery->selectRaw('DATE(created_at) as date, COUNT(*) as count')
|
||
->groupBy(DB::raw('DATE(created_at)'))
|
||
->orderBy('date', 'asc');
|
||
break;
|
||
case 'week':
|
||
$trendQuery->selectRaw('YEARWEEK(created_at, 1) as week, COUNT(*) as count')
|
||
->groupBy(DB::raw('YEARWEEK(created_at, 1)'))
|
||
->orderBy('week', 'asc');
|
||
break;
|
||
case 'month':
|
||
$trendQuery->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, COUNT(*) as count')
|
||
->groupBy(DB::raw('DATE_FORMAT(created_at, "%Y-%m")'))
|
||
->orderBy('month', 'asc');
|
||
break;
|
||
}
|
||
|
||
$trendStats = $trendQuery->get();
|
||
|
||
// 模块统计详情
|
||
$moduleStats = OperationLog::whereBetween('created_at', [$startDate, $endDate])
|
||
->selectRaw('module, COUNT(*) as total,
|
||
SUM(CASE WHEN response_code < 400 THEN 1 ELSE 0 END) as success,
|
||
SUM(CASE WHEN response_code >= 400 THEN 1 ELSE 0 END) as error')
|
||
->groupBy('module')
|
||
->orderBy('total', 'desc')
|
||
->get();
|
||
|
||
// 用户操作统计
|
||
$userStats = OperationLog::whereBetween('created_at', [$startDate, $endDate])
|
||
->selectRaw('user_id, user_name, COUNT(*) as total')
|
||
->groupBy('user_id', 'user_name')
|
||
->orderBy('total', 'desc')
|
||
->limit(20)
|
||
->get();
|
||
|
||
// 响应时间统计
|
||
$responseTimeStats = OperationLog::whereBetween('created_at', [$startDate, $endDate])
|
||
->selectRaw('AVG(execution_time) as avg_time,
|
||
MIN(execution_time) as min_time,
|
||
MAX(execution_time) as max_time')
|
||
->first();
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'overall' => $overallStats,
|
||
'trend' => $trendStats,
|
||
'modules' => $moduleStats,
|
||
'users' => $userStats,
|
||
'response_time' => $responseTimeStats,
|
||
'date_range' => [
|
||
'start_date' => $startDate,
|
||
'end_date' => $endDate,
|
||
],
|
||
],
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取模块列表
|
||
*/
|
||
public function getModules()
|
||
{
|
||
$modules = OperationLog::select('module')
|
||
->distinct()
|
||
->orderBy('module', 'asc')
|
||
->pluck('module');
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $modules,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取操作类型列表
|
||
*/
|
||
public function getActions()
|
||
{
|
||
$actions = OperationLog::select('action')
|
||
->distinct()
|
||
->orderBy('action', 'asc')
|
||
->pluck('action');
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => $actions,
|
||
'message' => 'success'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 导出操作日志
|
||
*/
|
||
public function export(Request $request)
|
||
{
|
||
$request->validate([
|
||
'format' => 'required|string|in:csv,excel',
|
||
'columns' => 'nullable|array',
|
||
'start_date' => 'nullable|date',
|
||
'end_date' => 'nullable|date',
|
||
]);
|
||
|
||
$query = OperationLog::with('user')->orderBy('created_at', 'desc');
|
||
|
||
if ($request->filled('start_date')) {
|
||
$query->where('created_at', '>=', $request->start_date);
|
||
}
|
||
|
||
if ($request->filled('end_date')) {
|
||
$query->where('created_at', '<=', $request->end_date);
|
||
}
|
||
|
||
$logs = $query->get();
|
||
|
||
// TODO: 实现导出功能
|
||
// 这里返回导出信息,实际导出需要前端处理或使用Laravel Excel
|
||
|
||
return response()->json([
|
||
'code' => 200,
|
||
'data' => [
|
||
'total' => $logs->count(),
|
||
'format' => $request->format,
|
||
'download_url' => null, // 实际项目中这里应该是导出文件的URL
|
||
],
|
||
'message' => '导出请求已接收'
|
||
]);
|
||
}
|
||
} |