apiGroups = $this->buildFromRoutes(); } private function buildFromRoutes(): array { $routes = Route::getRoutes(); $groups = []; $detailsMap = $this->buildDetailsMap(); foreach ($routes as $route) { $uri = $route->uri(); if (!str_starts_with($uri, 'api/')) { continue; } $methods = array_values(array_filter($route->methods(), fn ($method) => $method !== 'HEAD')); $path = '/' . $uri; $groupName = $this->resolveGroupName($uri); $tag = $this->resolveTag($route, $uri); $params = $this->buildParamHint($uri, $methods); $response = 'JSON'; $details = $detailsMap[$uri] ?? []; $details['route_name'] = $route->getName(); $details['action'] = $route->getActionName(); foreach ($methods as $method) { $groups[$groupName]['name'] = $groupName; $groups[$groupName]['items'][] = [ 'method' => $method, 'path' => $path, 'params' => $params, 'response' => $response, 'tag' => $tag, 'details' => $details, ]; } } ksort($groups); return array_values($groups); } private function buildDetailsMap(): array { return [ 'api/papers/{paperId}/json' => [ 'description' => '返回与智能出卷返回值中 exam_content 完全一致的试卷 JSON。', 'examples' => [ 'GET /api/papers/paper_1765788931_ce02f6a3/json', 'GET /api/papers/paper_1765788931_ce02f6a3/json?download=1', ], ], ]; } private function resolveGroupName(string $uri): string { $map = [ 'api/questions' => '题库核心 API', 'api/papers' => '题库核心 API', 'api/knowledge-mastery' => '知识点掌握', 'api/mistake-book' => '错题本 API', 'api/analytics' => '错题本 API', 'api/intelligent-exams' => '智能出卷与学情报告', 'api/exam-analysis' => '智能出卷与学情报告', 'api/textbooks' => '教材 API', 'api/mathrecsys' => 'MathRecSys 集成 API', 'api/knowledge' => '知识点与能力 API', 'api/knowledge-points' => '知识点与能力 API', ]; foreach ($map as $prefix => $name) { if (str_starts_with($uri, $prefix)) { return $name; } } if (str_starts_with($uri, 'api/ocr') || str_contains($uri, 'callback')) { return '回调与内部 API'; } if (str_contains($uri, 'test')) { return '测试 API'; } return '其他'; } private function resolveTag(\Illuminate\Routing\Route $route, string $uri): ?string { $middleware = (array) $route->middleware(); if (in_array('internal.token', $middleware, true)) { return 'internal'; } if (str_contains($uri, 'test')) { return 'test'; } return null; } private function buildParamHint(string $uri, array $methods): string { preg_match_all('/\{([^}]+)\}/', $uri, $matches); $pathParams = $matches[1] ?? []; $parts = []; if (!empty($pathParams)) { $parts[] = 'path: ' . implode(', ', $pathParams); } $hasBody = array_intersect($methods, ['POST', 'PUT', 'PATCH']); if ($hasBody) { $parts[] = 'body: payload'; } if (empty($parts)) { return 'query/body: -'; } return implode(' | ', $parts); } }