ConvertToPreQuestionsBulkAction.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. namespace App\Filament\Resources\PreQuestionCandidateResource\Actions;
  3. use App\Models\MarkdownImport;
  4. use App\Models\PreQuestion;
  5. use App\Services\Storage\ChunsunUploader;
  6. use Filament\Actions\BulkAction;
  7. use Filament\Facades\Filament;
  8. use Illuminate\Database\Eloquent\Collection;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. class ConvertToPreQuestionsBulkAction extends BulkAction
  12. {
  13. public function getName(): string
  14. {
  15. return 'convert_to_pre_questions';
  16. }
  17. protected function setUp(): void
  18. {
  19. parent::setUp();
  20. $this->label('入库到筛选库');
  21. $this->color('primary');
  22. $this->icon('heroicon-o-arrow-down-tray');
  23. $this->requiresConfirmation();
  24. $this->modalHeading('入库到筛选库');
  25. $this->modalDescription('将选中的候选题转换为正式题目并上传图片到春笋云。此操作不可撤销。');
  26. $this->action(function (Collection $records) {
  27. $this->convertToPreQuestions($records);
  28. });
  29. }
  30. /**
  31. * 转换候选题为正式题目
  32. */
  33. private function convertToPreQuestions(Collection $records): void
  34. {
  35. try {
  36. DB::beginTransaction();
  37. $uploader = app(ChunsunUploader::class);
  38. $processedCount = 0;
  39. $errorCount = 0;
  40. foreach ($records as $record) {
  41. if (!$record->is_question_candidate) {
  42. continue; // 跳过非题目
  43. }
  44. try {
  45. // 处理图片上传
  46. $uploadedImages = [];
  47. if (!empty($record->images)) {
  48. $images = is_string($record->images) ? json_decode($record->images, true) : $record->images;
  49. $uploadedImages = $uploader->uploadImagesFromArray($images);
  50. }
  51. // 创建 pre_question 记录
  52. PreQuestion::create([
  53. 'candidate_id' => $record->id,
  54. 'import_id' => $record->import_id,
  55. 'sequence' => $record->sequence,
  56. 'index' => $record->index,
  57. 'raw_markdown' => $record->raw_markdown,
  58. 'stem' => $record->stem ?: $record->raw_markdown,
  59. 'options' => $record->options,
  60. 'images' => $uploadedImages,
  61. 'tables' => $record->tables,
  62. 'source' => $this->getSourceArray($record->import_id),
  63. ]);
  64. // 更新候选题状态
  65. $record->update([
  66. 'status' => 'accepted',
  67. ]);
  68. $processedCount++;
  69. } catch (\Exception $e) {
  70. Log::error('Failed to convert candidate to pre_question', [
  71. 'candidate_id' => $record->id,
  72. 'error' => $e->getMessage(),
  73. ]);
  74. $errorCount++;
  75. }
  76. }
  77. // 更新 markdown_imports 状态
  78. if ($records->isNotEmpty()) {
  79. $importId = $records->first()->import_id;
  80. $import = MarkdownImport::find($importId);
  81. if ($import) {
  82. $import->update([
  83. 'status' => 'completed',
  84. 'progress_stage' => MarkdownImport::STAGE_COMPLETED,
  85. 'progress_message' => "已入库 {$processedCount} 题",
  86. 'progress_current' => $processedCount,
  87. 'progress_total' => $processedCount,
  88. 'progress_updated_at' => now(),
  89. 'processing_finished_at' => now(),
  90. ]);
  91. }
  92. }
  93. DB::commit();
  94. // 显示结果
  95. if ($processedCount > 0) {
  96. Filament::notify('success', "成功入库 {$processedCount} 个题目");
  97. if ($errorCount > 0) {
  98. Filament::notify('warning', "其中 {$errorCount} 个题目入库失败,请查看日志");
  99. }
  100. } else {
  101. Filament::notify('warning', '没有找到可入库的题目');
  102. }
  103. } catch (\Exception $e) {
  104. DB::rollBack();
  105. Log::error('Batch convert failed', [
  106. 'error' => $e->getMessage(),
  107. ]);
  108. Filament::notify('danger', '入库失败:' . $e->getMessage());
  109. }
  110. }
  111. /**
  112. * 获取来源数组
  113. */
  114. private function getSourceArray(int $importId): array
  115. {
  116. $import = MarkdownImport::find($importId);
  117. if (!$import || !$import->source_name) {
  118. return ['Markdown导入'];
  119. }
  120. return [$import->source_name];
  121. }
  122. }