ExamAnalysisApiController.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Controller;
  4. use App\Services\ExamAnalysisService;
  5. use App\Services\TaskManager;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Support\Facades\DB;
  9. use Illuminate\Support\Facades\Log;
  10. class ExamAnalysisApiController extends Controller
  11. {
  12. public function __construct(
  13. private readonly ExamAnalysisService $examAnalysisService,
  14. private readonly TaskManager $taskManager
  15. ) {}
  16. /**
  17. * 生成学情报告(异步模式)
  18. * 立即返回任务ID,PDF生成在后台进行
  19. */
  20. public function store(Request $request): JsonResponse
  21. {
  22. $data = $request->validate([
  23. 'paper_id' => 'required|string',
  24. 'student_id' => 'nullable|string',
  25. 'record_id' => 'nullable|string',
  26. 'callback_url' => 'nullable|url',
  27. ]);
  28. $paperId = $data['paper_id'];
  29. $studentId = $data['student_id'] ?? null;
  30. $recordId = $data['record_id'] ?? null;
  31. try {
  32. // 如果没有提供student_id,尝试从paper_id获取
  33. if (!$studentId) {
  34. $studentId = $this->getStudentIdFromPaper($paperId);
  35. }
  36. if (!$studentId) {
  37. return response()->json([
  38. 'success' => false,
  39. 'message' => '缺少 student_id',
  40. ], 422);
  41. }
  42. // 使用ExamAnalysisService生成报告
  43. $taskId = $this->examAnalysisService->generateReport($paperId, $studentId, $recordId);
  44. // 构建返回数据
  45. $payload = [
  46. 'success' => true,
  47. 'message' => '学情报告任务已创建,正在后台生成PDF...',
  48. 'data' => [
  49. 'task_id' => $taskId,
  50. 'paper_id' => $paperId,
  51. 'student_id' => $studentId,
  52. 'record_id' => $recordId,
  53. 'status' => 'processing',
  54. 'analysis_url' => route('filament.admin.pages.exam-analysis', [
  55. 'paperId' => $paperId,
  56. 'studentId' => $studentId,
  57. 'recordId' => $recordId,
  58. ]),
  59. 'pdf_url' => null, // 稍后生成
  60. 'created_at' => now()->toISOString(),
  61. ],
  62. ];
  63. return response()->json($payload, 200, [], JSON_UNESCAPED_SLASHES);
  64. } catch (\Exception $e) {
  65. Log::error('学情报告API失败', [
  66. 'paper_id' => $paperId,
  67. 'student_id' => $studentId,
  68. 'record_id' => $recordId,
  69. 'error' => $e->getMessage(),
  70. ]);
  71. return response()->json([
  72. 'success' => false,
  73. 'message' => '服务异常:' . $e->getMessage(),
  74. ], 500);
  75. }
  76. }
  77. /**
  78. * 轮询任务状态
  79. */
  80. public function status(string $taskId): JsonResponse
  81. {
  82. try {
  83. $task = $this->taskManager->getTaskStatus($taskId);
  84. if (!$task) {
  85. return response()->json([
  86. 'success' => false,
  87. 'message' => '任务不存在',
  88. ], 404);
  89. }
  90. return response()->json([
  91. 'success' => true,
  92. 'data' => $task,
  93. ]);
  94. } catch (\Exception $e) {
  95. Log::error('查询学情报告任务状态失败', [
  96. 'task_id' => $taskId,
  97. 'error' => $e->getMessage(),
  98. ]);
  99. return response()->json([
  100. 'success' => false,
  101. 'message' => '查询失败:' . $e->getMessage(),
  102. ], 500);
  103. }
  104. }
  105. /**
  106. * 获取PDF报告URL
  107. * 查询指定试卷是否已有生成好的学情分析报告
  108. */
  109. public function getPdfUrl(string $paperId): JsonResponse
  110. {
  111. try {
  112. // 从 exam_analysis_results 表查询PDF URL
  113. $report = DB::table('exam_analysis_results')
  114. ->where('paper_id', $paperId)
  115. ->first();
  116. if ($report && !empty($report->analysis_pdf_url)) {
  117. Log::info('学情报告PDF URL查询成功(从数据库)', [
  118. 'paper_id' => $paperId,
  119. 'pdf_url' => $report->analysis_pdf_url,
  120. ]);
  121. return response()->json([
  122. 'success' => true,
  123. 'data' => [
  124. 'paper_id' => $paperId,
  125. 'status' => 'completed',
  126. 'pdf_url' => $report->analysis_pdf_url,
  127. 'message' => '报告已生成',
  128. 'generated_at' => $report->created_at ?? null,
  129. ]
  130. ], 200, [], JSON_UNESCAPED_SLASHES);
  131. }
  132. // 如果数据库中没有找到报告
  133. Log::info('未找到学情报告', ['paper_id' => $paperId]);
  134. return response()->json([
  135. 'success' => true,
  136. 'data' => [
  137. 'paper_id' => $paperId,
  138. 'status' => 'not_found',
  139. 'pdf_url' => null,
  140. 'message' => '报告尚未生成,请先提交试卷进行分析',
  141. ]
  142. ], 200, [], JSON_UNESCAPED_SLASHES);
  143. } catch (\Exception $e) {
  144. Log::error('查询学情报告PDF URL失败', [
  145. 'paper_id' => $paperId,
  146. 'error' => $e->getMessage(),
  147. ]);
  148. return response()->json([
  149. 'success' => false,
  150. 'message' => '查询失败:' . $e->getMessage(),
  151. ], 500);
  152. }
  153. }
  154. /**
  155. * 从试卷ID获取学生ID
  156. */
  157. private function getStudentIdFromPaper(string $paperId): ?string
  158. {
  159. try {
  160. $paper = \App\Models\Paper::find($paperId);
  161. return $paper?->student_id;
  162. } catch (\Exception $e) {
  163. Log::warning('获取试卷学生ID失败', [
  164. 'paper_id' => $paperId,
  165. 'error' => $e->getMessage(),
  166. ]);
  167. return null;
  168. }
  169. }
  170. }