ExamAnalysisApiController.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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 (\InvalidArgumentException $e) {
  65. return response()->json([
  66. 'success' => false,
  67. 'message' => $e->getMessage(),
  68. ], 422);
  69. } catch (\Exception $e) {
  70. Log::error('学情报告API失败', [
  71. 'paper_id' => $paperId,
  72. 'student_id' => $studentId,
  73. 'record_id' => $recordId,
  74. 'error' => $e->getMessage(),
  75. ]);
  76. return response()->json([
  77. 'success' => false,
  78. 'message' => '服务异常:' . $e->getMessage(),
  79. ], 500);
  80. }
  81. }
  82. /**
  83. * 轮询任务状态
  84. */
  85. public function status(string $taskId): JsonResponse
  86. {
  87. try {
  88. $task = $this->taskManager->getTaskStatus($taskId);
  89. if (!$task) {
  90. return response()->json([
  91. 'success' => false,
  92. 'message' => '任务不存在',
  93. ], 404);
  94. }
  95. return response()->json([
  96. 'success' => true,
  97. 'data' => $task,
  98. ]);
  99. } catch (\Exception $e) {
  100. Log::error('查询学情报告任务状态失败', [
  101. 'task_id' => $taskId,
  102. 'error' => $e->getMessage(),
  103. ]);
  104. return response()->json([
  105. 'success' => false,
  106. 'message' => '查询失败:' . $e->getMessage(),
  107. ], 500);
  108. }
  109. }
  110. /**
  111. * 获取PDF报告URL
  112. * 查询指定试卷是否已有生成好的学情分析报告
  113. */
  114. public function getPdfUrl(string $paperId): JsonResponse
  115. {
  116. try {
  117. // 从 exam_analysis_results 表查询PDF URL
  118. $report = DB::table('exam_analysis_results')
  119. ->where('paper_id', $paperId)
  120. ->first();
  121. if ($report && !empty($report->analysis_pdf_url)) {
  122. Log::info('学情报告PDF URL查询成功(从数据库)', [
  123. 'paper_id' => $paperId,
  124. 'pdf_url' => $report->analysis_pdf_url,
  125. ]);
  126. return response()->json([
  127. 'success' => true,
  128. 'data' => [
  129. 'paper_id' => $paperId,
  130. 'status' => 'completed',
  131. 'pdf_url' => $report->analysis_pdf_url,
  132. 'message' => '报告已生成',
  133. 'generated_at' => $report->created_at ?? null,
  134. ]
  135. ], 200, [], JSON_UNESCAPED_SLASHES);
  136. }
  137. // 如果数据库中没有找到报告
  138. Log::info('未找到学情报告', ['paper_id' => $paperId]);
  139. return response()->json([
  140. 'success' => true,
  141. 'data' => [
  142. 'paper_id' => $paperId,
  143. 'status' => 'not_found',
  144. 'pdf_url' => null,
  145. 'message' => '报告尚未生成,请先提交试卷进行分析',
  146. ]
  147. ], 200, [], JSON_UNESCAPED_SLASHES);
  148. } catch (\Exception $e) {
  149. Log::error('查询学情报告PDF URL失败', [
  150. 'paper_id' => $paperId,
  151. 'error' => $e->getMessage(),
  152. ]);
  153. return response()->json([
  154. 'success' => false,
  155. 'message' => '查询失败:' . $e->getMessage(),
  156. ], 500);
  157. }
  158. }
  159. /**
  160. * 从试卷ID获取学生ID
  161. */
  162. private function getStudentIdFromPaper(string $paperId): ?string
  163. {
  164. try {
  165. $paper = \App\Models\Paper::find($paperId);
  166. return $paper?->student_id;
  167. } catch (\Exception $e) {
  168. Log::warning('获取试卷学生ID失败', [
  169. 'paper_id' => $paperId,
  170. 'error' => $e->getMessage(),
  171. ]);
  172. return null;
  173. }
  174. }
  175. }