Browse Source

feat: 按卷子 ID 数组批量重生成 PDF API

- POST /api/papers/regenerate-batch-by-ids
- 参数 paper_ids 数组,投递到 pdf 队列

Made-with: Cursor
yemeishu 1 week ago
parent
commit
2925b467d9
2 changed files with 79 additions and 0 deletions
  1. 74 0
      app/Http/Controllers/ExamPdfController.php
  2. 5 0
      routes/api.php

+ 74 - 0
app/Http/Controllers/ExamPdfController.php

@@ -1425,4 +1425,78 @@ class ExamPdfController extends Controller
             ], 500);
         }
     }
+
+    /**
+     * 按卷子 ID 数组批量重新生成 PDF,投递到队列异步处理
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function regeneratePdfBatchByIds(Request $request)
+    {
+        $paperIds = $request->input('paper_ids');
+
+        if (empty($paperIds) || ! is_array($paperIds)) {
+            return response()->json([
+                'success' => false,
+                'message' => '参数 paper_ids 必填,且为数组(如 ["paper_123","paper_456"])',
+            ], 400);
+        }
+
+        $paperIds = array_values(array_unique(array_filter(array_map('trim', $paperIds))));
+        $validPattern = '/^paper_\d+$/';
+        $invalid = array_filter($paperIds, fn ($id) => ! preg_match($validPattern, $id));
+        if (! empty($invalid)) {
+            return response()->json([
+                'success' => false,
+                'message' => 'paper_ids 格式错误,需为 paper_ 开头的数字',
+                'invalid' => array_values($invalid),
+            ], 400);
+        }
+
+        $includeKpExplain = $request->has('include_kp_explain')
+            ? filter_var($request->input('include_kp_explain'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
+            : null;
+
+        Log::info('RegeneratePdfBatchByIds: 投递队列', ['paper_ids' => $paperIds, 'count' => count($paperIds)]);
+
+        try {
+            $papers = Paper::with('questions')
+                ->whereIn('paper_id', $paperIds)
+                ->get()
+                ->keyBy('paper_id');
+
+            $queued = [];
+            $skipped = 0;
+            foreach ($paperIds as $paperId) {
+                $paper = $papers->get($paperId);
+                if (! $paper || $paper->questions->isEmpty()) {
+                    $skipped++;
+
+                    continue;
+                }
+                RegeneratePdfJob::dispatch($paperId, $includeKpExplain);
+                $queued[] = $paperId;
+            }
+
+            Log::info('RegeneratePdfBatchByIds: 已投递', [
+                'queued' => count($queued),
+                'skipped' => $skipped,
+            ]);
+
+            return response()->json([
+                'success' => true,
+                'message' => '已投递到 pdf 队列,请确保 queue worker 正在运行',
+                'queued' => count($queued),
+                'skipped' => $skipped,
+                'paper_ids' => $queued,
+            ]);
+        } catch (\Exception $e) {
+            Log::error('RegeneratePdfBatchByIds: 批量异常', ['error' => $e->getMessage()]);
+
+            return response()->json([
+                'success' => false,
+                'message' => '批量投递异常:'.$e->getMessage(),
+            ], 500);
+        }
+    }
 }

+ 5 - 0
routes/api.php

@@ -1177,6 +1177,11 @@ Route::post('/papers/regenerate-batch', [\App\Http\Controllers\ExamPdfController
     ->withoutMiddleware([Authenticate::class, 'auth', 'auth:sanctum', 'auth:api'])
     ->name('api.papers.regenerate-batch');
 
+// 批量重新生成 PDF:按卷子 ID 数组投递队列
+Route::post('/papers/regenerate-batch-by-ids', [\App\Http\Controllers\ExamPdfController::class, 'regeneratePdfBatchByIds'])
+    ->withoutMiddleware([Authenticate::class, 'auth', 'auth:sanctum', 'auth:api'])
+    ->name('api.papers.regenerate-batch-by-ids');
+
 // 重新生成统一 PDF(卷子 + 判卷)
 Route::post('/papers/{paper_id}/regenerate', [\App\Http\Controllers\ExamPdfController::class, 'regeneratePdf'])
     ->withoutMiddleware([Authenticate::class, 'auth', 'auth:sanctum', 'auth:api'])