| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <?php
- namespace App\Http\Controllers\Api;
- use App\Http\Controllers\Controller;
- use App\Services\ExamPdfExportService;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Validator;
- class QuestionPdfController extends Controller
- {
- protected ExamPdfExportService $pdfService;
- public function __construct(ExamPdfExportService $pdfService)
- {
- $this->pdfService = $pdfService;
- }
- /**
- * Generate PDF for specified questions
- *
- * POST /api/questions/pdf
- *
- * Request body:
- * {
- * "question_ids": [19903, 17766, ...],
- * "student_id": "123456",
- * "student_name": "张三", // optional
- * "student_grade": "初二", // optional
- * "teacher_name": "李老师", // optional
- * "paper_name": "专项练习", // optional
- * "include_grading": false // optional, whether to generate grading PDF
- * }
- */
- public function generate(Request $request)
- {
- $validator = Validator::make($request->all(), [
- 'question_ids' => 'required|array|min:1|max:100',
- 'question_ids.*' => 'required|integer',
- 'student_id' => 'required|string',
- 'student_name' => 'nullable|string|max:50',
- 'student_grade' => 'nullable|string|max:20',
- 'teacher_name' => 'nullable|string|max:50',
- 'paper_name' => 'nullable|string|max:100',
- 'include_grading' => 'nullable|boolean',
- ]);
- if ($validator->fails()) {
- return response()->json([
- 'success' => false,
- 'message' => '参数验证失败',
- 'errors' => $validator->errors(),
- ], 422);
- }
- $questionIds = $request->input('question_ids');
- $studentId = $request->input('student_id');
- $studentName = $request->input('student_name', '');
- $studentGrade = $request->input('student_grade', '');
- $teacherName = $request->input('teacher_name', '');
- $paperName = $request->input('paper_name', '专项练习');
- $includeGrading = $request->input('include_grading', false);
- Log::info('生成指定题目PDF', [
- 'question_ids' => $questionIds,
- 'student_id' => $studentId,
- 'count' => count($questionIds),
- ]);
- try {
- // 1. Fetch questions from database
- $questions = DB::connection('remote_mysql')
- ->table('questions')
- ->whereIn('id', $questionIds)
- ->get();
- if ($questions->isEmpty()) {
- return response()->json([
- 'success' => false,
- 'message' => '未找到指定的题目',
- ], 404);
- }
- // 2. Group questions by type
- $groupedQuestions = $this->groupQuestionsByType($questions, $questionIds);
- // 3. Build virtual paper structure
- $paper = $this->buildVirtualPaper($paperName, $studentId, $groupedQuestions);
- // 4. Generate PDF
- $result = $this->pdfService->generateByQuestions(
- $paper,
- $groupedQuestions,
- [
- 'name' => $studentName,
- 'grade' => $studentGrade,
- ],
- [
- 'name' => $teacherName,
- ],
- $includeGrading
- );
- Log::info('指定题目PDF生成成功', [
- 'student_id' => $studentId,
- 'question_count' => count($questionIds),
- 'pdf_url' => $result['pdf_url'] ?? null,
- ]);
- return response()->json([
- 'success' => true,
- 'message' => 'PDF生成成功',
- 'data' => $result,
- ]);
- } catch (\Exception $e) {
- Log::error('生成指定题目PDF失败', [
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString(),
- ]);
- return response()->json([
- 'success' => false,
- 'message' => '生成PDF失败: ' . $e->getMessage(),
- ], 500);
- }
- }
- /**
- * Group questions by type and maintain order
- */
- private function groupQuestionsByType($questions, array $originalOrder): array
- {
- // Create a map for quick lookup and preserve original order
- $questionMap = [];
- foreach ($questions as $q) {
- $questionMap[$q->id] = $q;
- }
- $grouped = [
- 'choice' => [],
- 'fill' => [],
- 'answer' => [],
- ];
- $questionNumber = 1;
- // Process in original order
- foreach ($originalOrder as $id) {
- if (!isset($questionMap[$id])) {
- continue;
- }
- $q = $questionMap[$id];
- $type = $this->normalizeQuestionType($q->question_type);
- // Build question object for template
- $questionObj = (object) [
- 'id' => $q->id,
- 'question_number' => $questionNumber++,
- 'content' => $q->stem,
- 'options' => is_string($q->options) ? json_decode($q->options, true) : ($q->options ?? []),
- 'answer' => $q->answer,
- 'solution' => $q->solution,
- 'score' => $this->getDefaultScore($type),
- 'difficulty' => $q->difficulty,
- 'kp_code' => $q->kp_code,
- ];
- $grouped[$type][] = $questionObj;
- }
- return $grouped;
- }
- /**
- * Normalize question type to standard format
- */
- private function normalizeQuestionType(?string $type): string
- {
- if (!$type) {
- return 'answer';
- }
- $type = strtolower(trim($type));
- $typeMap = [
- 'choice' => 'choice',
- '选择题' => 'choice',
- 'single_choice' => 'choice',
- 'multiple_choice' => 'choice',
- 'fill' => 'fill',
- '填空题' => 'fill',
- 'blank' => 'fill',
- 'answer' => 'answer',
- '解答题' => 'answer',
- 'subjective' => 'answer',
- 'calculation' => 'answer',
- 'proof' => 'answer',
- ];
- return $typeMap[$type] ?? 'answer';
- }
- /**
- * Get default score by question type
- */
- private function getDefaultScore(string $type): int
- {
- return match ($type) {
- 'choice' => 5,
- 'fill' => 5,
- 'answer' => 10,
- default => 5,
- };
- }
- /**
- * Build virtual paper structure
- */
- private function buildVirtualPaper(string $paperName, string $studentId, array $groupedQuestions): object
- {
- $totalScore = 0;
- $totalQuestions = 0;
- foreach ($groupedQuestions as $type => $questions) {
- foreach ($questions as $q) {
- $totalScore += $q->score;
- $totalQuestions++;
- }
- }
- // Generate unique paper ID
- $paperId = 'custom_' . $studentId . '_' . time() . '_' . uniqid();
- return (object) [
- 'paper_id' => $paperId,
- 'paper_name' => $paperName,
- 'total_score' => $totalScore,
- 'total_questions' => $totalQuestions,
- 'created_at' => now()->toDateTimeString(),
- ];
- }
- }
|