| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- <?php
- namespace App\Filament\Pages;
- use App\Filament\Widgets\StudentStatsWidget;
- use App\Models\Student;
- use App\Models\Teacher;
- use BackedEnum;
- use Filament\Actions\Action;
- use Filament\Actions\BulkAction;
- use Filament\Actions\BulkActionGroup;
- use Filament\Actions\CreateAction;
- use Filament\Tables;
- use Filament\Tables\Table;
- use Filament\Pages\Page;
- use Illuminate\Support\Facades\DB;
- use Filament\Tables\Concerns\InteractsWithTable;
- use Filament\Tables\Contracts\HasTable;
- use UnitEnum;
- class StudentManagement extends Page implements HasTable
- {
- use InteractsWithTable;
- protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-academic-cap';
- protected static ?string $navigationLabel = '师生管理';
- protected static string|UnitEnum|null $navigationGroup = '管理';
- protected static ?int $navigationSort = 16;
- protected string $view = 'filament.pages.student-management';
- public ?string $selectedTeacherId = null;
- public ?string $selectedTeacherName = null;
- public bool $isTeacher = false;
- public function mount(): void
- {
- $this->isTeacher = auth()->user()?->isTeacher() ?? false;
- }
- public function getTitle(): string
- {
- return '师生管理';
- }
- public function getBreadcrumb(): string
- {
- return '师生管理';
- }
-
- 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 = $currentUser->teacher?->teacher_id;
- 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', $currentUser->teacher?->teacher_id)
- ->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();
- }
- }
|