|
|
@@ -5,11 +5,9 @@ namespace App\Services;
|
|
|
use App\DTO\ExamAnalysisDataDto;
|
|
|
use App\DTO\ReportPayloadDto;
|
|
|
use App\Jobs\ProcessAnalysisReportTaskJob;
|
|
|
-use App\Models\OCRRecord;
|
|
|
use App\Models\Paper;
|
|
|
use App\Models\PaperQuestion;
|
|
|
use App\Models\Student;
|
|
|
-use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
/**
|
|
|
@@ -27,63 +25,13 @@ class ExamAnalysisService
|
|
|
private readonly ExamAnswerAnalysisService $examAnswerAnalysisService
|
|
|
) {}
|
|
|
|
|
|
- /**
|
|
|
- * 入队前校验:试卷/学生/分析数据等,避免无效任务进入 pdf 队列占用 worker。
|
|
|
- *
|
|
|
- * @throws \InvalidArgumentException
|
|
|
- */
|
|
|
- public function validateAnalysisReportEnqueue(string $paperId, string $studentId, ?string $recordId = null): void
|
|
|
- {
|
|
|
- $studentIdNorm = (string) $studentId;
|
|
|
-
|
|
|
- $paper = Paper::query()->select(['paper_id', 'student_id'])->find($paperId);
|
|
|
- if (! $paper) {
|
|
|
- throw new \InvalidArgumentException('试卷不存在');
|
|
|
- }
|
|
|
-
|
|
|
- if ($paper->student_id !== null && $paper->student_id !== ''
|
|
|
- && (string) $paper->student_id !== $studentIdNorm) {
|
|
|
- throw new \InvalidArgumentException('学生与试卷不匹配');
|
|
|
- }
|
|
|
-
|
|
|
- if (! Student::query()->where('student_id', $studentId)->exists()) {
|
|
|
- throw new \InvalidArgumentException('学生不存在');
|
|
|
- }
|
|
|
-
|
|
|
- if ($recordId !== null && $recordId !== '') {
|
|
|
- $ocr = OCRRecord::query()->find($recordId);
|
|
|
- if (! $ocr) {
|
|
|
- throw new \InvalidArgumentException('OCR 记录不存在');
|
|
|
- }
|
|
|
- if ((string) $ocr->student_id !== $studentIdNorm) {
|
|
|
- throw new \InvalidArgumentException('OCR 记录与学生不匹配');
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $row = DB::connection('mysql')->table('exam_analysis_results')
|
|
|
- ->where('paper_id', $paperId)
|
|
|
- ->where('student_id', $studentId)
|
|
|
- ->orderByDesc('created_at')
|
|
|
- ->first();
|
|
|
-
|
|
|
- if (! $row || $row->analysis_data === null || $row->analysis_data === '') {
|
|
|
- throw new \InvalidArgumentException('尚未完成答题分析或分析数据为空,请先完成阅卷分析后再生成报告');
|
|
|
- }
|
|
|
-
|
|
|
- $decoded = json_decode((string) $row->analysis_data, true);
|
|
|
- if (! is_array($decoded) || $decoded === []) {
|
|
|
- throw new \InvalidArgumentException('分析数据无效,无法生成 PDF');
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 生成学情报告
|
|
|
- * 异步模式,立即返回任务ID
|
|
|
+ * 异步模式,立即返回任务ID。
|
|
|
+ * 入队仅创建任务并投递 pdf 队列;构建分析数据、渲染与上传等复杂流程在 worker 内执行。
|
|
|
*/
|
|
|
public function generateReport(string $paperId, string $studentId, ?string $recordId = null): string
|
|
|
{
|
|
|
- $this->validateAnalysisReportEnqueue($paperId, $studentId, $recordId);
|
|
|
-
|
|
|
// 创建异步任务
|
|
|
$taskId = $this->taskManager->createTask(
|
|
|
TaskManager::TASK_TYPE_ANALYSIS,
|