|
@@ -4,6 +4,7 @@ namespace App\Filament\Resources;
|
|
|
|
|
|
|
|
use App\Filament\Resources\StudentResource\Pages;
|
|
use App\Filament\Resources\StudentResource\Pages;
|
|
|
use App\Models\Student;
|
|
use App\Models\Student;
|
|
|
|
|
+use App\Models\Teacher;
|
|
|
use BackedEnum;
|
|
use BackedEnum;
|
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\Select;
|
|
|
use Filament\Forms\Components\Textarea;
|
|
use Filament\Forms\Components\Textarea;
|
|
@@ -12,7 +13,7 @@ use Filament\Resources\Resource;
|
|
|
use Filament\Schemas\Schema;
|
|
use Filament\Schemas\Schema;
|
|
|
use Filament\Tables;
|
|
use Filament\Tables;
|
|
|
use Filament\Tables\Table;
|
|
use Filament\Tables\Table;
|
|
|
-use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
+use Illuminate\Support\Facades\Cache;
|
|
|
|
|
|
|
|
class StudentResource extends Resource
|
|
class StudentResource extends Resource
|
|
|
{
|
|
{
|
|
@@ -24,33 +25,39 @@ class StudentResource extends Resource
|
|
|
|
|
|
|
|
public static function form(Schema $schema): Schema
|
|
public static function form(Schema $schema): Schema
|
|
|
{
|
|
{
|
|
|
- return $schema->components([
|
|
|
|
|
|
|
+ return $schema->schema([
|
|
|
|
|
+ // 学生ID字段在创建时隐藏,编辑时显示但禁用
|
|
|
TextInput::make('student_id')
|
|
TextInput::make('student_id')
|
|
|
->label('学生ID')
|
|
->label('学生ID')
|
|
|
- ->numeric()
|
|
|
|
|
- ->required()
|
|
|
|
|
- ->disabled(fn (?Student $record) => filled($record)),
|
|
|
|
|
|
|
+ ->disabled()
|
|
|
|
|
+ ->hidden(fn (?Student $record) => blank($record))
|
|
|
|
|
+ ->formatStateUsing(fn (?Student $record): string => $record?->student_id ?? ''),
|
|
|
TextInput::make('name')
|
|
TextInput::make('name')
|
|
|
->label('姓名')
|
|
->label('姓名')
|
|
|
->required()
|
|
->required()
|
|
|
- ->maxLength(128),
|
|
|
|
|
|
|
+ ->maxLength(128)
|
|
|
|
|
+ ->placeholder('请输入学生姓名'),
|
|
|
TextInput::make('grade')
|
|
TextInput::make('grade')
|
|
|
->label('年级')
|
|
->label('年级')
|
|
|
->required()
|
|
->required()
|
|
|
- ->maxLength(32),
|
|
|
|
|
|
|
+ ->maxLength(32)
|
|
|
|
|
+ ->placeholder('例如:高一、高二等'),
|
|
|
TextInput::make('class_name')
|
|
TextInput::make('class_name')
|
|
|
->label('班级')
|
|
->label('班级')
|
|
|
- ->required()
|
|
|
|
|
- ->maxLength(64),
|
|
|
|
|
|
|
+ ->helperText('选填项,如不确定可留空')
|
|
|
|
|
+ ->maxLength(64)
|
|
|
|
|
+ ->placeholder('例如:1班、2班等'),
|
|
|
Select::make('teacher_id')
|
|
Select::make('teacher_id')
|
|
|
->label('指导老师')
|
|
->label('指导老师')
|
|
|
->options(fn () => self::teacherOptions())
|
|
->options(fn () => self::teacherOptions())
|
|
|
->searchable()
|
|
->searchable()
|
|
|
->required()
|
|
->required()
|
|
|
- ->preload(),
|
|
|
|
|
|
|
+ ->preload()
|
|
|
|
|
+ ->placeholder('请选择指导老师'),
|
|
|
Textarea::make('remark')
|
|
Textarea::make('remark')
|
|
|
->label('备注')
|
|
->label('备注')
|
|
|
->rows(3)
|
|
->rows(3)
|
|
|
|
|
+ ->placeholder('请输入备注信息(可选)')
|
|
|
->columnSpanFull(),
|
|
->columnSpanFull(),
|
|
|
])->columns(2);
|
|
])->columns(2);
|
|
|
}
|
|
}
|
|
@@ -61,27 +68,53 @@ class StudentResource extends Resource
|
|
|
->columns([
|
|
->columns([
|
|
|
Tables\Columns\TextColumn::make('student_id')
|
|
Tables\Columns\TextColumn::make('student_id')
|
|
|
->label('学生ID')
|
|
->label('学生ID')
|
|
|
|
|
+ ->badge()
|
|
|
|
|
+ ->color('primary')
|
|
|
|
|
+ ->copyable()
|
|
|
|
|
+ ->copyMessage('学生ID已复制')
|
|
|
|
|
+ ->copyMessageDuration(1500)
|
|
|
->sortable()
|
|
->sortable()
|
|
|
->searchable(),
|
|
->searchable(),
|
|
|
Tables\Columns\TextColumn::make('name')
|
|
Tables\Columns\TextColumn::make('name')
|
|
|
->label('姓名')
|
|
->label('姓名')
|
|
|
->weight('bold')
|
|
->weight('bold')
|
|
|
- ->searchable(),
|
|
|
|
|
|
|
+ ->searchable()
|
|
|
|
|
+ ->sortable(),
|
|
|
Tables\Columns\TextColumn::make('grade')
|
|
Tables\Columns\TextColumn::make('grade')
|
|
|
->label('年级')
|
|
->label('年级')
|
|
|
|
|
+ ->badge()
|
|
|
|
|
+ ->color('success')
|
|
|
->sortable(),
|
|
->sortable(),
|
|
|
Tables\Columns\TextColumn::make('class_name')
|
|
Tables\Columns\TextColumn::make('class_name')
|
|
|
->label('班级')
|
|
->label('班级')
|
|
|
- ->sortable(),
|
|
|
|
|
|
|
+ ->placeholder('未分配')
|
|
|
|
|
+ ->sortable()
|
|
|
|
|
+ ->formatStateUsing(fn ($state) => $state ?: '未分配'),
|
|
|
|
|
+ Tables\Columns\TextColumn::make('teacher.user.full_name')
|
|
|
|
|
+ ->label('指导老师')
|
|
|
|
|
+ ->default('未分配')
|
|
|
|
|
+ ->sortable()
|
|
|
|
|
+ ->searchable(),
|
|
|
])
|
|
])
|
|
|
->filters([
|
|
->filters([
|
|
|
Tables\Filters\SelectFilter::make('grade')
|
|
Tables\Filters\SelectFilter::make('grade')
|
|
|
->label('年级')
|
|
->label('年级')
|
|
|
- ->options(fn () => self::gradeOptions()),
|
|
|
|
|
|
|
+ ->options(fn () => self::gradeOptions())
|
|
|
|
|
+ ->placeholder('全部年级'),
|
|
|
Tables\Filters\SelectFilter::make('class_name')
|
|
Tables\Filters\SelectFilter::make('class_name')
|
|
|
->label('班级')
|
|
->label('班级')
|
|
|
- ->options(fn () => self::classOptions()),
|
|
|
|
|
- ]);
|
|
|
|
|
|
|
+ ->options(fn () => self::classOptions())
|
|
|
|
|
+ ->placeholder('全部班级'),
|
|
|
|
|
+ Tables\Filters\SelectFilter::make('teacher_id')
|
|
|
|
|
+ ->label('指导老师')
|
|
|
|
|
+ ->options(fn () => self::teacherOptions())
|
|
|
|
|
+ ->placeholder('全部老师'),
|
|
|
|
|
+ ])
|
|
|
|
|
+ ->actions([])
|
|
|
|
|
+ ->bulkActions([])
|
|
|
|
|
+ ->emptyStateHeading('暂无学生记录')
|
|
|
|
|
+ ->emptyStateDescription('开始创建你的第一个学生吧')
|
|
|
|
|
+ ->emptyStateActions([]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static function getPages(): array
|
|
public static function getPages(): array
|
|
@@ -96,28 +129,63 @@ class StudentResource extends Resource
|
|
|
|
|
|
|
|
protected static function teacherOptions(): array
|
|
protected static function teacherOptions(): array
|
|
|
{
|
|
{
|
|
|
- return DB::table('teachers')
|
|
|
|
|
- ->join('users', 'teachers.user_id', '=', 'users.user_id')
|
|
|
|
|
- ->where('users.role', 'teacher')
|
|
|
|
|
- ->pluck('users.full_name', 'teachers.teacher_id')
|
|
|
|
|
- ->toArray();
|
|
|
|
|
|
|
+ // 使用缓存优化性能,缓存1小时
|
|
|
|
|
+ return cache()->remember('teacher_options', 3600, function () {
|
|
|
|
|
+ return Teacher::with(['user' => function ($query) {
|
|
|
|
|
+ $query->select('user_id', 'full_name', 'role');
|
|
|
|
|
+ }])
|
|
|
|
|
+ ->whereHas('user', function ($query) {
|
|
|
|
|
+ $query->where('role', 'teacher');
|
|
|
|
|
+ })
|
|
|
|
|
+ ->select('teacher_id', 'user_id', 'name')
|
|
|
|
|
+ ->get()
|
|
|
|
|
+ ->map(function ($teacher) {
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'id' => $teacher->teacher_id,
|
|
|
|
|
+ 'name' => $teacher->user->full_name ?? $teacher->name
|
|
|
|
|
+ ];
|
|
|
|
|
+ })
|
|
|
|
|
+ ->pluck('name', 'id')
|
|
|
|
|
+ ->toArray();
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected static function gradeOptions(): array
|
|
protected static function gradeOptions(): array
|
|
|
{
|
|
{
|
|
|
- return DB::table('students')
|
|
|
|
|
- ->distinct()
|
|
|
|
|
- ->orderBy('grade')
|
|
|
|
|
- ->pluck('grade', 'grade')
|
|
|
|
|
- ->toArray();
|
|
|
|
|
|
|
+ // 使用缓存优化性能,缓存30分钟
|
|
|
|
|
+ return cache()->remember('grade_options', 1800, function () {
|
|
|
|
|
+ return Student::query()
|
|
|
|
|
+ ->select('grade')
|
|
|
|
|
+ ->distinct()
|
|
|
|
|
+ ->whereNotNull('grade')
|
|
|
|
|
+ ->orderBy('grade')
|
|
|
|
|
+ ->pluck('grade', 'grade')
|
|
|
|
|
+ ->toArray();
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected static function classOptions(): array
|
|
protected static function classOptions(): array
|
|
|
{
|
|
{
|
|
|
- return DB::table('students')
|
|
|
|
|
- ->distinct()
|
|
|
|
|
- ->orderBy('class_name')
|
|
|
|
|
- ->pluck('class_name', 'class_name')
|
|
|
|
|
- ->toArray();
|
|
|
|
|
|
|
+ // 使用缓存优化性能,缓存30分钟
|
|
|
|
|
+ return Cache::remember('class_options', 1800, function () {
|
|
|
|
|
+ return Student::query()
|
|
|
|
|
+ ->select('class_name')
|
|
|
|
|
+ ->whereNotNull('class_name')
|
|
|
|
|
+ ->where('class_name', '!=', '')
|
|
|
|
|
+ ->distinct()
|
|
|
|
|
+ ->orderBy('class_name')
|
|
|
|
|
+ ->pluck('class_name', 'class_name')
|
|
|
|
|
+ ->toArray();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 清除相关缓存
|
|
|
|
|
+ */
|
|
|
|
|
+ public static function clearCaches(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ Cache::forget('teacher_options');
|
|
|
|
|
+ Cache::forget('grade_options');
|
|
|
|
|
+ Cache::forget('class_options');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|