markdownImportId); if (!$import) { Log::error('MarkdownImport not found for batch', [ 'id' => $this->markdownImportId, 'sequence_start' => $this->sequenceStart, 'sequence_end' => $this->sequenceEnd, ]); return; } Log::info('Markdown batch started', [ 'import_id' => $this->markdownImportId, 'sequence_start' => $this->sequenceStart, 'sequence_end' => $this->sequenceEnd, ]); $records = PreQuestionCandidate::query() ->where('import_id', $this->markdownImportId) ->whereBetween('sequence', [$this->sequenceStart, $this->sequenceEnd]) ->orderBy('sequence') ->get(); $processed = 0; $failed = 0; foreach ($records as $record) { try { // 已经处理过的不重复处理 if (in_array($record->status, ['pending', 'reviewed', 'accepted', 'rejected'], true) && $record->stem !== null) { continue; } $parsed = $parser->parseRawMarkdown((string) $record->raw_markdown, (int) $record->index); $record->update([ 'stem' => $parsed['stem'] ?? null, 'options' => $parsed['options'] ?? null, 'images' => $parsed['images'] ?? [], 'tables' => $parsed['tables'] ?? [], 'is_question_candidate' => (bool) ($parsed['is_question_candidate'] ?? false), 'ai_confidence' => $parsed['ai_confidence'] ?? null, 'status' => 'pending', ]); $processed++; } catch (\Throwable $e) { $failed++; Log::warning('Markdown batch item failed', [ 'import_id' => $this->markdownImportId, 'candidate_id' => $record->id, 'sequence' => $record->sequence, 'index' => $record->index, 'error' => $e->getMessage(), ]); } } if ($processed > 0) { DB::table('markdown_imports') ->where('id', $this->markdownImportId) ->update([ 'progress_current' => DB::raw('progress_current + ' . (int) $processed), 'progress_updated_at' => now(), 'progress_stage' => MarkdownImport::STAGE_AI_PARSING, 'progress_message' => 'AI 解析中…', ]); } Log::info('Markdown batch finished', [ 'import_id' => $this->markdownImportId, 'sequence_start' => $this->sequenceStart, 'sequence_end' => $this->sequenceEnd, 'processed' => $processed, 'failed' => $failed, ]); $this->finalizeIfDone(); } private function finalizeIfDone(): void { $import = MarkdownImport::find($this->markdownImportId); if (!$import) { return; } $total = (int) ($import->progress_total ?? 0); $current = (int) ($import->progress_current ?? 0); if ($total <= 0 || $current < $total) { return; } // 只要有一个 batch 到达“完成条件”,就尝试做一次幂等的最终状态更新 $updated = DB::table('markdown_imports') ->where('id', $this->markdownImportId) ->where('status', 'processing') ->update([ 'status' => 'parsed', 'progress_stage' => MarkdownImport::STAGE_PARSED, 'progress_message' => '解析完成,等待人工校对', 'progress_updated_at' => now(), 'processing_finished_at' => now(), ]); if ($updated) { Log::info('Markdown import finalized', [ 'import_id' => $this->markdownImportId, 'progress_total' => $total, 'progress_current' => $current, ]); } } }