initializeUserRole(); } protected ?string $subheading = '集中管理老师与学生信息,支持筛选与快速操作'; public function filterByTeacher(?string $teacherId): void { $this->selectedTeacherId = $teacherId; if (! $teacherId) { $this->selectedTeacherName = null; return; } $teacher = Teacher::with('user')->find($teacherId); $this->selectedTeacherName = $teacher?->user?->full_name ?? $teacher?->name ?? '未知老师'; } public function resetTeacherFilter(): void { $this->selectedTeacherId = null; $this->selectedTeacherName = null; } public function table(Table $table): Table { $currentUser = auth()->user(); return $table ->query( Student::query() ->with(['teacher.user', 'user']) ->when($this->selectedTeacherId, fn ($query) => $query->where('teacher_id', $this->selectedTeacherId)) ->when($currentUser?->isTeacher() ?? false, function ($query) use ($currentUser) { // 如果是老师登录,只显示该老师的学生 $teacherId = $this->getCurrentTeacherId(); if ($teacherId) { $query->where('teacher_id', $teacherId); } }) ) ->columns([ Tables\Columns\TextColumn::make('student_id') ->label('学生ID') ->searchable() ->copyable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('name') ->label('姓名') ->searchable() ->sortable() ->weight('bold'), Tables\Columns\TextColumn::make('grade') ->label('年级') ->sortable() ->badge() ->color(fn(string $state): string => match($state) { '一年级' => 'gray', '二年级' => 'gray', '三年级' => 'blue', '四年级' => 'blue', '五年级' => 'green', '六年级' => 'green', default => 'primary', }), Tables\Columns\TextColumn::make('class_name') ->label('班级') ->sortable(), Tables\Columns\TextColumn::make('teacher.user.full_name') ->label('指导老师') ->sortable() ->url(fn($record): string => optional($record->teacher?->user)->email ? "mailto:{$record->teacher?->user?->email}" : '' ) ->openUrlInNewTab() ->visible(fn () => !($currentUser?->isTeacher() ?? false)), // 老师登录时不显示老师列 Tables\Columns\TextColumn::make('user.email') ->label('邮箱') ->copyable() ->toggleable(), Tables\Columns\TextColumn::make('user.login_count') ->label('登录次数') ->sortable() ->alignCenter() ->badge() ->color(fn(?int $state): string => ($state ?? 0) === 0 ? 'danger' : (($state ?? 0) < 5 ? 'warning' : 'success') ), Tables\Columns\TextColumn::make('user.last_login') ->label('最后登录') ->dateTime('Y-m-d H:i') ->sortable() ->description(fn($record): string => $record->user?->last_login ? \Carbon\Carbon::parse($record->user->last_login)->diffForHumans() : '从未登录' ), Tables\Columns\TextColumn::make('created_at') ->label('创建时间') ->dateTime('Y-m-d H:i') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\SelectFilter::make('grade') ->label('年级') ->options(fn() => Student::query() ->orderBy('grade') ->pluck('grade', 'grade') ->filter() ->toArray()), Tables\Filters\SelectFilter::make('class_name') ->label('班级') ->options(fn() => Student::query() ->orderBy('class_name') ->pluck('class_name', 'class_name') ->filter() ->toArray()), Tables\Filters\SelectFilter::make('teacher_id') ->label('指导老师') ->options(fn() => Teacher::query() ->with('user') ->get() ->mapWithKeys(fn (Teacher $teacher) => [ $teacher->teacher_id => $teacher->user->full_name ?? $teacher->name ?? "老师 #{$teacher->teacher_id}", ]) ->toArray()) ->visible(fn () => !($currentUser?->isTeacher() ?? false)), // 老师登录时隐藏 Tables\Filters\Filter::make('has_logged_in') ->label('登录状态') ->query(fn($query) => $query->whereHas('user', fn ($sub) => $sub->whereNotNull('last_login'))), ]) ->actions([ Action::make('view') ->label('查看') ->icon('heroicon-o-eye') ->url(fn($record): string => route('filament.admin.resources.students.view', $record)) ->openUrlInNewTab(), Action::make('edit') ->label('编辑') ->icon('heroicon-o-pencil-square') ->url(fn($record): string => route('filament.admin.resources.students.edit', $record)) ->openUrlInNewTab(), Action::make('reset_password') ->label('重置密码') ->icon('heroicon-o-key') ->color('warning') ->action(function ($record) { $newPassword = 'student123'; $hashedPassword = \Hash::make($newPassword); DB::table('users') ->where('user_id', $record->student_id) ->update(['password_hash' => $hashedPassword]); \Filament\Notifications\Notification::make() ->success() ->title('密码重置成功') ->body("学生 {$record->name} 的密码已重置为: {$newPassword}") ->send(); }) ->requiresConfirmation() ->modalHeading('重置学生密码') ->modalDescription('确定要重置该学生的密码吗?新密码将是: student123') ->modalSubmitActionLabel('确认重置'), ]) ->bulkActions([ BulkActionGroup::make([ BulkAction::make('reset_passwords') ->label('批量重置密码') ->icon('heroicon-o-key') ->color('warning') ->action(function ($records) { $newPassword = 'student123'; $hashedPassword = \Hash::make($newPassword); foreach ($records as $record) { DB::table('users') ->where('user_id', $record->student_id) ->update(['password_hash' => $hashedPassword]); } \Filament\Notifications\Notification::make() ->success() ->title('批量重置密码成功') ->body("已为 {$records->count()} 位学生重置密码为: {$newPassword}") ->send(); }) ->requiresConfirmation() ->modalHeading('批量重置密码') ->modalDescription('确定要重置所选学生的密码吗?新密码将是: student123') ->modalSubmitActionLabel('确认重置'), ]), ]) ->searchPlaceholder('搜索学生姓名、ID或邮箱...') ->emptyStateHeading('暂无学生数据') ->emptyStateDescription('还没有添加任何学生数据。') ->emptyStateActions([ CreateAction::make() ->label('添加新学生') ->url(route('filament.admin.resources.students.create')) ->icon('heroicon-o-plus'), ]) ->paginated([10, 25, 50, 100]) ->poll('60s'); // 每60秒刷新一次 } public function getHeaderWidgets(): array { return [ StudentStatsWidget::class, ]; } public function getTeacherOverviewProperty(): array { $currentUser = auth()->user(); // 如果是老师,只返回自己的信息 if ($currentUser?->isTeacher() ?? false) { $teacher = Teacher::query() ->with([ 'user', 'students' => fn ($query) => $query ->select('student_id', 'name', 'grade', 'class_name', 'teacher_id') ->orderBy('name'), ]) ->where('teacher_id', $this->getCurrentTeacherId()) ->withCount('students') ->withMax('students', 'updated_at') ->first(); if (!$teacher) { return []; } return [[ 'teacher_id' => $teacher->teacher_id, 'teacher_name' => $teacher->user->full_name ?? $teacher->name ?? '未命名老师', 'teacher_email' => $teacher->user->email ?? null, 'students_count' => $teacher->students_count ?? 0, 'latest_student_activity' => $teacher->students_max_updated_at, 'students' => $teacher->students ->sortBy('name') ->take(4) ->map(fn (Student $student) => [ 'student_id' => $student->student_id, 'name' => $student->name, 'grade' => $student->grade, 'class_name' => $student->class_name, ])->values()->toArray(), ]]; } // 如果是管理员,返回所有老师信息 $teachers = Teacher::query() ->with([ 'user', 'students' => fn ($query) => $query ->select('student_id', 'name', 'grade', 'class_name', 'teacher_id') ->orderBy('name'), ]) ->withCount('students') ->withMax('students', 'updated_at') ->orderByDesc('students_count') ->get(); return $teachers->map(function (Teacher $teacher) { return [ 'teacher_id' => $teacher->teacher_id, 'teacher_name' => $teacher->user->full_name ?? $teacher->name ?? '未命名老师', 'teacher_email' => $teacher->user->email ?? null, 'students_count' => $teacher->students_count ?? 0, 'latest_student_activity' => $teacher->students_max_updated_at, 'students' => $teacher->students ->sortBy('name') ->take(4) ->map(fn (Student $student) => [ 'student_id' => $student->student_id, 'name' => $student->name, 'grade' => $student->grade, 'class_name' => $student->class_name, ])->values()->toArray(), ]; })->toArray(); } }