initializeUserRole(); // 如果是老师,自动选择当前老师 if ($this->isTeacher) { $teacherId = $this->getCurrentTeacherId(); if ($teacherId) { $this->teacherId = $teacherId; } } else { // 从请求中获取老师ID $this->teacherId = (string) ($request->input('teacher_id') ?? ''); } // 从请求中获取学生ID $this->studentId = (string) ($request->input('student_id') ?? ''); if ($this->studentId && empty($this->teacherId)) { $student = StudentModel::find($this->studentId); if ($student && $student->teacher_id) { $this->teacherId = (string) $student->teacher_id; } } // 若已通过 URL 传入学生,自动加载仪表盘数据,减少手动刷新 if ($this->studentId && $this->teacherId) { $this->loadDashboardData(); } } #[Computed] public function teachers(): array { try { $query = Teacher::query() ->leftJoin('users as u', 'teachers.teacher_id', '=', 'u.user_id') ->select( 'teachers.teacher_id', 'teachers.name', 'teachers.subject', 'u.username', 'u.email' ); // 如果是老师,只返回自己 if ($this->isTeacher) { $teacherId = $this->getCurrentTeacherId(); if ($teacherId) { $query->where('teachers.teacher_id', $teacherId); } } $teachers = $query->orderBy('teachers.name')->get(); // 检查是否有学生没有对应的老师记录 $teacherIds = $teachers->pluck('teacher_id')->toArray(); $missingTeacherIds = Student::query() ->distinct() ->whereNotIn('teacher_id', $teacherIds) ->pluck('teacher_id') ->toArray(); $teachersArray = $teachers->all(); if (!empty($missingTeacherIds)) { foreach ($missingTeacherIds as $missingId) { $teachersArray[] = (object) [ 'teacher_id' => $missingId, 'name' => '未知老师 (' . $missingId . ')', 'subject' => '未知', 'username' => null, 'email' => null ]; } usort($teachersArray, function($a, $b) { return strcmp($a->name, $b->name); }); } return $teachersArray; } catch (\Exception $e) { Log::error('加载老师列表失败', [ 'error' => $e->getMessage() ]); return []; } } #[Computed] public function students(): array { if (empty($this->teacherId)) { return []; } try { return Student::query() ->leftJoin('users as u', 'students.student_id', '=', 'u.user_id') ->where('students.teacher_id', $this->teacherId) ->select( 'students.student_id', 'students.name', 'students.grade', 'students.class_name', 'u.username', 'u.email' ) ->orderBy('students.grade') ->orderBy('students.class_name') ->orderBy('students.name') ->get() ->all(); } catch (\Exception $e) { Log::error('加载学生列表失败', [ 'teacher_id' => $this->teacherId, 'error' => $e->getMessage() ]); return []; } } /** * 老师改变时重新加载学生列表 */ public function updatedTeacherId(): void { // 清空之前选中的学生ID $this->studentId = ''; } /** * 学生改变时重新加载数据 */ public function updatedStudentId(): void { if (!empty($this->studentId)) { $this->loadDashboardData(); } else { $this->mindmapMasteryData = []; $this->dispatch('mastery-updated', data: []); $this->mistakePanel = []; } } public function loadDashboardData(): void { // 检查是否选择了学生 if (empty($this->studentId)) { $this->errorMessage = '请先选择学生'; $this->isLoading = false; return; } $this->isLoading = true; $this->errorMessage = ''; try { $service = app(LearningAnalyticsService::class); // 检查服务健康状态 if (!$service->checkHealth()) { $this->errorMessage = '学习分析系统当前不可用,请稍后重试'; $this->isLoading = false; return; } Log::info('开始加载仪表板数据', ['student_id' => $this->studentId]); // 获取各项数据 $masteryOverview = $service->getStudentMasteryOverview($this->studentId); $skillProficiency = $service->getStudentSkillProficiency($this->studentId); $skillSummary = $service->getStudentSkillSummary($this->studentId); $predictions = $service->getStudentPredictions($this->studentId, 5); $learningPaths = $service->getStudentLearningPaths($this->studentId, 3); $predictionAnalytics = $service->getPredictionAnalytics($this->studentId); $pathAnalytics = $service->getLearningPathAnalytics($this->studentId); $quickPrediction = $service->quickScorePrediction($this->studentId); Log::info('快速预测结果', [ 'student_id' => $this->studentId, 'quick_prediction' => $quickPrediction ]); $recommendations = $service->recommendLearningPaths($this->studentId, 3); // 组合数据 $this->dashboardData = [ 'mastery' => [ 'overview' => $masteryOverview, 'list' => $service->getStudentMasteryList($this->studentId), ], 'skill' => [ 'proficiency' => $skillProficiency, 'summary' => $skillSummary, ], 'prediction' => [ 'list' => $predictions, 'analytics' => $predictionAnalytics, 'quick' => $quickPrediction, ], 'learning_path' => [ 'list' => $learningPaths, 'analytics' => $pathAnalytics, 'recommendations' => $recommendations, ], ]; $this->mindmapMasteryData = $this->buildMasteryMap( $this->dashboardData['mastery']['list'] ?? [] ); $this->dispatch('mastery-updated', data: $this->mindmapMasteryData); Log::info('仪表板数据加载完成', [ 'student_id' => $this->studentId, 'dashboard_data_keys' => array_keys($this->dashboardData) ]); try { $mistakeService = app(MistakeBookService::class); $this->mistakePanel = $mistakeService->getPanelSnapshot($this->studentId, 5); } catch (\Exception $e) { Log::warning('加载错题本面板数据失败', [ 'student_id' => $this->studentId, 'error' => $e->getMessage() ]); $this->mistakePanel = []; } } catch (\Exception $e) { $this->errorMessage = '加载数据时发生错误:' . $e->getMessage(); Log::error('学生仪表板数据加载失败', [ 'student_id' => $this->studentId, 'error' => $e->getMessage() ]); $this->mindmapMasteryData = []; $this->dispatch('mastery-updated', data: []); $this->mistakePanel = []; } finally { $this->isLoading = false; } } public function recalculateMastery(string $kpCode): void { try { $service = app(LearningAnalyticsService::class); $result = $service->recalculateMastery($this->studentId, $kpCode); if ($result) { $this->dispatch('notify', message: '掌握度重新计算完成', type: 'success'); $this->loadDashboardData(); // 刷新数据 } else { $this->dispatch('notify', message: '掌握度重新计算失败', type: 'danger'); } } catch (\Exception $e) { Log::error('重新计算掌握度失败', [ 'student_id' => $this->studentId, 'kp_code' => $kpCode, 'error' => $e->getMessage() ]); $this->dispatch('notify', message: '操作失败:' . $e->getMessage(), type: 'danger'); } } public function batchUpdateSkills(): void { try { $service = app(LearningAnalyticsService::class); $result = $service->batchUpdateSkillProficiency($this->studentId); if ($result) { $this->dispatch('notify', message: '技能熟练度更新完成', type: 'success'); $this->loadDashboardData(); // 刷新数据 } else { $this->dispatch('notify', message: '技能熟练度更新失败', type: 'danger'); } } catch (\Exception $e) { Log::error('批量更新技能熟练度失败', [ 'student_id' => $this->studentId, 'error' => $e->getMessage() ]); $this->dispatch('notify', message: '操作失败:' . $e->getMessage(), type: 'danger'); } } public function generateQuickPrediction(): void { try { $service = app(LearningAnalyticsService::class); $result = $service->quickScorePrediction($this->studentId); if ($result) { $this->dispatch('notify', message: '快速预测生成完成', type: 'success'); $this->loadDashboardData(); // 刷新数据 } else { $this->dispatch('notify', message: '快速预测生成失败', type: 'danger'); } } catch (\Exception $e) { Log::error('生成快速预测失败', [ 'student_id' => $this->studentId, 'error' => $e->getMessage() ]); $this->dispatch('notify', message: '操作失败:' . $e->getMessage(), type: 'danger'); } } protected function buildMasteryMap(array $list): array { $map = []; $items = $list['data'] ?? $list['masteries'] ?? $list; if (!is_array($items)) { return $map; } foreach ($items as $item) { if (!is_array($item)) { continue; } $code = $item['kp_code'] ?? $item['code'] ?? null; if (!$code) { continue; } $map[$code] = $item; } return $map; } public function openMindmapDrawer(string $nodeId): void { $this->mindmapSelectedNode = $nodeId; $this->mindmapNodeDetails = $this->getNodeDetails($nodeId, $this->mindmapMasteryData); $this->mindmapDrawerOpen = true; } public function closeMindmapDrawer(): void { $this->mindmapDrawerOpen = false; $this->mindmapSelectedNode = null; $this->mindmapNodeDetails = []; } /** * 监听TeacherStudentSelector组件的老师变化事件 */ #[On('teacherChanged')] public function onTeacherChanged(string $teacherId): void { $this->teacherId = $teacherId; $this->loadStudentsByTeacher(); $this->studentId = $this->getDefaultStudentId(); } /** * 监听TeacherStudentSelector组件的学生变化事件 */ #[On('studentChanged')] public function onStudentChanged(string $teacherId, string $studentId): void { $this->teacherId = $teacherId; $this->studentId = $studentId; $this->loadDashboardData(); } }