schema([ TextInput::make('name') ->label('系列名称') ->required() ->maxLength(128) ->placeholder('如:人教版、北师大版、华东师大版'), TextInput::make('slug') ->label('别名') ->maxLength(64) ->placeholder('如:pep、bsd、ecnu'), TextInput::make('publisher') ->label('出版社') ->maxLength(128) ->placeholder('如:人民教育出版社'), TextInput::make('region') ->label('适用地区') ->maxLength(128) ->placeholder('如:全国、江苏省、浙江省'), TextInput::make('stages') ->label('适用学段') ->helperText('JSON 格式,如:["primary", "junior"]') ->placeholder('["primary", "junior", "senior"]') ->formatStateUsing(fn ($state) => is_array($state) ? json_encode($state, JSON_UNESCAPED_UNICODE) : $state) ->dehydrateStateUsing(fn ($state) => is_string($state) ? json_decode($state, true) : $state), TextInput::make('start_year') ->label('起始年份') ->numeric() ->placeholder('如:2024'), Select::make('is_active') ->label('是否启用') ->options(function (): array { return [ 1 => '已启用', 0 => '已停用', ]; }) ->default(1) ->required() ->native(false) ->selectablePlaceholder(false) ->helperText('选择是否启用此教材系列'), TextInput::make('sort_order') ->label('排序') ->numeric() ->default(0) ->helperText('数字越小排序越靠前'), Textarea::make('meta') ->label('扩展信息') ->placeholder('JSON 格式,如:{"website": "http://example.com", "description": "说明"}') ->formatStateUsing(fn ($state) => is_array($state) ? json_encode($state, JSON_UNESCAPED_UNICODE) : $state) ->dehydrateStateUsing(fn ($state) => is_string($state) ? json_decode($state, true) : $state) ->columnSpanFull(), ]); } public static function table(Tables\Table $table): Tables\Table { return $table ->columns([ TextColumn::make('id') ->label('ID') ->sortable() ->copyable() ->copyMessage('ID 已复制'), TextColumn::make('name') ->label('系列名称') ->searchable() ->sortable(), TextColumn::make('slug') ->label('别名') ->searchable() ->copyable(), TextColumn::make('publisher') ->label('出版社') ->searchable(), TextColumn::make('region') ->label('适用地区') ->searchable(), BadgeColumn::make('stages') ->label('学段') ->formatStateUsing(function ($state): string { // 确保返回字符串,即使输入是数组 if (is_string($state)) { $stages = json_decode($state, true) ?? []; } elseif (is_array($state)) { $stages = $state; } else { return ''; } $stageMap = [ 'primary' => '小学', 'junior' => '初中', 'senior' => '高中', ]; return implode(', ', array_map(fn($s) => $stageMap[$s] ?? $s, $stages)); }) ->separator(',') ->color('success'), TextColumn::make('start_year') ->label('起始年份') ->sortable(), ToggleColumn::make('is_active') ->label('启用状态'), TextColumn::make('sort_order') ->label('排序') ->sortable(), TextColumn::make('created_at') ->label('创建时间') ->dateTime('Y-m-d H:i') ->sortable() ->toggleable(), ]) ->filters([ Tables\Filters\SelectFilter::make('is_active') ->label('启用状态') ->options([ 1 => '已启用', 0 => '已停用', ]), ]) ->actions([ EditAction::make() ->label('编辑'), DeleteAction::make() ->label('删除'), Action::make('view_textbooks') ->label('查看教材') ->icon('heroicon-o-book-open') ->url(fn(Model $record): string => route('filament.admin.resources.textbooks.index', ['tableFilters[series_id][value]' => $record->id]) ), ]) ->bulkActions([ \Filament\Actions\BulkActionGroup::make([ \Filament\Actions\DeleteBulkAction::make() ->label('批量删除'), \Filament\Actions\BulkAction::make('activate') ->label('批量启用') ->icon('heroicon-o-check-circle') ->action(function ($records) { foreach ($records as $record) { static::getApiService()->updateTextbookSeries($record->id, ['is_active' => true]); } Filament::notify('success', '批量启用成功'); }), \Filament\Actions\BulkAction::make('deactivate') ->label('批量停用') ->icon('heroicon-o-x-circle') ->action(function ($records) { foreach ($records as $record) { static::getApiService()->updateTextbookSeries($record->id, ['is_active' => false]); } Filament::notify('success', '批量停用成功'); }), ]), ]) ->defaultSort('sort_order') ->paginated([10, 25, 50, 100]) ->poll('30s'); } public static function getEloquentQuery(): \Illuminate\Database\Eloquent\builder { // 直接使用数据库查询 return parent::getEloquentQuery(); } public static function getRecord(?string $key): ?Model { // 直接从数据库获取记录 return app(static::$model)->find($key); } protected static function newModel(array $data): Model { // 直接创建记录到数据库 $model = app(static::$model); $model->fill($data); $model->save(); return $model; } protected static function updateRecord(Model $record, array $data): Model { // 直接更新数据库记录 $record->update($data); return $record; } protected static function deleteRecord(Model $record): bool { // 直接删除数据库记录 return $record->delete(); } public static function getPages(): array { return [ 'index' => Pages\ManageTextbookSeries::route('/'), 'create' => Pages\CreateTextbookSeries::route('/create'), 'edit' => Pages\EditTextbookSeries::route('/{record}/edit'), ]; } public static function canViewAny(): bool { // 临时允许所有用户查看,等待权限系统完善 return true; } public static function getHeaderActions(): array { return [ \Filament\Actions\Action::make('import_excel') ->label('Excel导入') ->icon('heroicon-o-document-arrow-up') ->color('success') ->url(fn(): string => route('filament.admin.pages.textbook-excel-import-page') ), ]; } public static function canCreate(): bool { // 临时允许所有用户创建,等待权限系统完善 return true; } public static function canEdit(Model $record): bool { // 临时允许所有用户编辑,等待权限系统完善 return true; } public static function canDelete(Model $record): bool { // 临时允许所有用户删除,等待权限系统完善 return true; } public static function canDeleteAny(): bool { // 临时允许所有用户批量删除,等待权限系统完善 return true; } }