yemeishu 5 днів тому
батько
коміт
b18214bed8

+ 119 - 0
app/Http/Controllers/Api/ExamAnalysisApiController.php

@@ -119,6 +119,125 @@ class ExamAnalysisApiController extends Controller
         }
     }
 
+    /**
+     * 获取PDF报告URL
+     * 查询指定试卷是否已有生成好的学情分析报告
+     */
+    public function getPdfUrl(string $paperId): JsonResponse
+    {
+        try {
+            // 首先尝试从 student_reports 表直接查询(最快速的方式)
+            $report = \App\Models\StudentReport::where('exam_id', $paperId)
+                ->where('report_type', 'exam_analysis')
+                ->first();
+
+            if ($report && $report->pdf_url && $report->generation_status === 'completed') {
+                Log::info('学情报告PDF URL查询成功(从数据库)', [
+                    'paper_id' => $paperId,
+                    'pdf_url' => $report->pdf_url,
+                ]);
+
+                return response()->json([
+                    'success' => true,
+                    'data' => [
+                        'paper_id' => $paperId,
+                        'status' => 'completed',
+                        'pdf_url' => $report->pdf_url,
+                        'message' => '报告已生成',
+                        'generated_at' => $report->generated_at?->toISOString(),
+                    ]
+                ], 200, [], JSON_UNESCAPED_SLASHES);
+            }
+
+            // 如果数据库中没有,尝试从任务系统查找
+            $task = $this->taskManager->findAnalysisTaskByPaperId($paperId);
+
+            if ($task) {
+                $status = $task['status'];
+                $pdfUrl = $task['pdf_url'] ?? null;
+
+                if ($status === \App\Services\TaskManager::STATUS_COMPLETED && $pdfUrl) {
+                    // 任务已完成且有PDF URL
+                    Log::info('学情报告PDF URL查询成功(从任务系统)', [
+                        'paper_id' => $paperId,
+                        'task_id' => $task['task_id'],
+                        'pdf_url' => $pdfUrl,
+                    ]);
+
+                    return response()->json([
+                        'success' => true,
+                        'data' => [
+                            'paper_id' => $paperId,
+                            'status' => 'completed',
+                            'pdf_url' => $pdfUrl,
+                            'message' => '报告已生成',
+                            'generated_at' => $task['completed_at'] ?? null,
+                        ]
+                    ], 200, [], JSON_UNESCAPED_SLASHES);
+                } elseif ($status === \App\Services\TaskManager::STATUS_PROCESSING) {
+                    // 任务正在处理中
+                    Log::info('学情报告正在生成中', [
+                        'paper_id' => $paperId,
+                        'task_id' => $task['task_id'],
+                        'progress' => $task['progress'] ?? 0,
+                    ]);
+
+                    return response()->json([
+                        'success' => true,
+                        'data' => [
+                            'paper_id' => $paperId,
+                            'status' => 'processing',
+                            'pdf_url' => null,
+                            'message' => '报告正在生成中,请稍后刷新页面查看',
+                            'progress' => $task['progress'] ?? 0,
+                        ]
+                    ], 200, [], JSON_UNESCAPED_SLASHES);
+                } elseif ($status === \App\Services\TaskManager::STATUS_FAILED) {
+                    // 任务失败
+                    Log::warning('学情报告生成失败', [
+                        'paper_id' => $paperId,
+                        'task_id' => $task['task_id'],
+                        'error' => $task['error'] ?? '未知错误',
+                    ]);
+
+                    return response()->json([
+                        'success' => false,
+                        'data' => [
+                            'paper_id' => $paperId,
+                            'status' => 'failed',
+                            'pdf_url' => null,
+                            'message' => '报告生成失败:' . ($task['error'] ?? '未知错误'),
+                        ]
+                    ], 200, [], JSON_UNESCAPED_SLASHES);
+                }
+            }
+
+            // 既没有完成的任务,也没有正在进行的任务
+            Log::info('未找到学情报告任务', ['paper_id' => $paperId]);
+
+            return response()->json([
+                'success' => true,
+                'data' => [
+                    'paper_id' => $paperId,
+                    'status' => 'not_found',
+                    'pdf_url' => null,
+                    'message' => '报告尚未生成,请先提交试卷进行分析',
+                ]
+            ], 200, [], JSON_UNESCAPED_SLASHES);
+
+        } catch (\Exception $e) {
+            Log::error('查询学情报告PDF URL失败', [
+                'paper_id' => $paperId,
+                'error' => $e->getMessage(),
+            ]);
+
+            return response()->json([
+                'success' => false,
+                'message' => '查询失败:' . $e->getMessage(),
+            ], 500);
+        }
+    }
+
     /**
      * 从试卷ID获取学生ID
      */

+ 50 - 0
app/Services/TaskManager.php

@@ -48,6 +48,9 @@ class TaskManager
 
         $this->saveTask($taskId, $taskData);
 
+        // 保存任务映射(用于快速查找)
+        $this->saveTaskMapping($type, $data, $taskId);
+
         Log::info('TaskManager: 任务已创建', [
             'task_id' => $taskId,
             'type' => $type,
@@ -205,6 +208,53 @@ class TaskManager
         return "task:{$taskId}";
     }
 
+    /**
+     * 保存任务映射
+     */
+    private function saveTaskMapping(string $type, array $data, string $taskId): void
+    {
+        if ($type === self::TASK_TYPE_ANALYSIS) {
+            $paperId = $data['paperId'] ?? $data['paper_id'] ?? null;
+            $studentId = $data['studentId'] ?? $data['student_id'] ?? null;
+
+            if ($paperId) {
+                $mappingKey = $this->getTaskMappingKey($paperId, $studentId);
+                Cache::put($mappingKey, $taskId, now()->addDay());
+            }
+        }
+    }
+
+    /**
+     * 根据试卷ID查找分析任务
+     */
+    public function findAnalysisTaskByPaperId(string $paperId, ?string $studentId = null): ?array
+    {
+        // 尝试从映射缓存中获取任务ID
+        $mappingKey = $this->getTaskMappingKey($paperId, $studentId);
+        $taskId = Cache::get($mappingKey);
+
+        if ($taskId) {
+            $task = $this->loadTask($taskId);
+            if ($task) {
+                return $task;
+            } else {
+                // 任务不存在,清理映射缓存
+                Cache::forget($mappingKey);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 获取任务映射缓存键
+     */
+    private function getTaskMappingKey(string $paperId, ?string $studentId = null): string
+    {
+        $studentPart = $studentId ? "_{$studentId}" : '';
+        return "task_mapping:analysis:{$paperId}{$studentPart}";
+    }
+
     /**
      * 构建回调负载
      */

+ 10 - 0
routes/api.php

@@ -463,6 +463,16 @@ Route::get('/exam-analysis/status/{taskId}', [ExamAnalysisApiController::class,
     ])
     ->name('api.exam-analysis.status');
 
+// 获取PDF报告URL(查询指定试卷的报告状态)
+Route::get('/exam-analysis/pdf/{paper_id}', [ExamAnalysisApiController::class, 'getPdfUrl'])
+    ->withoutMiddleware([
+        Authenticate::class,
+        'auth',
+        'auth:sanctum',
+        'auth:api',
+    ])
+    ->name('api.exam-analysis.pdf');
+
 /*
 |--------------------------------------------------------------------------
 | 错题本 API 路由