validate([ 'paper_id' => 'required|string', 'student_id' => 'nullable|string', 'callback_url' => 'nullable|url', ]); $paperId = $data['paper_id']; $studentId = $data['student_id'] ?? null; $paper = Paper::find($paperId); if (!$paper) { return response()->json([ 'success' => false, 'message' => '未找到试卷', ], 404); } if (!$studentId) { $studentId = $paper->student_id; } if (!$studentId) { return response()->json([ 'success' => false, 'message' => '缺少 student_id', ], 422); } try { // 创建异步任务 $taskId = $this->createAsyncTask($paperId, $studentId, $data); // 立即返回任务信息 $viewUrl = URL::to("/admin/exam-analysis?paperId={$paperId}&studentId={$studentId}"); $payload = [ 'success' => true, 'message' => '学情报告任务已创建,正在后台生成PDF...', 'data' => [ 'task_id' => $taskId, 'paper_id' => $paperId, 'student_id' => $studentId, 'status' => 'processing', 'analysis_url' => $viewUrl, 'pdf_url' => null, // 稍后生成 'created_at' => now()->toISOString(), ], ]; return response()->json($payload, 200, [], JSON_UNESCAPED_SLASHES); } catch (\Exception $e) { Log::error('学情报告API失败', [ 'paper_id' => $paperId, 'student_id' => $studentId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '服务异常,请稍后重试', ], 500); } } /** * 轮询任务状态 */ public function status(string $taskId): JsonResponse { try { $task = $this->getTaskStatus($taskId); if (!$task) { return response()->json([ 'success' => false, 'message' => '任务不存在', ], 404); } return response()->json([ 'success' => true, 'data' => $task, ]); } catch (\Exception $e) { Log::error('查询学情报告任务状态失败', [ 'task_id' => $taskId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '查询失败,请稍后重试', ], 500); } } /** * 创建异步任务 */ private function createAsyncTask(string $paperId, string $studentId, array $data): string { $taskId = 'analysis_' . uniqid() . '_' . substr(md5($paperId . $studentId . time()), 0, 8); // 保存任务信息到缓存 $taskData = [ 'task_id' => $taskId, 'paper_id' => $paperId, 'student_id' => $studentId, 'status' => 'processing', 'created_at' => now()->toISOString(), 'updated_at' => now()->toISOString(), 'progress' => 0, 'message' => '正在生成学情报告...', 'data' => $data, 'callback_url' => $data['callback_url'] ?? null, ]; // 保存到缓存,24小时过期 cache()->put("analysis_task:{$taskId}", $taskData, now()->addDay()); // 触发后台处理 $this->processAnalysisGeneration($taskId, $paperId, $studentId); return $taskId; } /** * 获取任务状态 */ private function getTaskStatus(string $taskId): ?array { return cache()->get("analysis_task:{$taskId}"); } /** * 处理学情报告生成 */ private function processAnalysisGeneration(string $taskId, string $paperId, string $studentId): void { try { // 更新任务状态 $this->updateTaskStatus($taskId, [ 'status' => 'processing', 'progress' => 10, 'message' => '开始生成学情报告...', ]); // 生成学情报告PDF $pdfUrl = app(ExamPdfExportService::class)->generateAnalysisReportPdf($paperId, $studentId); // 更新任务状态为完成 $this->updateTaskStatus($taskId, [ 'status' => 'completed', 'progress' => 100, 'message' => '学情报告生成完成', 'pdf_url' => $pdfUrl, 'completed_at' => now()->toISOString(), ]); Log::info('学情报告异步任务完成', [ 'task_id' => $taskId, 'paper_id' => $paperId, 'student_id' => $studentId, 'pdf_url' => $pdfUrl, ]); // 发送回调通知 $this->sendCallbackNotification($taskId); } catch (\Exception $e) { Log::error('学情报告生成失败', [ 'task_id' => $taskId, 'paper_id' => $paperId, 'student_id' => $studentId, 'error' => $e->getMessage(), ]); // 更新任务状态为失败 $this->updateTaskStatus($taskId, [ 'status' => 'failed', 'progress' => 0, 'message' => '学情报告生成失败: ' . $e->getMessage(), 'error' => $e->getMessage(), ]); } } /** * 更新任务状态 */ private function updateTaskStatus(string $taskId, array $updates): void { $task = $this->getTaskStatus($taskId); if (!$task) { return; } $updatedTask = array_merge($task, $updates, [ 'updated_at' => now()->toISOString(), ]); cache()->put("analysis_task:{$taskId}", $updatedTask, now()->addDay()); } /** * 发送回调通知 */ private function sendCallbackNotification(string $taskId): void { $task = $this->getTaskStatus($taskId); if (!$task || !$task['callback_url']) { return; } try { $payload = [ 'task_id' => $task['task_id'], 'paper_id' => $task['paper_id'], 'student_id' => $task['student_id'], 'status' => $task['status'], 'pdf_url' => $task['pdf_url'] ?? null, 'completed_at' => $task['completed_at'], 'callback_type' => 'analysis_report_generated', ]; $response = Http::timeout(30) ->post($task['callback_url'], $payload); if ($response->successful()) { Log::info('学情报告回调通知发送成功', [ 'task_id' => $taskId, 'callback_url' => $task['callback_url'], ]); } else { Log::warning('学情报告回调通知发送失败', [ 'task_id' => $taskId, 'callback_url' => $task['callback_url'], 'status' => $response->status(), ]); } } catch (\Exception $e) { Log::error('学情报告回调通知异常', [ 'task_id' => $taskId, 'callback_url' => $task['callback_url'] ?? 'unknown', 'error' => $e->getMessage(), ]); } } }