308 lines
12 KiB
PHP
308 lines
12 KiB
PHP
<?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'),
|
||
];
|
||
}
|
||
}
|