Filament 添加上一页下一页导航按钮功能

在本文中,我们将深入探讨在 Filament 页面中制作上一页和下一页导航按钮的过程。这些按钮设计为 Fila

在本文中,我们将深入探讨在 Filament 页面中制作上一页和下一页导航按钮的过程。这些按钮设计为 Filament Header 操作,可以应用在 ViewPages 和 EditPages 之间无缝导航。

引入新的 Action

首先,我们需要引入两个新 Action:PreviousAction 和 NextAction。我将这两个 Action 放在 app/Filament/Resources/Actions 文件夹中。

PreviousAction.php

//Path:app/Filament/Resources/Actions/PreviousAction.php
namespace AppFilamentResourcesActions;
 
use FilamentActionsAction;
 
class PreviousAction extends Action
{
    public static function getDefaultName(): ?string
    {
        return '上一页';
    }
 
    protected function setUp(): void
    {
        parent::setUp();
 
        $this->hiddenLabel()
            ->icon('heroicon-o-arrow-left')
            ->outlined()
            ->tooltip("Previous {$this->getRecordTitle()}");
    }
}

NextAction.php

//Path:app/Filament/Resources/Actions/NextAction.php
namespace AppFilamentResourcesActions;
 
use FilamentActionsAction;
 
class NextAction extends Action
{
    public static function getDefaultName(): ?string
    {
        return '下一页';
    }
 
    protected function setUp(): void
    {
        parent::setUp();
 
        $this->hiddenLabel()
            ->icon('heroicon-o-arrow-right')
            ->outlined()
            ->tooltip("Next {$this->getRecordTitle()}");
    }
}

在 Pages 中配置 Action

接下来,我们通过添加 CanPaginateViewRecord Trait来扩展 ViewRecord 和 EditRecord 类的功能。我将这个特性放在 app/Filament/Resources/Pages/Concerns 文件夹中,用于配置分页操作,并提供根据当前记录检索上一条和下一条记录的方法。

# Laravel 11 及更高版本可以运行下面的命令创建 trait
php artisan make:trait Filament/Resources/Pages/Concerns/CanPaginateViewRecord
 
# Laravel 10 及以下的版本需要手动创建 trait 文件
namespace AppFilamentResourcesPagesConcerns;
 
use AppFilamentResourcesActionsNextAction;
use AppFilamentResourcesActionsPreviousAction;
use FilamentActionsAction;
use IlluminateDatabaseEloquentModel;
 
trait CanPaginateViewRecord
{
    protected function configureAction(Action $action): void
    {
        $this->configureActionRecord($action);
 
        match (true) {
            $action instanceof PreviousAction => $this->configurePreviousAction($action),
            $action instanceof NextAction => $this->configureNextAction($action),
            default => parent::configureAction($action),
        };
    }
 
    protected function configurePreviousAction(Action $action): void
    {
        if ($this->getPreviousRecord()) {
            $action->url(fn (): string => static::getResource()::getUrl(static::getResourcePageName(), ['record' => $this->getPreviousRecord()]));
        } else {
            $action
                ->disabled()
                ->color('gray');
        }
    }
 
    protected function configureNextAction(Action $action): void
    {
        if ($this->getNextRecord()) {
            $action->url(fn (): string => static::getResource()::getUrl(static::getResourcePageName(), ['record' => $this->getNextRecord()]));
        } else {
            $action
                ->disabled()
                ->color('gray');
        }
    }
 
    protected function getPreviousRecord(): ?Model
    {
        return $this
            ->getRecord()
            ->where('id', '<', $this->getRecord()->id)
            ->orderBy('id', 'desc')
            ->first();
    }
 
    protected function getNextRecord(): ?Model
    {
        return $this
            ->getRecord()
            ->where('id', '>', $this->getRecord()->id)
            ->orderBy('id', 'asc')
            ->first();
    }
}

注意:在此示例中,我们默认表格使用了自动递增的 ID。如果您的表配置不同,则需要相应地调整 getPreviousRecord 和 getNextRecord 方法。

使用示例

现在,让我们在 ViewRecord 和 EditRecord 页面中实现这些操作。通过包含 CanPaginateViewRecord Trait 并在 getHeaderActions 数组中注册 Action,您可以启用上一个和下一个导航按钮。以下是在 ViewPost 页面中的使用示例:

namespace AppFilamentResourcesPostResourcePages;
 
use AppFilamentResourcesActionsNextAction;
use AppFilamentResourcesActionsPreviousAction;
use AppFilamentResourcesPagesConcernsCanPaginateViewRecord;
use AppFilamentResourcesPostResource;
use FilamentActions;
use FilamentResourcesPagesViewRecord;
 
class ViewPost extends ViewRecord
{
    use CanPaginateViewRecord;
 
    protected static string $resource = PostResource::class;
 
    protected function getHeaderActions(): array
    {
        return [
            ActionsEditAction::make(),
            PreviousAction::make(),
            NextAction::make(),
        ];
    }
}

效果展示