Languages

Version

Theme

Widget

概述

简介

Filament 允许你创建由 Widget 组成的动态仪表盘。Widget 是仪表盘上以特定方式显示数据的元素。比如,你可以展示统计数据图表表格

创建 Widget

要创建 Widget,你可以使用 make:filament-widget 命令:

php artisan make:filament-widget MyWidget

该命令将会询问你想创建哪种类型的 Widget。以下是你可以选择的选项:

  • Custom: 自定义 Widget。
  • Chart: 展示图表的 Widget。
  • Stats overview: 展示统计信息的 Widget。
  • Table: 展示表格的 Widget。

Widget 排序

每个 Widget 类都包含一个 $sort 属性,你可以用它来修改其在页面中相对于其他 Widget 的排序。

protected static ?int $sort = 2;

自定义仪表盘页面

如果你想自定义仪表盘类,比如,修改 Widget 列的数量,请新建 app/Filament/Pages/Dashboard.php 文件:

<?php

namespace App\Filament\Pages;

use Filament\Pages\Dashboard as BaseDashboard;

class Dashboard extends BaseDashboard
{
    // ...
}

最后,请从配置文件中删除原来的 Dashboard 类:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
        ->pages([]);
}

如果你没有使用 discoverPages() 来发现新仪表盘类目录中的页面,那么你应该在 pages() 方法中手动这侧该类:

use App\Filament\Pages\Dashboard;
use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->pages([
            Dashboard::class,
        ]);
}

创建多个仪表盘

如果你想创建多个仪表盘,你可以重复上述过程。创建继承 Dashboard 类的新页面将允许创建多个仪表盘怕。

你也需要定义指向其他仪表盘的 URL 路径,否则它将会是 /

protected static string $routePath = 'finance';

你也可以通过重写 $title 属性来自定义仪表盘标题:

protected static ?string $title = 'Finance dashboard';

