getKnowledgePointOptions(); } #[Computed(cache: false)] public function skillsOptions(): array { if (!$this->generateKpCode) { return []; } $service = app(KnowledgeGraphService::class); return $service->getSkillsByKnowledgePoint($this->generateKpCode); } #[Computed(cache: false)] public function questionTypeOptions(): array { return [ 'CHOICE' => '单选题', 'MULTIPLE_CHOICE' => '多选题', 'FILL_IN_THE_BLANK' => '填空题', 'CALCULATION' => '计算题', 'WORD_PROBLEM' => '应用题', 'PROOF' => '证明题', ]; } #[Computed(cache: false)] public function promptOptions(): array { $service = app(\App\Services\QuestionServiceApi::class); $prompts = $service->listPrompts(type: 'question_generation', active: 'yes'); // 只展示激活的题目生成模板 $options = []; foreach ($prompts as $prompt) { $label = $prompt['template_name']; if (!empty($prompt['description'])) { $label .= ' - ' . (is_string($prompt['description']) ? $prompt['description'] : json_encode($prompt['description'])); } $options[$prompt['template_name']] = $label; } // 自动选择第一个激活模板 if (!$this->promptTemplate && !empty($options)) { $this->promptTemplate = array_key_first($options); } return $options; } public function updatedGenerateKpCode(): void { // 选择新知识点时清空技能选择 $this->selectedSkills = []; } public function toggleAllSkills(): void { $skillsOptions = $this->skillsOptions; $skillsCount = count($skillsOptions); \Log::info('[ToggleAllSkills] Called', [ 'skillsCount' => $skillsCount, 'selectedSkillsCount' => count($this->selectedSkills), 'skillsOptions' => array_column($skillsOptions, 'code'), 'selectedSkills' => $this->selectedSkills ]); if ($skillsCount === 0) { \Log::info('[ToggleAllSkills] No skills available, returning'); return; } // 获取所有技能的编码列表 $allSkillCodes = array_values(array_unique(array_column($skillsOptions, 'code'))); // 检查当前选中的技能是否等于全部技能 if (count($this->selectedSkills) === $skillsCount && count(array_intersect($this->selectedSkills, $allSkillCodes)) === $skillsCount) { // 如果已全选,则清空 $this->selectedSkills = []; \Log::info('[ToggleAllSkills] Deselecting all skills'); } else { // 否则全选 $this->selectedSkills = $allSkillCodes; \Log::info('[ToggleAllSkills] Selecting all skills', ['newSelection' => $this->selectedSkills]); } } public function executeGenerate() { if ($this->isGenerating) { return; } if (!$this->generateKpCode) { Notification::make()->title('请选择知识点')->danger()->send(); return; } $skillsOptions = $this->skillsOptions; $skillsCount = count($skillsOptions); if ($skillsCount > 0 && empty($this->selectedSkills)) { Notification::make()->title('请选择至少一个技能')->danger()->send(); return; } $this->isGenerating = true; $this->currentTaskId = null; try { $service = app(QuestionBankService::class); $callbackUrl = route('api.questions.callback'); \Log::info("[QuestionGen] 开始异步生成,callback URL: " . $callbackUrl); // 异步请求生成题目 $params = [ 'kp_code' => $this->generateKpCode, 'skills' => $this->selectedSkills, 'count' => $this->questionCount, 'difficulty' => $this->generateDifficulty, 'type' => $this->generateType, 'prompt_template' => $this->promptTemplate ?? null ]; // 添加回调 URL $params['callback_url'] = $callbackUrl; // 获取 base URL(通过公共方法或配置) $baseUrl = config('services.question_bank.base_url', env('QUESTION_BANK_API_BASE', 'http://localhost:5015')); $baseUrl = rtrim($baseUrl, '/'); if (!str_ends_with($baseUrl, '/api')) { $baseUrl .= '/api'; } // 直接发送异步请求,不使用队列 try { // 先立即跳转,避免阻塞 $redirectUrl = "/admin/question-management"; $this->js("window.location.href = '{$redirectUrl}';"); // 使用 stream 方式快速发送请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $baseUrl . '/ai/generate-intelligent-questions'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Accept: application/json' ]); curl_setopt($ch, CURLOPT_TIMEOUT, 1); // 1秒超时,只确保请求发出 curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); // 异步执行,不等待响应 curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); \Log::info("[QuestionGen] 异步请求已发送", [ 'http_code' => $httpCode ]); return; // 立即返回 } catch (\Exception $e) { $this->isGenerating = false; \Log::error("[QuestionGen] 发送异步请求失败", [ 'error' => $e->getMessage() ]); Notification::make() ->title('❌ 请求发送失败') ->body('请检查网络连接并重试') ->danger() ->send(); } } catch (\Illuminate\Http\Client\ConnectionException $e) { $this->isGenerating = false; \Log::error("[QuestionGen] 连接异常: " . $e->getMessage()); Notification::make() ->title('连接AI服务失败') ->body('请检查AI服务是否正常运行') ->danger() ->send(); } catch (\Exception $e) { $this->isGenerating = false; \Log::error("[QuestionGen] 生成异常: " . $e->getMessage()); Notification::make() ->title('请求异常') ->body($e->getMessage()) ->danger() ->send(); } } public function forceCloseStatusBar(string $taskId): void { \Log::info("[QuestionGen] 强制关闭状态栏: {$taskId}"); $this->isGenerating = false; $this->currentTaskId = null; Notification::make() ->title('⚠️ 任务超时') ->body('生成任务可能已完成,请刷新页面查看') ->warning() ->persistent() ->send(); } }