paperId = request()->query('paperId'); if ($this->paperId) { $this->loadPaperDetail(); } } protected function loadPaperDetail() { if (!$this->paperId) { $this->paperDetail = []; return; } $paper = \App\Models\Paper::with(['questions' => function($query) { $query->orderBy('question_number'); }])->find($this->paperId); if ($paper) { $this->paperDetail = [ 'paper_id' => $paper->paper_id, 'paper_name' => $paper->paper_name, 'question_count' => $paper->questions->count(), 'total_score' => $paper->total_score, 'difficulty_category' => $paper->difficulty_category, 'status' => $paper->status, 'created_at' => $paper->created_at, 'updated_at' => $paper->updated_at, 'questions' => $paper->questions->map(function($question) { // 直接使用paper_questions表中的数据,不依赖外部Question模型 return [ 'id' => $question->id, 'question_id' => $question->question_id, 'question_number' => $question->question_number, 'question_bank_id' => $question->question_bank_id, 'question_type' => $question->question_type, 'score' => $question->score, 'knowledge_point' => $question->knowledge_point, 'difficulty' => $question->difficulty, 'estimated_time' => $question->estimated_time, // 使用question_text字段(如果有的话) 'stem' => $question->question_text ?: '题目详情请查看题库系统', 'answer' => '', 'solution' => '', 'question_code' => 'QB_' . $question->question_bank_id, 'difficulty_label' => $this->getDifficultyLabel($question->difficulty), ]; })->toArray(), ]; } else { $this->paperDetail = []; } // 切换试卷时关闭预览,避免展示旧数据 $this->showPreview = false; } /** * 根据难度值获取难度标签 */ private function getDifficultyLabel(?float $difficulty): string { if ($difficulty === null) { return '未知'; } return match (true) { $difficulty <= 0.4 => '基础', $difficulty <= 0.7 => '中等', default => '拔高', }; } public function startEditExam() { $paper = \App\Models\Paper::find($this->paperId); if ($paper) { $this->editingExamId = $this->paperId; $this->editForm = [ 'paper_name' => $paper->paper_name, 'difficulty_category' => $paper->difficulty_category, 'status' => $paper->status, ]; } } public function saveExamEdit() { try { $paper = \App\Models\Paper::find($this->paperId); if (!$paper) { throw new \Exception('试卷不存在'); } // 验证表单数据 $validated = \Illuminate\Support\Facades\Validator::make($this->editForm, [ 'paper_name' => 'required|string|max:255', 'difficulty_category' => 'required|in:基础,进阶,竞赛', 'status' => 'required|in:draft,completed,graded', ])->validate(); $paper->update($validated); Notification::make() ->title('修改成功') ->body('试卷信息已更新') ->success() ->send(); $this->reset('editingExamId', 'editForm'); $this->loadPaperDetail(); } catch (\Illuminate\Validation\ValidationException $e) { Notification::make() ->title('验证失败') ->body('请检查输入的数据是否正确') ->danger() ->send(); } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error('修改试卷失败', [ 'paper_id' => $this->paperId, 'error' => $e->getMessage() ]); Notification::make() ->title('修改失败') ->body($e->getMessage()) ->danger() ->send(); } } public function cancelEdit() { $this->reset('editingExamId', 'editForm'); } /** * 删除试卷中的题目 */ public function deleteQuestion(int $questionId) { try { \Illuminate\Support\Facades\DB::beginTransaction(); $paperQuestion = \App\Models\PaperQuestion::where('paper_id', $this->paperId) ->where('id', $questionId) ->first(); if (!$paperQuestion) { throw new \Exception('题目不存在'); } $paperQuestion->delete(); // 更新试卷的题目数量 $paper = \App\Models\Paper::find($this->paperId); if ($paper) { $paper->question_count = $paper->questions()->count(); $paper->total_score = $paper->questions()->sum('score'); $paper->save(); } \Illuminate\Support\Facades\DB::commit(); Notification::make() ->title('删除成功') ->body('题目已从试卷中删除') ->success() ->send(); $this->loadPaperDetail(); } catch (\Exception $e) { \Illuminate\Support\Facades\DB::rollBack(); \Illuminate\Support\Facades\Log::error('删除题目失败', [ 'paper_id' => $this->paperId, 'question_id' => $questionId, 'error' => $e->getMessage() ]); Notification::make() ->title('删除失败') ->body($e->getMessage()) ->danger() ->send(); } } /** * 搜索可选题目 * 注意:由于没有questions表,这里返回空数组 * 实际使用时需要连接外部题库API */ public function searchQuestions() { if (!$this->selectedKnowledgePoint && !$this->selectedQuestionType) { $this->availableQuestions = []; return; } try { // TODO: 连接外部题库API获取题目 // 这里暂时返回空数组,实际项目中需要调用题库服务 $this->availableQuestions = []; // 如果需要,可以显示提示信息 Notification::make() ->title('提示') ->body('题库功能需要连接外部API,当前显示模拟数据') ->info() ->send(); } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error('搜索题目失败', ['error' => $e->getMessage()]); $this->availableQuestions = []; } } /** * 添加题目到试卷 * 注意:由于没有questions表,这里暂时禁用了添加功能 */ public function addQuestion(int $questionBankId) { try { // TODO: 连接外部题库API获取题目详情 // 这里暂时返回错误提示 Notification::make() ->title('功能暂未开放') ->body('添加题目功能需要连接外部题库API,当前暂未开放') ->warning() ->send(); } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error('添加题目失败', [ 'paper_id' => $this->paperId, 'question_bank_id' => $questionBankId, 'error' => $e->getMessage() ]); Notification::make() ->title('添加失败') ->body($e->getMessage()) ->danger() ->send(); } } /** * 根据题目确定题型 * 已移除对Question模型的依赖 */ /** * 根据难度计算分数 */ private function calculateScore(float $difficulty): float { return match (true) { $difficulty <= 0.4 => 5.0, $difficulty <= 0.7 => 10.0, default => 15.0, }; } /** * 根据难度计算预计用时(秒) */ private function calculateEstimatedTime(float $difficulty): int { return match (true) { $difficulty <= 0.4 => 120, $difficulty <= 0.7 => 180, default => 300, }; } /** * 预览卷子 * 显示试卷预览,可以直接打印 */ public function previewPaper() { $previewUrl = $this->getPreviewUrl(); $gradingUrl = $this->getGradingUrl(); if (!$previewUrl || !$gradingUrl) { Notification::make() ->title('无法预览试卷') ->body('当前试卷 ID 不存在或尚未加载,无法展示试卷或判卷') ->danger() ->send(); return; } $this->showPreview = true; // 通知前端刷新 iframe,保持与智能出卷页面一致 $this->dispatch('refresh-preview', previewUrl: $previewUrl, gradingUrl: $gradingUrl); Notification::make() ->title('已打开试卷与判卷预览') ->body('预览区域会依次展示试卷正文和判卷页,便于连贯查看') ->success() ->send(); } /** * 打印试卷 */ public function printPaper() { $previewUrl = $this->getPreviewUrl(); $gradingUrl = $this->getGradingUrl(); if (!$previewUrl || !$gradingUrl) { Notification::make() ->title('无法打印试卷或判卷') ->body('当前试卷 ID 不存在或尚未加载,无法启动打印') ->danger() ->send(); return; } $this->showPreview = true; // 使用智能出卷 PDF 预览进行打印,保证样式一致 $this->dispatch('print-paper', url: $previewUrl); $this->dispatch('print-paper', url: $gradingUrl); Notification::make() ->title('打印功能已启动') ->body('已同时打开试卷与判卷的打印窗口,如未弹出请检查浏览器弹窗设置') ->info() ->send(); } private function getPreviewUrl(): ?string { $paperId = $this->paperDetail['paper_id'] ?? $this->paperId; if (empty($paperId)) { return null; } return route('filament.admin.auth.intelligent-exam.pdf', [ 'paper_id' => $paperId, 'answer' => 'false', ]); } private function getGradingUrl(): ?string { $paperId = $this->paperDetail['paper_id'] ?? $this->paperId; if (empty($paperId)) { return null; } return route('filament.admin.auth.intelligent-exam.grading', [ 'paper_id' => $paperId, ]); } /** * 复制试卷配置 */ public function duplicateExam() { $learningService = app(\App\Services\LearningAnalyticsService::class); // 提取试卷配置 $examConfig = [ 'paper_name' => $this->paperDetail['paper_name'] . ' (副本)', 'total_questions' => $this->paperDetail['question_count'], 'difficulty_category' => $this->paperDetail['difficulty_category'] ?? '基础', 'question_type_ratio' => [ '选择题' => 40, '填空题' => 30, '解答题' => 30, ], 'difficulty_ratio' => [ '基础' => 50, '中等' => 35, '拔高' => 15, ], ]; Notification::make() ->title('试卷配置已复制') ->body('请前往智能出卷页面查看并使用该配置') ->success() ->send(); } public function getStatusColor(string $status): string { return match($status) { 'draft' => 'ghost', 'completed' => 'success', 'graded' => 'primary', default => 'ghost', }; } public function getStatusLabel(string $status): string { return match($status) { 'draft' => '草稿', 'completed' => '已完成', 'graded' => '已评分', default => '未知', }; } public function getDifficultyColor(string $difficulty): string { return match($difficulty) { '基础' => 'success', '进阶' => 'warning', '竞赛' => 'error', default => 'ghost', }; } }