根据定义的导航排序顺序,向用户显示的主仪表盘是他们有权访问的第一个仪表盘(由 [canAccess() 方法](../navigation/custom pages#授权)控制)。

仪表盘的默认排序顺序为 -2。你可以使用 $navigationSort 控制自定义仪表盘的排序顺序:

protected static ?int $navigationSort = 15;

自定义 Widget 网格

你可以更改用于显示 Widget 的网格列的数量。

首先,你必须替换原始仪表盘页面

现在,在新的 app/Filament/Pages/Dashboard.php 文件中,你可以重写 getColumn() 方法以返回要使用的网格列数量:

public function getColumns(): int | string | array
{
    return 2;
}

响应式 Widget 网格

你可能希望基于浏览器的响应式断点修改 Widget 的网格列数。可以使用一个数组来完成此操作,该数组包含 Widget 在每个断点处应占用的列数:

public function getColumns(): int | string | array
{
    return [
        'md' => 4,
        'xl' => 5,
    ];
}

这与响应式 Widget 宽度非常匹配。

自定义 Widget 宽度

你可以使用 $columnSpan 属性自定义 Widget 宽度。你可以使用 1 到 12 之间的数值说明 Widget 该占用多少列,或者使用 full 使之占用页面的全宽。

protected int | string | array $columnSpan = 'full';
响应式 Widget 宽度

你可能希望基于浏览器的响应式断点修改 Widget 的宽度。可以使用一个数组来完成此操作,该数组包含 Widget 在每个断点处应占用的列数:

protected int | string | array $columnSpan = [
    'md' => 2,
    'xl' => 3,
];

当使用响应式 Widget 网格时,这尤其有用。

条件性隐藏 Widget

你可以重写 Widget 的 canView() 静态方法,条件性地隐藏它们:

public static function canView(): bool
{
    return auth()->user()->isAdmin();
}

表格 Widget

使用如下 Widget 创建命令,你可以添加表格到仪表盘中:

php artisan make:filament-widget LatestOrders --table

现在你可以编辑 Widget 文件自定义表格

自定义 Widget

创建 BlogPostsOverview Widget:

php artisan make:filament-widget BlogPostsOverview

该命令将生成两个文件 —— 在 Filament 目录下的 Widgets 目录中生成一个 Widget 类,以及在 Filament 视图目录的 widgets 目录中生成一个视图文件。

该类是一个 Livewire 组件,因此 Livewire 的所有特性都是可用的。Blade 视图可以包含任何你希望使用的 HTML,并且你可以在视图中访问所有公开的 Livewire 属性。你也可以在视图中使用 $this 访问 Livewire 组件实例。

过滤 Widget 数据

你可以向仪表盘添加一个表单,允许用户过滤所有 Widget 中显示数据。当过滤器更新时,Widget 将重新加载新数据。

首先,你必须[替换原始仪表盘页面](#自定义仪表盘页面)。

现在,在新的 app/Filament/Pages/Dashboard.php 文件中,你可以添加 HasFiltersForm trait,并添加 filtersForm() 方法来返回表单组件:

use Filament\Forms\Components\DatePicker;
use Filament\Pages\Dashboard as BaseDashboard;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;

class Dashboard extends BaseDashboard
{
    use HasFiltersForm;

    public function filtersForm(Schema $schema): Schema
    {
        return $schema
            ->components([
                Section::make()
                    ->schema([
                        DatePicker::make('startDate'),
                        DatePicker::make('endDate'),
                        // ...
                    ])
                    ->columns(3),
            ]);
    }
}

In widget classes that require data from the filters, you need to add the InteractsWithPageFilters trait, which will allow you to use the $this->pageFilters property to access the raw data from the filters form:

use App\Models\BlogPost;
use Carbon\CarbonImmutable;
use Filament\Widgets\StatsOverviewWidget;
use Filament\Widgets\Concerns\InteractsWithPageFilters;
use Illuminate\Database\Eloquent\Builder;

class BlogPostsOverview extends StatsOverviewWidget
{
    use InteractsWithPageFilters;

    public function getStats(): array
    {
        $startDate = $this->pageFilters['startDate'] ?? null;
        $endDate = $this->pageFilters['endDate'] ?? null;

        return [
            StatsOverviewWidget\Stat::make(
                label: 'Total posts',
                value: BlogPost::query()
                    ->when($startDate, fn (Builder $query) => $query->whereDate('created_at', '>=', $startDate))
                    ->when($endDate, fn (Builder $query) => $query->whereDate('created_at', '<=', $endDate))
                    ->count(),
            ),
            // ...
        ];
    }
}

$this->pageFilters 数组将始终反射当前表单数据。请注意,此数据未经验证,因为它是实时的,且不打算用于查询数据库以外的任何目的。在使用数据之前,你必须确保数据是有效的。在这个例子中,我们检查在将其用于查询之前是否设置了开始日期。

使用 Action 模态框过滤 Widget 数据

或者,你可以将过滤器表单替换为操作模态框,模态框可以通过单击页面标题中的按钮打开。使用这种方法有很多好处:

  • 过滤器表单并不总是可见的,这允许 Widget 使用页面的全高。
  • 在用户单击“应用(Apply)”按钮之前,过滤器不会更新 Widget,这意味着在用户准备就绪之前,Widget 不会重新加载。如果加载 Widget 的开销很高,这可以提高性能。
  • 可以对过滤器表单执行验证,这意味着 Widget 可以依赖于数据有效这一事实——在数据有效之前,用户无法提交表单。取消模态框将放弃用户的更改。

要使用操作模态框替代过滤器表单,你可以使用 HasFiltersAction trait 特性而不是 HasFiltersForm。然后,将 FilterAction 类注册为 getHeaderActions() 中的一个操作:

use Filament\Forms\Components\DatePicker;
use Filament\Pages\Dashboard as BaseDashboard;
use Filament\Pages\Dashboard\Actions\FilterAction;
use Filament\Pages\Dashboard\Concerns\HasFiltersAction;

class Dashboard extends BaseDashboard
{
    use HasFiltersAction;
    
    protected function getHeaderActions(): array
    {
        return [
            FilterAction::make()
                ->form([
                    DatePicker::make('startDate'),
                    DatePicker::make('endDate'),
                    // ...
                ]),
        ];
    }
}

处理来自过滤器操作的数据与处理来自过滤器表单的数据相同,除了数据在传递给 Widget 之前经过验证。InteractisWithPageFilters trait 仍然适用。

在用户 Session 中持久化 Widget 过滤器

默认情况下,仪表盘过滤器将在页面之间的用户 Session 中持久化。要禁用此功能,请在仪表盘页面类中重写 $persistsFiltersInSession 属性:

use Filament\Pages\Dashboard as BaseDashboard;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;

class Dashboard extends BaseDashboard
{
    use HasFiltersForm;

    protected bool $persistsFiltersInSession = false;
}

或者,在仪表盘页面类中重写 persistsFiltersInSession() 方法:

use Filament\Pages\Dashboard as BaseDashboard;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;

class Dashboard extends BaseDashboard
{
    use HasFiltersForm;

    public function persistsFiltersInSession(): bool
    {
        return false;
    }
}

禁用默认 Widget

仪表盘中默认有两个 Widegt。你可以更新配置widgets() 数组禁用这些 Widget:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->widgets([]);
}
Edit on GitHub

Still need help? Join our Discord community or open a GitHub discussion