diff --git a/backend/app/Controller/Api/V1/RequestLogController.php b/backend/app/Controller/Api/V1/RequestLogController.php new file mode 100644 index 0000000..74d8a78 --- /dev/null +++ b/backend/app/Controller/Api/V1/RequestLogController.php @@ -0,0 +1,139 @@ + 'exact', + 'method' => 'exact', + 'path' => 'like', + 'status_code' => 'exact', + 'created_at_from' => 'date_from', + 'created_at_to' => 'date_to', + ]; + } + + protected function getDefaultSort(): string + { + return 'created_at'; + } + + /** + * 请求日志列表 + */ + #[OA\Get( + path: '/api/v1/logs/requests', + summary: '请求日志列表', + description: '获取 API 请求日志列表,支持分页、按用户/方法/路径/状态码/时间筛选。仅 admin 可访问。', + security: [['bearerAuth' => []]], + tags: ['Request Logs'], + parameters: [ + new OA\Parameter(name: 'page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)), + new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15, maximum: 100)), + new OA\Parameter(name: 'user_id', in: 'query', required: false, description: '用户 ID 精确筛选', schema: new OA\Schema(type: 'integer')), + new OA\Parameter(name: 'method', in: 'query', required: false, description: 'HTTP 方法精确筛选', schema: new OA\Schema(type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])), + new OA\Parameter(name: 'path', in: 'query', required: false, description: '请求路径模糊搜索', schema: new OA\Schema(type: 'string')), + new OA\Parameter(name: 'status_code', in: 'query', required: false, description: 'HTTP 状态码精确筛选', schema: new OA\Schema(type: 'integer')), + new OA\Parameter(name: 'created_at_from', in: 'query', required: false, description: '创建时间起始(含)', schema: new OA\Schema(type: 'string', format: 'date', example: '2026-01-01')), + new OA\Parameter(name: 'created_at_to', in: 'query', required: false, description: '创建时间截止(含)', schema: new OA\Schema(type: 'string', format: 'date', example: '2026-12-31')), + ], + responses: [ + new OA\Response( + response: 200, + description: '获取成功', + content: new OA\JsonContent(properties: [ + new OA\Property(property: 'code', type: 'integer', example: 0), + new OA\Property(property: 'message', type: 'string', example: '获取成功'), + new OA\Property(property: 'data', properties: [ + new OA\Property(property: 'items', type: 'array', items: new OA\Items(ref: '#/components/schemas/ApiRequestLogList')), + new OA\Property(property: 'total', type: 'integer', example: 100), + new OA\Property(property: 'page', type: 'integer', example: 1), + new OA\Property(property: 'per_page', type: 'integer', example: 15), + ], type: 'object'), + ]) + ), + new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), + new OA\Response(response: 403, description: '无权限', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), + ] + )] + #[RequestMapping(path: "", methods: "GET")] + public function index(): ResponseInterface|array + { + return parent::index(); + } + + /** + * 请求日志详情 + */ + #[OA\Get( + path: '/api/v1/logs/requests/{id}', + summary: '请求日志详情', + description: '获取请求日志详情,含完整请求体和 User-Agent。仅 admin 可访问。', + security: [['bearerAuth' => []]], + tags: ['Request Logs'], + parameters: [ + new OA\Parameter(name: 'id', in: 'path', required: true, description: '请求日志 ID', schema: new OA\Schema(type: 'integer')), + ], + responses: [ + new OA\Response( + response: 200, + description: '获取成功', + content: new OA\JsonContent(properties: [ + new OA\Property(property: 'code', type: 'integer', example: 0), + new OA\Property(property: 'message', type: 'string', example: '获取成功'), + new OA\Property(property: 'data', ref: '#/components/schemas/ApiRequestLogDetail'), + ]) + ), + new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), + new OA\Response(response: 403, description: '无权限', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), + new OA\Response(response: 404, description: '数据不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), + ] + )] + #[RequestMapping(path: "{id}", methods: "GET")] + public function show(int $id): ResponseInterface|array + { + return parent::show($id); + } +}