blog/app/Filament/Resources/PostResource.php

308 lines
12 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PostResource\Pages;
use App\Models\Post;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Forms\Components\ColorPicker;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Group;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Support\Str;
class PostResource extends Resource
{
protected static ?string $model = Post::class;
public static function getNavigationIcon(): string|\BackedEnum|null
{
return 'heroicon-o-document-text';
}
public static function getNavigationSort(): ?int
{
return 0;
}
public static function getNavigationGroup(): ?string
{
return '内容管理';
}
public static function getModelLabel(): string
{
return '文章';
}
public static function getPluralModelLabel(): string
{
return '文章';
}
public static function form(Schema $schema): Schema
{
return $schema
->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'),
];
}
}