components([ Group::make() ->schema([ Section::make('文章内容') ->schema([ TextInput::make('title') ->label('标题') ->required() ->maxLength(255) ->live(onBlur: true) ->afterStateUpdated(fn ($state, callable $set) => $set('slug', Str::slug($state))), TextInput::make('slug') ->label('URL 别名') ->required() ->unique(ignoreRecord: true) ->maxLength(255), Textarea::make('excerpt') ->label('摘要') ->rows(3) ->maxLength(500) ->helperText('文章简短描述,用于列表展示'), RichEditor::make('content') ->label('正文') ->required() ->columnSpanFull() ->fileAttachmentsDisk('public') ->fileAttachmentsDirectory('posts'), ]) ->columns(2), Section::make('图片') ->schema([ FileUpload::make('cover_image') ->label('封面图片') ->image() ->directory('posts/covers') ->imageEditor() ->imageEditorAspectRatios([ '16:9', '4:3', '1:1', ]), FileUpload::make('gallery') ->label('图片墙') ->image() ->multiple() ->reorderable() ->directory('posts/gallery') ->maxFiles(9) ->helperText('最多上传 9 张图片,ins 风格展示'), ]) ->columns(2), ]) ->columnSpan(['lg' => 2]), Group::make() ->schema([ Section::make('发布设置') ->schema([ Select::make('status') ->label('状态') ->options([ 'draft' => '草稿', 'published' => '已发布', 'scheduled' => '定时发布', ]) ->default('draft') ->required() ->live(), DateTimePicker::make('published_at') ->label('发布时间') ->default(now()) ->visible(fn (callable $get) => in_array($get('status'), ['published', 'scheduled'])), Toggle::make('is_featured') ->label('精选文章') ->helperText('精选文章将在首页突出显示'), ]), Section::make('分类与标签') ->schema([ Select::make('category_id') ->label('分类') ->relationship('category', 'name') ->searchable() ->preload() ->createOptionForm([ TextInput::make('name') ->label('分类名称') ->required(), TextInput::make('slug') ->label('别名') ->required(), ]), Select::make('tags') ->label('标签') ->relationship('tags', 'name') ->multiple() ->searchable() ->preload() ->createOptionForm([ TextInput::make('name') ->label('标签名称') ->required(), TextInput::make('slug') ->label('别名') ->required(), ColorPicker::make('color') ->label('颜色') ->default('#6366f1'), ]), ]), Section::make('统计信息') ->schema([ Placeholder::make('views_count') ->label('浏览量') ->content(fn (?Post $record): string => $record?->views_count ?? '0'), Placeholder::make('likes_count') ->label('点赞数') ->content(fn (?Post $record): string => $record?->likes_count ?? '0'), Placeholder::make('created_at') ->label('创建时间') ->content(fn (?Post $record): string => $record?->created_at?->format('Y-m-d H:i:s') ?? '-'), Placeholder::make('updated_at') ->label('更新时间') ->content(fn (?Post $record): string => $record?->updated_at?->format('Y-m-d H:i:s') ?? '-'), ]) ->hidden(fn (?Post $record) => $record === null), ]) ->columnSpan(['lg' => 1]), ]) ->columns(3); } public static function table(Table $table): Table { return $table ->columns([ ImageColumn::make('cover_image') ->label('封面') ->square(), TextColumn::make('title') ->label('标题') ->searchable() ->sortable() ->limit(40), TextColumn::make('category.name') ->label('分类') ->badge() ->sortable(), TextColumn::make('status') ->label('状态') ->badge() ->color(fn (string $state): string => match ($state) { 'draft' => 'gray', 'published' => 'success', 'scheduled' => 'warning', default => 'gray', }) ->formatStateUsing(fn (string $state): string => match ($state) { 'draft' => '草稿', 'published' => '已发布', 'scheduled' => '定时发布', default => $state, }), IconColumn::make('is_featured') ->label('精选') ->boolean(), TextColumn::make('views_count') ->label('浏览') ->numeric() ->sortable(), TextColumn::make('published_at') ->label('发布时间') ->dateTime('Y-m-d H:i') ->sortable(), TextColumn::make('created_at') ->label('创建时间') ->dateTime('Y-m-d H:i') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->defaultSort('created_at', 'desc') ->filters([ SelectFilter::make('status') ->label('状态') ->options([ 'draft' => '草稿', 'published' => '已发布', 'scheduled' => '定时发布', ]), SelectFilter::make('category') ->label('分类') ->relationship('category', 'name'), TernaryFilter::make('is_featured') ->label('精选'), ]) ->actions([ ViewAction::make(), EditAction::make(), DeleteAction::make(), ]) ->bulkActions([ \Filament\Actions\BulkActionGroup::make([ \Filament\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListPosts::route('/'), 'create' => Pages\CreatePost::route('/create'), 'view' => Pages\ViewPost::route('/{record}'), 'edit' => Pages\EditPost::route('/{record}/edit'), ]; } }