$this->selectedKpCode, 'difficulty' => $this->selectedDifficulty, 'search' => $this->search, ], fn ($value) => filled($value)); $response = $service->listQuestions($this->currentPage, $this->perPage, $filters); return $response['data'] ?? []; } /** * 计算属性:分页信息 */ #[Computed] public function meta(): array { $service = app(QuestionServiceApi::class); $filters = array_filter([ 'kp_code' => $this->selectedKpCode, 'difficulty' => $this->selectedDifficulty, 'search' => $this->search, ], fn ($value) => filled($value)); $response = $service->listQuestions($this->currentPage, $this->perPage, $filters); return $response['meta'] ?? [ 'page' => 1, 'per_page' => 25, 'total' => 0, 'total_pages' => 0, ]; } /** * 计算属性:统计数据 */ #[Computed] public function statistics(): array { $service = app(QuestionServiceApi::class); return $service->getStatistics(); } /** * 计算属性:知识点选项 */ #[Computed] public function knowledgePointOptions(): array { $service = app(QuestionServiceApi::class); return $service->getKnowledgePointOptions(); } /** * 计算属性:根据知识点获取技能列表 */ #[Computed] public function skillsOptions(): array { if (!$this->generateKpCode) { return []; } $service = app(KnowledgeGraphService::class); return $service->getSkillsByKnowledgePoint($this->generateKpCode); } /** * 计算属性:提示词模板 */ #[Computed] public function promptTemplateData(): array { $service = app(PromptService::class); try { $response = $service->listPrompts(); if (!empty($response)) { return $response; } } catch (\Exception $e) { // 使用默认提示词 } // 返回默认提示词模板 return [[ 'id' => 'default', 'template_name' => 'AI题目生成_增强版', 'template_content' => $service->getDefaultPromptTemplate(), 'version' => 2, 'is_active' => true, 'description' => '增强版AI题目生成模板,支持精确的难度和题型分布控制', 'tags' => 'AI生成,增强版,智能分布' ]]; } /** * 打开生成题目模态框 */ public function openGenerateModal(): void { $this->showGenerateModal = true; } /** * 关闭生成题目模态框 */ public function closeGenerateModal(): void { $this->showGenerateModal = false; $this->reset(['generateKpCode', 'selectedSkills', 'questionCount']); } /** * 打开提示词编辑模态框 */ public function openPromptModal(): void { $templates = $this->promptTemplateData; if (!empty($templates)) { $this->promptTemplate = $templates[0]['template_content'] ?? null; } $this->showPromptModal = true; } /** * 关闭提示词编辑模态框 */ public function closePromptModal(): void { $this->showPromptModal = false; $this->reset('promptTemplate'); } /** * 全选/取消全选技能 */ public function toggleAllSkills(): void { $skills = $this->skillsOptions; if (count($this->selectedSkills) === count($skills)) { $this->selectedSkills = []; } else { $this->selectedSkills = array_column($skills, 'code'); } } /** * 监听知识点选择变化 */ public function updatedGenerateKpCode(): void { // 选择新知识点时重置技能选择 $this->selectedSkills = []; // 重新计算skillsOptions会自动触发(通过#[Computed]) } /** * 监听技能选择变化 */ public function updatedSelectedSkills(): void { // 可选:在这里添加其他逻辑 } /** * 搜索更新处理 */ public function updatedSearch(): void { $this->currentPage = 1; } /** * 知识点筛选更新处理 */ public function updatedSelectedKpCode(): void { $this->currentPage = 1; } /** * 难度筛选更新处理 */ public function updatedSelectedDifficulty(): void { $this->currentPage = 1; } /** * 每页数量更新处理 */ public function updatedPerPage(): void { $this->currentPage = 1; } /** * 刷新数据 */ #[On('refresh-data')] public function refreshData(): void { $this->resetCache(); Notification::make() ->title('数据已刷新') ->success() ->send(); } /** * AI 生成题目 */ #[On('ai-generate')] public function aiGenerate(): void { // 打开生成模态框 $this->openGenerateModal(); } /** * 执行生成题目(异步模式) */ #[On('execute-generate')] public function executeGenerate(): void { if (!$this->generateKpCode) { Notification::make() ->title('请选择知识点') ->danger() ->send(); return; } if (empty($this->selectedSkills)) { Notification::make() ->title('请至少选择一个技能') ->danger() ->send(); return; } try { $service = app(QuestionBankService::class); // 构建回调 URL $callbackUrl = route('api.questions.callback'); $result = $service->generateIntelligentQuestions([ 'kp_code' => $this->generateKpCode, 'skills' => $this->selectedSkills, 'count' => $this->questionCount, 'prompt_template' => $this->promptTemplate ], $callbackUrl); if ($result['success'] ?? false) { // 获取task_id $this->currentTaskId = $result['task_id'] ?? null; // 关闭模态框 $this->showGenerateModal = false; // 显示提示消息 Notification::make() ->title('任务已创建') ->body("任务 ID: {$this->currentTaskId}\n题目生成完成后将自动刷新列表") ->info() ->send(); // 不再轮询,等待回调 } else { $error = $result['message'] ?? '未知错误'; Notification::make() ->title('创建任务失败') ->body($error) ->danger() ->send(); } } catch (\Exception $e) { Notification::make() ->title('生成异常') ->body($e->getMessage()) ->danger() ->send(); } } /** * 轮询任务状态 */ public function pollTaskStatus(): void { if (!$this->currentTaskId) { return; } try { $service = app(QuestionBankService::class); $taskStatus = $service->getTaskStatus($this->currentTaskId); if ($taskStatus) { $this->currentTaskStatus = $taskStatus['status'] ?? 'unknown'; $this->currentTaskProgress = $taskStatus['progress'] ?? 0; $this->currentTaskMessage = $this->getTaskStatusMessage($taskStatus); // 如果任务完成或失败,停止轮询 if (in_array($this->currentTaskStatus, ['completed', 'failed'])) { $this->isGenerating = false; if ($this->currentTaskStatus === 'completed') { $result = $taskStatus['result'] ?? null; $total = $result['total'] ?? $this->questionCount; Notification::make() ->title('生成完成') ->body("已为知识点 {$this->generateKpCode} 成功生成 {$total} 道题目") ->success() ->send(); // 刷新数据 $this->refreshData(); } else { $error = $taskStatus['error_message'] ?? '未知错误'; // 分析错误类型并提供解决建议 $suggestion = $this->getErrorSuggestion($error); Notification::make() ->title('生成失败') ->body($error . ($suggestion ? "\n\n建议:{$suggestion}" : '')) ->danger() ->persistent() // 让通知持续显示,用户需要手动关闭 ->actions([ \Filament\Notifications\Actions\Action::make('retry') ->label('重试') ->color('primary') ->emit('retryGeneration', [$this->generateKpCode, $this->selectedSkills, $this->questionCount]), \Filament\Notifications\Actions\Action::make('dismiss') ->label('关闭') ->color('gray'), ]) ->send(); } // 重置任务状态 $this->currentTaskId = null; $this->currentTaskStatus = null; $this->currentTaskProgress = 0; $this->currentTaskMessage = null; } else { // 继续轮询 $this->dispatch('$refresh'); $this->dispatch('poll-task'); } } } catch (\Exception $e) { $this->isGenerating = false; Notification::make() ->title('查询任务状态失败') ->body($e->getMessage()) ->danger() ->send(); } } /** * 获取任务状态消息 */ private function getTaskStatusMessage(array $taskStatus): string { $status = $taskStatus['status'] ?? 'unknown'; $progress = $taskStatus['progress'] ?? 0; return match ($status) { 'pending' => '任务已创建,等待开始...', 'processing' => "正在生成题目... {$progress}%", 'completed' => '生成完成', 'failed' => '生成失败', default => '未知状态', }; } /** * 取消生成任务 */ #[On('cancel-generate')] public function cancelGenerate(): void { $this->isGenerating = false; $this->currentTaskId = null; $this->currentTaskStatus = null; $this->currentTaskProgress = 0; $this->currentTaskMessage = null; Notification::make() ->title('已取消生成任务') ->warning() ->send(); } /** * 保存提示词 */ #[On('save-prompt')] public function savePrompt(): void { if (!$this->promptTemplate) { Notification::make() ->title('提示词不能为空') ->danger() ->send(); return; } try { $service = app(PromptService::class); $result = $service->savePrompt([ 'template_name' => 'AI题目生成_增强版', 'template_type' => '题目生成', 'template_content' => $this->promptTemplate, 'version' => 2, 'is_active' => true, 'description' => '增强版AI题目生成模板,支持精确的难度和题型分布控制', 'tags' => 'AI生成,增强版,智能分布' ]); if ($result['success'] ?? false) { Notification::make() ->title('提示词保存成功') ->success() ->send(); } else { Notification::make() ->title('保存失败') ->body($result['message'] ?? '未知错误') ->danger() ->send(); } $this->closePromptModal(); } catch (\Exception $e) { Notification::make() ->title('保存异常') ->body($e->getMessage()) ->danger() ->send(); } } /** * 删除题目 */ public function deleteQuestion(string $questionCode): void { try { $service = app(QuestionBankService::class); $result = $service->deleteQuestion($questionCode); if ($result) { // 显示成功消息 Notification::make() ->title('删除成功') ->body("题目 {$questionCode} 已删除") ->success() ->send(); // 延迟1秒后刷新页面,确保用户体验好 $this->dispatch('show-message', [ 'type' => 'success', 'message' => "题目 {$questionCode} 已删除" ]); // 强制刷新页面 $this->dispatch('refresh-page'); } else { Notification::make() ->title('删除失败') ->body("题目 {$questionCode} 不存在或已被删除") ->warning() ->send(); } } catch (\Exception $e) { Notification::make() ->title('删除异常') ->body($e->getMessage()) ->danger() ->send(); } } /** * 智能搜索 */ #[On('smart-search')] public function smartSearch(): void { Notification::make() ->title('智能搜索功能') ->body('请使用搜索框输入关键词') ->info() ->send(); } /** * 跳转到指定页 */ public function gotoPage(int $page): void { $this->currentPage = $page; } /** * 上一页 */ public function previousPage(): void { if ($this->currentPage > 1) { $this->currentPage--; } } /** * 下一页 */ public function nextPage(): void { if ($this->currentPage < ($this->meta['total_pages'] ?? 1)) { $this->currentPage++; } } /** * 获取页码数组(用于分页器) */ public function getPages(): array { $totalPages = $this->meta['total_pages'] ?? 1; $currentPage = $this->currentPage; $pages = []; $start = max(1, $currentPage - 2); $end = min($totalPages, $currentPage + 2); for ($i = $start; $i <= $end; $i++) { $pages[] = $i; } return $pages; } /** * 重置缓存数据 */ public function resetCache(): void { // 重置分页参数 $this->currentPage = 1; $this->search = null; $this->selectedKpCode = null; $selectedDifficulty = null; // 重置生成的题目缓存数据 $this->resetQuestionsCache(); // 强制刷新Computed属性 unset($this->questions); unset($this->meta); } /** * 重置题目缓存 */ private function resetQuestionsCache(): void { // 这里可以根据需要添加具体的缓存清理逻辑 // 例如:清除任何本地存储的缓存、Redis缓存等 // 目前简单重置计算属性即可 } /** * 获取错误解决建议 */ private function getErrorSuggestion(string $error): string { if (str_contains($error, 'peer closed connection') || str_contains($error, 'incomplete chunked read')) { return '网络连接不稳定,系统已自动重试。如果问题持续,请稍后再试或减少生成题目数量。'; } if (str_contains($error, 'Authentication Fails') || str_contains($error, 'invalid api key')) { return 'API密钥认证失败,请检查DeepSeek API密钥配置。'; } if (str_contains($error, 'timeout') || str_contains($error, '超时')) { return '请求超时,建议减少题目数量或稍后再试。'; } if (str_contains($error, 'rate limit') || str_contains($error, 'too many requests')) { return 'API调用频率限制,请稍后再试。'; } if (str_contains($error, 'insufficient quota') || str_contains($error, 'balance')) { return 'API账户余额不足,请充值后重试。'; } return '请检查网络连接或稍后再试,如问题持续请联系技术支持。'; } /** * 重试生成 */ #[On('retryGeneration')] public function retryGeneration(string $kpCode, array $skills, int $count): void { $this->generateKpCode = $kpCode; $this->selectedSkills = $skills; $this->questionCount = min($count, 50); // 重试时限制题目数量 Notification::make() ->title('准备重试') ->body("正在为知识点 {$kpCode} 重新生成 {$this->questionCount} 道题目...") ->info() ->send(); // 延迟2秒后开始重试,避免频率限制 $this->js('setTimeout(() => { $wire.dispatch("execute-generate") }, 2000)'); } /** * 头部操作按钮已在视图中直接添加 */ }