|
@@ -3,9 +3,6 @@
|
|
|
namespace App\Livewire\UploadExam;
|
|
namespace App\Livewire\UploadExam;
|
|
|
|
|
|
|
|
use Livewire\Component;
|
|
use Livewire\Component;
|
|
|
-use App\Models\Paper;
|
|
|
|
|
-use App\Models\PaperQuestion;
|
|
|
|
|
-use App\Services\QuestionBankService;
|
|
|
|
|
use App\Services\LearningAnalyticsService;
|
|
use App\Services\LearningAnalyticsService;
|
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Notifications\Notification;
|
|
|
|
|
|
|
@@ -23,108 +20,35 @@ class GradingPanel extends Component
|
|
|
|
|
|
|
|
protected $listeners = [
|
|
protected $listeners = [
|
|
|
'loadPaper' => 'loadPaper',
|
|
'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')]
|
|
#[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->selectedPaperId = $paperId;
|
|
|
$this->teacherId = $teacherId;
|
|
$this->teacherId = $teacherId;
|
|
|
$this->studentId = $studentId;
|
|
$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();
|
|
$this->convertGradingDataToQuestionGrades();
|
|
|
|
|
|
|
|
|
|
+ \Log::info('GradingPanel: 转换后的评分数据', [
|
|
|
|
|
+ 'questionGrades' => $this->questionGrades
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
if (empty($this->questionGrades)) {
|
|
if (empty($this->questionGrades)) {
|
|
|
Notification::make()
|
|
Notification::make()
|
|
|
->title('请至少为一道题目评分')
|
|
->title('请至少为一道题目评分')
|
|
@@ -167,17 +95,19 @@ class GradingPanel extends Component
|
|
|
return;
|
|
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) {
|
|
} catch (\Exception $e) {
|
|
|
|
|
+ \Log::error('GradingPanel: 提交失败', [
|
|
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
|
|
+ 'trace' => $e->getTraceAsString()
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
Notification::make()
|
|
Notification::make()
|
|
|
->title('提交失败')
|
|
->title('提交失败')
|
|
|
->body($e->getMessage())
|
|
->body($e->getMessage())
|
|
@@ -193,16 +123,17 @@ class GradingPanel extends Component
|
|
|
foreach ($this->questions as $index => $question) {
|
|
foreach ($this->questions as $index => $question) {
|
|
|
$grading = $this->gradingData[$index] ?? null;
|
|
$grading = $this->gradingData[$index] ?? null;
|
|
|
|
|
|
|
|
|
|
+ // 检查 grading 数据是否存在且有评分信息
|
|
|
if ($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'];
|
|
$questionId = $question['id'];
|
|
|
|
|
|
|
|
// 处理评分数据...
|
|
// 处理评分数据...
|
|
|
$this->questionGrades[$questionId] = [
|
|
$this->questionGrades[$questionId] = [
|
|
|
- 'is_correct' => $grading['is_correct'],
|
|
|
|
|
- 'score' => $grading['score'],
|
|
|
|
|
|
|
+ 'is_correct' => $grading['is_correct'] ?? null,
|
|
|
|
|
+ 'score' => $grading['score'] ?? null,
|
|
|
'student_answer' => '',
|
|
'student_answer' => '',
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
@@ -211,6 +142,55 @@ class GradingPanel extends Component
|
|
|
|
|
|
|
|
public function render()
|
|
public function render()
|
|
|
{
|
|
{
|
|
|
|
|
+ // 直接复用父页面的逻辑获取题目数据
|
|
|
|
|
+ if (!empty($this->selectedPaperId)) {
|
|
|
|
|
+ $this->questions = $this->loadPaperQuestionsDirectly();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return view('livewire.upload-exam.grading-panel');
|
|
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 [];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|