فهرست منبع

修改 api 路径的问题

yemeishu 3 هفته پیش
والد
کامیت
86bb64dbe3

+ 12 - 38
app/Filament/Pages/ExamAnalysis.php

@@ -169,46 +169,20 @@ class ExamAnalysis extends Page
             }
 
             if ($paperId) {
-                // 从 paper_analysis_results 表读取分析结果
-                $paperAnalysis = \DB::table('paper_analysis_results')
-                    ->where('paper_id', $paperId)
-                    ->first();
-
-                if ($paperAnalysis && !empty($paperAnalysis->analysis_data)) {
-                    $this->paperAnalysisData = json_decode($paperAnalysis->analysis_data, true);
-
-                    \Log::info('本次试卷分析结果已从数据库加载', [
-                        'paper_id' => $paperId,
-                        'student_id' => $studentId,
-                        'data_keys' => array_keys($this->paperAnalysisData ?? [])
-                    ]);
-                } else {
-                    // 如果数据库中没有分析结果,回退到API调用(临时解决方案)
-                    \Log::info('数据库中未找到分析结果,回退到API调用', [
-                        'paper_id' => $paperId,
-                        'student_id' => $studentId
-                    ]);
-                    $this->loadLearningAnalysisFromAPI($studentId, $paperId);
-                    return;
-                }
-            }
-
-            // 2. 尝试从知识点记录表获取整体掌握度数据
-            $knowledgePointRecords = \DB::table('knowledge_point_records')
-                ->where('student_id', $studentId)
-                ->get();
-
-            // 处理知识点掌握度数据
-            if ($knowledgePointRecords->count() > 0) {
-                // 如果找到了知识点记录数据,使用它
-                $this->processKnowledgePointRecords($knowledgePointRecords);
-            } else {
-                // 如果没有找到知识点记录,回退到API调用
-                \Log::info('知识点记录表为空,回退到API调用', [
+                // 直接从API调用获取分析结果,不查询本地数据库
+                \Log::info('跳过本地数据库查询,直接从API加载分析结果', [
+                    'paper_id' => $paperId,
                     'student_id' => $studentId
                 ]);
-                $this->loadLearningAnalysisFromAPI($studentId, $paperId ?? null);
+                $this->loadLearningAnalysisFromAPI($studentId, $paperId);
+                return;
             }
+
+            // 2. 直接从API获取整体掌握度数据,不查询本地数据库
+            \Log::info('跳过知识点记录表查询,直接从API获取掌握度数据', [
+                'student_id' => $studentId
+            ]);
+            $this->loadLearningAnalysisFromAPI($studentId, $paperId ?? null);
         } catch (\Exception $e) {
             \Log::warning('加载分析数据失败,回退到API调用', [
                 'identifier' => $identifier,
@@ -776,7 +750,7 @@ class ExamAnalysis extends Page
                     'reference_answer' => $detail['answer'] ?? '',
                     'score_total' => $pq->score ?? 5,
                     'score_obtained' => $pq->score_obtained ?? 0,
-                    'student_answer' => $pq->student_answer ?? '未作答',
+                    'student_answer' => '老师已评分', // 隐藏学生答案,显示老师评分状态
                     'is_correct' => $pq->is_correct ?? false,
                     'kp_code' => $kpCode,
                     'ai_analysis' => $aiAnalysis,

+ 77 - 10
app/Filament/Pages/UploadExamPaper.php

@@ -497,6 +497,48 @@ class UploadExamPaper extends Page
         $this->questionGrades = [];
     }
 
+    /**
+     * 处理评分完成事件
+     */
+    #[On('gradingComplete')]
+    public function handleGradingComplete(): void
+    {
+        // 提交完成后跳转到详情页
+        if ($this->selectedPaperId && $this->studentId) {
+            $url = $this->getViewRecordUrl('graded_paper', $this->selectedPaperId, '', $this->studentId);
+            $this->redirect($url, navigate: true);
+        }
+    }
+
+    /**
+     * 处理来自子组件的评分提交事件
+     */
+    #[On('submitManualGrading')]
+    public function handleSubmitFromParent(array $questionGrades, array $gradingData, array $questions): void
+    {
+        // 从子组件接收数据
+        $this->questionGrades = $questionGrades;
+        $this->gradingData = $gradingData;
+        $this->questions = $questions;
+
+        \Log::info('UploadExamPaper: 接收到子组件提交的评分数据', [
+            'questionGrades_count' => count($questionGrades),
+            'questions_count' => count($questions)
+        ]);
+
+        // 调用原有的提交方法
+        $this->submitManualGrading();
+
+        // 通知用户提交成功
+        Notification::make()
+            ->title('评分提交成功')
+            ->success()
+            ->send();
+
+        // 触发事件处理跳转
+        $this->dispatch('gradingComplete');
+    }
+
     public function submitUpload(): void
     {
         if (!$this->teacherId) {
@@ -736,6 +778,13 @@ class UploadExamPaper extends Page
 
             // 步骤0: 保存学生答案到本地数据库 (重要:确保数据持久化)
             foreach ($this->questionGrades as $questionId => $grade) {
+                // 从数据库获取当前题目的记录(包含满分)
+                $paperQuestion = \App\Models\PaperQuestion::where('id', $questionId)->first();
+                if (!$paperQuestion) {
+                    \Log::warning('未找到题目记录', ['question_id' => $questionId]);
+                    continue;
+                }
+
                 // 确保 is_correct 是布尔值(转换字符串 'true'/'false' 为布尔值)
                 $isCorrect = $grade['is_correct'];
                 if ($isCorrect === 'true' || $isCorrect === true) {
@@ -751,13 +800,28 @@ class UploadExamPaper extends Page
                 }
 
                 // **关键修复**:确保 is_correct 和 score 的一致性
-                // 如果分数为满分或大于0,视为正确
-                if ($score > 0) {
-                    $isCorrect = true;
-                } elseif ($score === 0) {
-                    $isCorrect = false;
+                // score 优先级高于 is_correct,根据得分比例动态计算
+                $maxScore = $paperQuestion->score ?? 0;
+                if ($maxScore > 0) {
+                    $scoreRatio = $score / $maxScore;
+                    // 只有达到满分才算完全正确
+                    if ($scoreRatio >= 1.0) {
+                        $isCorrect = true;
+                    } elseif ($scoreRatio > 0) {
+                        $isCorrect = false; // 部分得分不算完全正确
+                    } else {
+                        $isCorrect = false;
+                    }
                 }
 
+                \Log::info('保存评分数据', [
+                    'question_id' => $questionId,
+                    'max_score' => $maxScore,
+                    'score_obtained' => $score,
+                    'is_correct' => $isCorrect,
+                    'score_ratio' => $maxScore > 0 ? ($score / $maxScore) : 0
+                ]);
+
                 \App\Models\PaperQuestion::where('id', $questionId)->update([
                     'student_answer' => $grade['student_answer'] ?? '',
                     'is_correct' => $isCorrect,
@@ -930,21 +994,22 @@ class UploadExamPaper extends Page
 
             // 只有当 grading 不为空且有评分数据时才添加
             if ($grading && (
-                $grading['is_correct'] !== null ||
-                ($grading['score'] ?? null) !== null
+                (isset($grading['is_correct']) && $grading['is_correct'] !== null) ||
+                (isset($grading['score']) && $grading['score'] !== null)
             )) {
                 $questionId = $question['id'];
 
                 // 处理 is_correct 值(字符串 'true'/'false' 或布尔值)
-                $isCorrect = $grading['is_correct'];
+                $isCorrect = $grading['is_correct'] ?? null;
                 if ($isCorrect === 'true') {
                     $isCorrect = true;
                 } elseif ($isCorrect === 'false') {
                     $isCorrect = false;
                 }
+                // 如果 is_correct 为 null,保持为 null(不要转换为布尔值)
 
                 // 处理 score 值
-                $score = $grading['score'];
+                $score = $grading['score'] ?? null;
                 if ($score !== null && $score !== '') {
                     $score = is_numeric($score) ? (float)$score : null;
                 }
@@ -960,7 +1025,9 @@ class UploadExamPaper extends Page
                 } else {
                     // 填空/解答题:只有 score,需要自动计算 is_correct
                     if ($score !== null) {
-                        $isCorrect = ($score >= ($question['score'] ?? 0)); // 得分>=满分视为正确
+                        // 动态计算:得分等于满分才算正确
+                        $maxScore = $question['score'] ?? 0;
+                        $isCorrect = ($score >= $maxScore && $maxScore > 0);
                     }
                 }
 

+ 88 - 108
app/Livewire/UploadExam/GradingPanel.php

@@ -3,9 +3,6 @@
 namespace App\Livewire\UploadExam;
 
 use Livewire\Component;
-use App\Models\Paper;
-use App\Models\PaperQuestion;
-use App\Services\QuestionBankService;
 use App\Services\LearningAnalyticsService;
 use Filament\Notifications\Notification;
 
@@ -23,108 +20,35 @@ class GradingPanel extends Component
 
     protected $listeners = [
         'loadPaper' => 'loadPaper',
+        'submitManualGrading' => 'handleSubmitFromParent',
     ];
 
+    // 接收从父组件传递的参数
+    public function mount(
+        ?string $teacherId = null,
+        ?string $studentId = null,
+        ?string $selectedPaperId = null,
+        array $questions = []
+    ): void {
+        $this->teacherId = $teacherId;
+        $this->studentId = $studentId;
+        $this->selectedPaperId = $selectedPaperId;
+        $this->questions = $questions;
+    }
+
     #[On('loadPaper')]
-    public function loadPaper(string $paperId, string $teacherId, string $studentId)
+    public function loadPaper(string $paperId, string $teacherId, string $studentId): void
     {
         $this->selectedPaperId = $paperId;
         $this->teacherId = $teacherId;
         $this->studentId = $studentId;
-
-        $this->loadPaperQuestions();
     }
 
-    public function loadPaperQuestions()
+    public function updatedSelectedPaperId($value): void
     {
-        try {
-            $paper = Paper::find($this->selectedPaperId);
-
-            if (!$paper) {
-                throw new \Exception('未找到试卷');
-            }
-
-            // 设置试卷信息
-            $this->paperName = $paper->paper_name;
-            $this->paperClass = $paper->difficulty_category ?? '未设置';
-            $this->paperStudent = $paper->student_id;
-            $this->paperDate = $paper->created_at->format('Y-m-d H:i');
-
-            // 加载题目
-            $paperWithQuestions = Paper::with(['questions' => function($query) {
-                $query->orderBy('question_number');
-            }])->where('paper_id', $this->selectedPaperId)->first();
-
-            $questions = $paperWithQuestions ? $paperWithQuestions->questions : collect([]);
-
-            // 如果没有正确答案,先尝试从题库API获取
-            $apiDetailsMap = new \Illuminate\Support\Collection();
-            if (!$questions->isEmpty()) {
-                $questionBankIds = $questions->where('question_bank_id', '!=', null)->pluck('question_bank_id')->unique()->toArray();
-                if (!empty($questionBankIds)) {
-                    try {
-                        $questionBankService = app(QuestionBankService::class);
-                        $apiResponse = $questionBankService->getQuestionsByIds($questionBankIds);
-
-                        if (!empty($apiResponse['data'])) {
-                            foreach ($apiResponse['data'] as $detail) {
-                                $apiDetailsMap->put($detail['id'], $detail);
-                            }
-                        }
-                    } catch (\Exception $e) {
-                        \Log::warning('获取题库详情失败', ['error' => $e->getMessage()]);
-                    }
-                }
-            }
-
-            if ($questions->isEmpty()) {
-                $this->questions = [
-                    [
-                        'id' => 'no_questions',
-                        'question_number' => 1,
-                        'question_type' => 'info',
-                        'content' => '该试卷暂无题目数据',
-                        'answer' => '',
-                        'score' => 0,
-                        'is_empty' => true
-                    ]
-                ];
-            } else {
-                $this->questions = $questions->map(function($question, $index) use ($apiDetailsMap) {
-                    // 从 API 获取正确答案(优先使用 API 数据)
-                    $correctAnswer = $question->correct_answer;
-                    if (empty($correctAnswer) && $question->question_bank_id && $apiDetailsMap->has($question->question_bank_id)) {
-                        $detail = $apiDetailsMap->get($question->question_bank_id);
-                        $correctAnswer = $detail['answer'] ?? $detail['correct_answer'] ?? '';
-                    }
-
-                    return [
-                        'id' => $question->id,
-                        'question_number' => $question->question_number,
-                        'question_type' => $question->question_type,
-                        'question_text' => $question->question_text,
-                        'content' => $question->question_text,
-                        'options' => json_decode($question->options, true) ?: [],
-                        'answer' => $correctAnswer,
-                        'correct_answer' => $correctAnswer,
-                        'student_answer' => '',
-                        'score' => $question->score,
-                        'max_score' => $question->score,
-                        'question_bank_id' => $question->question_bank_id,
-                        'is_empty' => false
-                    ];
-                })->toArray();
-            }
-
-            // 初始化评分数据
-            $this->gradingData = array_fill(0, count($this->questions), ['score' => null, 'is_correct' => null]);
-
-        } catch (\Exception $e) {
-            Notification::make()
-                ->title('加载失败')
-                ->body($e->getMessage())
-                ->danger()
-                ->send();
+        if (!empty($value)) {
+            // 清空评分数据
+            $this->gradingData = [];
         }
     }
 
@@ -159,6 +83,10 @@ class GradingPanel extends Component
             // 数据验证和处理
             $this->convertGradingDataToQuestionGrades();
 
+            \Log::info('GradingPanel: 转换后的评分数据', [
+                'questionGrades' => $this->questionGrades
+            ]);
+
             if (empty($this->questionGrades)) {
                 Notification::make()
                     ->title('请至少为一道题目评分')
@@ -167,17 +95,19 @@ class GradingPanel extends Component
                 return;
             }
 
-            // 提交评分逻辑...
-            // 这里省略具体实现,因为原来的代码很长
-
-            Notification::make()
-                ->title('评分提交成功')
-                ->success()
-                ->send();
-
-            $this->dispatch('gradingComplete');
+            // dispatch 事件让父页面处理提交
+            $this->dispatch('submitManualGrading',
+                questionGrades: $this->questionGrades,
+                gradingData: $this->gradingData,
+                questions: $this->questions
+            );
 
         } catch (\Exception $e) {
+            \Log::error('GradingPanel: 提交失败', [
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+
             Notification::make()
                 ->title('提交失败')
                 ->body($e->getMessage())
@@ -193,16 +123,17 @@ class GradingPanel extends Component
         foreach ($this->questions as $index => $question) {
             $grading = $this->gradingData[$index] ?? null;
 
+            // 检查 grading 数据是否存在且有评分信息
             if ($grading && (
-                $grading['is_correct'] !== null ||
-                ($grading['score'] ?? null) !== null
+                (isset($grading['is_correct']) && $grading['is_correct'] !== null) ||
+                (isset($grading['score']) && $grading['score'] !== null)
             )) {
                 $questionId = $question['id'];
 
                 // 处理评分数据...
                 $this->questionGrades[$questionId] = [
-                    'is_correct' => $grading['is_correct'],
-                    'score' => $grading['score'],
+                    'is_correct' => $grading['is_correct'] ?? null,
+                    'score' => $grading['score'] ?? null,
                     'student_answer' => '',
                 ];
             }
@@ -211,6 +142,55 @@ class GradingPanel extends Component
 
     public function render()
     {
+        // 直接复用父页面的逻辑获取题目数据
+        if (!empty($this->selectedPaperId)) {
+            $this->questions = $this->loadPaperQuestionsDirectly();
+        }
+
         return view('livewire.upload-exam.grading-panel');
     }
+
+    // 直接加载题目数据(复用父页面逻辑)
+    private function loadPaperQuestionsDirectly(): array
+    {
+        try {
+            \Log::info('GradingPanel: 开始加载题目', ['paper_id' => $this->selectedPaperId]);
+
+            $paper = \App\Models\Paper::where('paper_id', $this->selectedPaperId)->first();
+            if (!$paper) {
+                \Log::warning('GradingPanel: 试卷不存在', ['paper_id' => $this->selectedPaperId]);
+                return [];
+            }
+
+            $questions = $paper->questions()->orderBy('question_number')->get();
+            \Log::info('GradingPanel: 查询到题目', ['count' => $questions->count()]);
+
+            if ($questions->isEmpty()) {
+                \Log::warning('GradingPanel: 题目为空');
+                // 直接返回空数组,不要返回提示信息
+                return [];
+            }
+
+            // 无论如何都返回题目数据,即使API失败
+            $processedQuestions = $questions->map(function($q) {
+                return [
+                    'id' => $q->id,
+                    'question_number' => $q->question_number,
+                    'question_type' => $q->question_type,
+                    'content' => $q->question_text,
+                    'answer' => '', // 可以为空
+                    'score' => $q->score ?? 5,
+                    'question_bank_id' => $q->question_bank_id,
+                    'is_empty' => false
+                ];
+            })->toArray();
+
+            \Log::info('GradingPanel: 处理后的题目', ['count' => count($processedQuestions)]);
+
+            return $processedQuestions;
+        } catch (\Exception $e) {
+            \Log::error('GradingPanel: 加载失败', ['error' => $e->getMessage()]);
+            return [];
+        }
+    }
 }

+ 40 - 0
app/Services/QuestionBankService.php

@@ -444,6 +444,41 @@ class QuestionBankService
                     'difficulty_category' => $examData['difficulty_category'] ?? '基础',
                 ]);
 
+                // 获取所有题目的正确答案
+                $questionBankIds = array_filter(array_map(function($q) {
+                    return $q['id'] ?? $q['question_id'] ?? null;
+                }, $examData['questions']));
+
+                $correctAnswersMap = [];
+                if (!empty($questionBankIds)) {
+                    Log::info('获取题目正确答案', [
+                        'paper_id' => $paperId,
+                        'question_bank_ids' => $questionBankIds
+                    ]);
+
+                    try {
+                        $response = Http::timeout(10)->post($this->baseUrl . '/questions/batch', [
+                            'ids' => array_values($questionBankIds)
+                        ]);
+
+                        if ($response->successful()) {
+                            $questionsDetails = $response->json('data', []);
+                            foreach ($questionsDetails as $detail) {
+                                $correctAnswersMap[$detail['id']] = $detail['answer'] ?? $detail['correct_answer'] ?? '';
+                            }
+                            Log::info('获取到题目正确答案', [
+                                'paper_id' => $paperId,
+                                'answers_count' => count($correctAnswersMap)
+                            ]);
+                        }
+                    } catch (\Exception $e) {
+                        Log::warning('获取题目正确答案失败', [
+                            'paper_id' => $paperId,
+                            'error' => $e->getMessage()
+                        ]);
+                    }
+                }
+
                 // 准备题目数据
                 $questionInsertData = [];
                 foreach ($examData['questions'] as $index => $question) {
@@ -527,6 +562,10 @@ class QuestionBankService
                         }
                     }
 
+                    // 获取正确答案
+                    $questionBankId = $question['id'] ?? $question['question_id'] ?? null;
+                    $correctAnswer = $correctAnswersMap[$questionBankId] ?? $question['answer'] ?? $question['correct_answer'] ?? '';
+
                     $questionInsertData[] = [
                         'paper_id' => $paperId,
                         'question_id' => $question['question_code'] ?? $question['question_id'] ?? null,
@@ -534,6 +573,7 @@ class QuestionBankService
                         'knowledge_point' => $knowledgePoint,
                         'question_type' => $questionType,
                         'question_text' => $question['stem'] ?? $question['content'] ?? $question['question_text'] ?? '',
+                        'correct_answer' => $correctAnswer,  // 保存正确答案
                         'difficulty' => $difficultyValue,
                         'score' => $question['score'] ?? 5, // 默认5分
                         'estimated_time' => $question['estimated_time'] ?? 300,

+ 28 - 22
resources/views/components/exam-analysis/question-details.blade.php

@@ -37,28 +37,34 @@
                     </div>
                 </div>
                 <div>
-                    <h5 class="text-sm font-medium text-gray-700 mb-2">
-                        @if(isset($question['answer_comparison']))
-                            ✏️ 答案对比
-                        @else
-                            ✏️ 学生答案
-                        @endif
-                    </h5>
+                    <h5 class="text-sm font-medium text-gray-700 mb-2">✏️ 老师评分</h5>
                     <div class="bg-blue-50 rounded p-3">
-                        @if(isset($question['answer_comparison']))
-                            <div class="space-y-2">
-                                <div>
-                                    <p class="text-xs text-gray-500">学生答案:</p>
-                                    <p class="text-sm text-gray-700">{{ $question['answer_comparison']['student'] }}</p>
-                                </div>
-                                <div class="border-t pt-2">
-                                    <p class="text-xs text-gray-500">正确答案(老师校准):</p>
-                                    <p class="text-sm text-green-700 font-medium">{{ $question['answer_comparison']['correct'] }}</p>
-                                </div>
+                        <div class="space-y-2">
+                            <div>
+                                <p class="text-xs text-gray-500">评分结果:</p>
+                                <p class="text-sm text-gray-700">
+                                    得分: <span class="font-semibold text-blue-600">{{ $question['score_obtained'] ?? 0 }}</span>
+                                    / {{ $question['score_total'] ?? 5 }}
+                                    @if(($question['is_correct'] ?? false))
+                                        <span class="ml-2 px-2 py-0.5 bg-green-100 text-green-800 text-xs rounded">✓ 正确</span>
+                                    @else
+                                        <span class="ml-2 px-2 py-0.5 bg-red-100 text-red-800 text-xs rounded">✗ 错误</span>
+                                    @endif
+                                </p>
                             </div>
-                        @else
-                            <p class="text-sm text-gray-600">{{ $question['student_answer'] ?? '未作答' }}</p>
-                        @endif
+                            @if(isset($question['answer_comparison']))
+                            <div class="border-t pt-2">
+                                <p class="text-xs text-gray-500">正确答案(老师校准):</p>
+                                <p class="text-sm text-green-700 font-medium">{{ $question['answer_comparison']['correct'] }}</p>
+                            </div>
+                            @endif
+                            @if(isset($question['reference_answer']))
+                            <div class="border-t pt-2">
+                                <p class="text-xs text-gray-500">参考答案:</p>
+                                <p class="text-sm text-gray-600">{{ $question['reference_answer'] }}</p>
+                            </div>
+                            @endif
+                        </div>
                     </div>
                 </div>
             </div>
@@ -94,8 +100,8 @@
                         </ul>
                     </div>
                     @endif
-                @elseif(!empty($question['student_answer']) && $question['student_answer'] !== '未作答')
-                    {{-- 错误答题的AI反馈 --}}
+                @else
+                    {{-- 错误答题的AI反馈(基于老师评分) --}}
                     @if($question['ai_analysis']['mistake_type'] || $question['ai_analysis']['mistake_category'])
                     <div class="grid grid-cols-2 gap-2 mb-2">
                         @if($question['ai_analysis']['mistake_type'])

+ 6 - 1
resources/views/filament/pages/upload-exam-paper.blade.php

@@ -170,7 +170,12 @@
 
             {{-- 评分面板组件 --}}
             @if(!empty($selectedPaperId))
-                <livewire:upload-exam.grading-panel :teacherId="$teacherId" :studentId="$studentId" />
+                <livewire:upload-exam.grading-panel
+                    :teacherId="$teacherId"
+                    :studentId="$studentId"
+                    :selectedPaperId="$selectedPaperId"
+                    :questions="$this->selectedPaperQuestions"
+                />
             @endif
         </div>
     @endif

+ 132 - 116
resources/views/livewire/upload-exam/grading-panel.blade.php

@@ -2,34 +2,13 @@
     <div class="bg-white shadow-md rounded-lg p-6">
         <h2 class="text-xl font-semibold text-gray-900 mb-6">试卷评分</h2>
 
-        {{-- 试卷基本信息 --}}
-        <div class="bg-gray-50 rounded-lg p-4 mb-6">
-            <div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
-                <div>
-                    <span class="text-gray-600">试卷名称:</span>
-                    <span class="font-medium text-gray-900">{{ $paperName ?? '未知' }}</span>
-                </div>
-                <div>
-                    <span class="text-gray-600">班级:</span>
-                    <span class="font-medium text-gray-900">{{ $paperClass ?? '未知' }}</span>
-                </div>
-                <div>
-                    <span class="text-gray-600">学生:</span>
-                    <span class="font-medium text-gray-900">{{ $paperStudent ?? '未知' }}</span>
-                </div>
-                <div>
-                    <span class="text-gray-600">考试日期:</span>
-                    <span class="font-medium text-gray-900">{{ $paperDate ?? '未知' }}</span>
-                </div>
-            </div>
-        </div>
-
         {{-- 评分列表 --}}
         @if(!empty($questions))
-            <div class="space-y-4">
+            <div class="space-y-6">
                 @foreach($questions as $index => $question)
-                    <div class="border border-gray-200 rounded-lg p-4 hover:border-blue-300 transition-colors">
-                        <div class="flex items-start justify-between mb-3">
+                    <div class="border border-gray-200 rounded-lg p-6 hover:border-blue-300 transition-colors">
+                        {{-- 题目顶部信息 --}}
+                        <div class="flex items-center justify-between mb-4">
                             <div class="flex items-center">
                                 <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 mr-3">
                                     第 {{ $question['question_number'] ?? ($index + 1) }} 题
@@ -41,108 +20,145 @@
                                     ({{ $question['score'] ?? 0 }} 分)
                                 </span>
                             </div>
+
+                            {{-- 当前评分状态(实时更新,放在左上角) --}}
+                            <div class="flex items-center">
+                                @if($question['question_type'] === 'choice')
+                                    <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium
+                                        {{ ($gradingData[$index]['is_correct'] ?? null) === true
+                                            ? 'bg-green-100 text-green-800'
+                                            : (($gradingData[$index]['is_correct'] ?? null) === false
+                                                ? 'bg-red-100 text-red-800'
+                                                : 'bg-gray-100 text-gray-800') }}">
+                                        {{ ($gradingData[$index]['is_correct'] ?? null) === true
+                                            ? '正确'
+                                            : (($gradingData[$index]['is_correct'] ?? null) === false
+                                                ? '错误'
+                                                : '未评分') }}
+                                        @if(($gradingData[$index]['is_correct'] ?? null) !== null)
+                                            ({{ ($gradingData[$index]['is_correct'] ?? false) ? ($question['score'] ?? 0) : 0 }} 分)
+                                        @endif
+                                    </span>
+                                @else
+                                    @php
+                                        $score = floatval($gradingData[$index]['score'] ?? 0);
+                                        $maxScore = floatval($question['score'] ?? 0);
+                                        $isCorrect = $maxScore > 0 ? ($score >= $maxScore && $score > 0) : false;
+                                        $isEmpty = ($gradingData[$index]['score'] ?? null) === null;
+                                    @endphp
+                                    <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium
+                                        {{ $isEmpty
+                                            ? 'bg-gray-100 text-gray-800'
+                                            : ($isCorrect ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800') }}">
+                                        {{ $isEmpty
+                                            ? '未评分'
+                                            : ($isCorrect ? '完全正确' : '部分得分') }}
+                                        @if(!$isEmpty)
+                                           ({{ $score }} / {{ $maxScore }} 分)
+                                        @endif
+                                    </span>
+                                @endif
+                            </div>
                         </div>
 
-                        {{-- 题目内容 --}}
-                        <div class="mb-4">
-                            <p class="text-gray-800">{{ $question['content'] ?? $question['question_text'] ?? '' }}</p>
+                        {{-- 左右布局:题目内容 | 评分操作 --}}
+                        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
+                            {{-- 左侧:题目内容 --}}
+                            <div class="lg:col-span-2">
+                                {{-- 题目内容 --}}
+                                <div class="mb-4">
+                                    <p class="text-gray-800">{{ $question['content'] ?? $question['question_text'] ?? '' }}</p>
 
-                            {{-- 选择题选项 --}}
-                            @if(($question['question_type'] ?? '') === 'choice' && !empty($question['options']))
-                                <div class="mt-3 grid grid-cols-1 md:grid-cols-2 gap-2">
-                                    @foreach($question['options'] as $option)
-                                        <div class="text-sm text-gray-700 bg-gray-50 px-3 py-2 rounded">
-                                            <span class="font-medium">{{ $option['key'] ?? '' }}.</span>
-                                            <span class="ml-1">{{ $option['value'] ?? '' }}</span>
+                                    {{-- 选择题选项 --}}
+                                    @if(($question['question_type'] ?? '') === 'choice' && !empty($question['options']))
+                                        <div class="mt-3 grid grid-cols-1 md:grid-cols-2 gap-2">
+                                            @foreach($question['options'] as $option)
+                                                <div class="text-sm text-gray-700 bg-gray-50 px-3 py-2 rounded">
+                                                    <span class="font-medium">{{ $option['key'] ?? '' }}.</span>
+                                                    <span class="ml-1">{{ $option['value'] ?? '' }}</span>
+                                                </div>
+                                            @endforeach
                                         </div>
-                                    @endforeach
-                                </div>
-                            @endif
-                        </div>
-
-                        {{-- 参考答案 --}}
-                        <div class="mb-4 p-3 bg-green-50 border border-green-200 rounded-md">
-                            <div class="flex items-start">
-                                <svg class="h-5 w-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
-                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
-                                </svg>
-                                <div>
-                                    <p class="text-sm font-medium text-green-800">参考答案</p>
-                                    @if(!empty($question['answer']))
-                                        <p class="text-sm text-green-700 mt-1">{{ $question['answer'] }}</p>
-                                    @else
-                                        <p class="text-sm text-yellow-700 mt-1">⚠️ 未找到参考答案</p>
                                     @endif
                                 </div>
-                            </div>
-                        </div>
 
-                        {{-- 评分操作区 --}}
-                        <div class="border-t pt-4">
-                            @if($question['question_type'] === 'choice')
-                                {{-- 选择题评分 --}}
-                                <div class="flex items-center space-x-4">
-                                    <span class="text-sm font-medium text-gray-700">评分:</span>
-                                    <div class="flex space-x-2">
-                                        <button
-                                            type="button"
-                                            wire:click="setChoiceAnswer({{ $index }}, true)"
-                                            class="inline-flex items-center px-4 py-2 border rounded-md text-sm font-medium transition-colors
-                                                {{ ($gradingData[$index]['is_correct'] ?? null) === true
-                                                    ? 'border-green-500 bg-green-500 text-white'
-                                                    : 'border-gray-300 bg-white text-gray-700 hover:bg-green-50 hover:border-green-300' }}">
-                                            <svg class="h-4 w-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
-                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
-                                            </svg>
-                                            正确 (✓)
-                                        </button>
-                                        <button
-                                            type="button"
-                                            wire:click="setChoiceAnswer({{ $index }}, false)"
-                                            class="inline-flex items-center px-4 py-2 border rounded-md text-sm font-medium transition-colors
-                                                {{ ($gradingData[$index]['is_correct'] ?? null) === false
-                                                    ? 'border-red-500 bg-red-500 text-white'
-                                                    : 'border-gray-300 bg-white text-gray-700 hover:bg-red-50 hover:border-red-300' }}">
-                                            <svg class="h-4 w-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
-                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
-                                            </svg>
-                                            错误 (✗)
-                                        </button>
+                                {{-- 参考答案 --}}
+                                <div class="p-3 bg-green-50 border border-green-200 rounded-md">
+                                    <div class="flex items-start">
+                                        <svg class="h-5 w-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
+                                        </svg>
+                                        <div>
+                                            <p class="text-sm font-medium text-green-800">参考答案</p>
+                                            @if(!empty($question['answer']))
+                                                <p class="text-sm text-green-700 mt-1">{{ $question['answer'] }}</p>
+                                            @else
+                                                <p class="text-sm text-yellow-700 mt-1">⚠️ 未找到参考答案</p>
+                                            @endif
+                                        </div>
                                     </div>
-                                    @if(($gradingData[$index]['is_correct'] ?? null) !== null)
-                                        <span class="text-sm text-gray-600">
-                                            当前:{{ ($gradingData[$index]['is_correct'] ?? false) ? '正确' : '错误' }}
-                                            ({{ ($gradingData[$index]['is_correct'] ?? false) ? ($question['score'] ?? 0) : 0 }} 分)
-                                        </span>
-                                    @endif
                                 </div>
-                            @else
-                                {{-- 填空题/解答题评分 --}}
-                                <div class="flex items-center space-x-4">
-                                    <span class="text-sm font-medium text-gray-700">得分:</span>
-                                    <div class="flex items-center space-x-2">
-                                        <input
-                                            type="number"
-                                            wire:model.live="gradingData.{{ $index }}.score"
-                                            placeholder="0 - {{ $question['score'] ?? 0 }}"
-                                            min="0"
-                                            max="{{ $question['score'] ?? 0 }}"
-                                            step="0.5"
-                                            class="w-24 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm">
-                                        <span class="text-sm text-gray-600">/ {{ $question['score'] ?? 0 }} 分</span>
-                                    </div>
-                                    @if(($gradingData[$index]['score'] ?? null) !== null)
-                                        @php
-                                            $score = $gradingData[$index]['score'] ?? 0;
-                                            $maxScore = $question['score'] ?? 0;
-                                            $isCorrect = $score >= $maxScore;
-                                        @endphp
-                                        <span class="text-sm {{ $isCorrect ? 'text-green-600' : 'text-yellow-600' }}">
-                                            ({{ $isCorrect ? '完全正确' : '部分得分' }}:{{ number_format(($score / $maxScore) * 100, 1) }}%)
-                                        </span>
+                            </div>
+
+                            {{-- 右侧:评分操作区 --}}
+                            <div class="lg:col-span-1">
+                                <div class="border-l pl-6 h-full flex flex-col justify-center">
+                                    @if($question['question_type'] === 'choice')
+                                        {{-- 选择题评分 --}}
+                                        <div class="space-y-4">
+                                            <div class="text-sm font-medium text-gray-700">评分</div>
+                                            <div class="flex flex-col space-y-2">
+                                                <button
+                                                    type="button"
+                                                    wire:click="setChoiceAnswer({{ $index }}, true)"
+                                                    class="inline-flex items-center justify-center px-4 py-3 border rounded-md text-sm font-medium transition-colors
+                                                        {{ ($gradingData[$index]['is_correct'] ?? null) === true
+                                                            ? 'border-green-500 bg-green-500 text-white'
+                                                            : 'border-gray-300 bg-white text-gray-700 hover:bg-green-50 hover:border-green-300' }}">
+                                                    <svg class="h-4 w-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
+                                                    </svg>
+                                                    正确 (✓)
+                                                </button>
+                                                <button
+                                                    type="button"
+                                                    wire:click="setChoiceAnswer({{ $index }}, false)"
+                                                    class="inline-flex items-center justify-center px-4 py-3 border rounded-md text-sm font-medium transition-colors
+                                                        {{ ($gradingData[$index]['is_correct'] ?? null) === false
+                                                            ? 'border-red-500 bg-red-500 text-white'
+                                                            : 'border-gray-300 bg-white text-gray-700 hover:bg-red-50 hover:border-red-300' }}">
+                                                    <svg class="h-4 w-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
+                                                    </svg>
+                                                    错误 (✗)
+                                                </button>
+                                            </div>
+                                        </div>
+                                    @else
+                                        {{-- 填空题/解答题评分 --}}
+                                        <div class="space-y-4">
+                                            <div class="text-sm font-medium text-gray-700">评分</div>
+                                            <div class="space-y-3">
+                                                <div>
+                                                    <label class="block text-xs text-gray-600 mb-1">得分</label>
+                                                    <div class="flex items-center space-x-2">
+                                                        <input
+                                                            type="number"
+                                                            wire:model="gradingData.{{ $index }}.score"
+                                                            wire:change="$refresh"
+                                                            placeholder="0"
+                                                            min="0"
+                                                            max="{{ $question['score'] ?? 0 }}"
+                                                            step="0.5"
+                                                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm">
+                                                    </div>
+                                                    <div class="text-xs text-gray-500 mt-1">满分:{{ $question['score'] ?? 0 }} 分</div>
+                                                </div>
+                                            </div>
+                                        </div>
                                     @endif
                                 </div>
-                            @endif
+                            </div>
                         </div>
                     </div>
                 @endforeach