跳到主要内容
版本:3.x

仪表盘

概述

Filament 让你可以使用 Widget,创建动态自定义面板。

接下来的文档将解释如何使用这些 Widget 来在后台面板中组装仪表盘。

可用 Widget

Filament 随带了这些 Widget:

  • 统计概览插件可以在卡片内显示任何数据,通常为数值型数据,显示成一行统计数据。
  • 图表插件在一个可视化图标中显示数值型数据。
  • 表格插件可用在仪表盘中显示表格

你也可以创建自己自定义插件,使之与 Filament 预制的 Widget 保存一致的设计。

Widget 排序

每一个 Widget 类都有一个 $sort 属性,可用于改变该插件在页面中相对于其他插件的排序:

protected static ?int $sort = 2;

自定义 Widget 宽度

你可以使用 $columnSpan 属性自定义 Widget 的宽度。你可以设置为 1 到 12 之间的数字,表明插件占用多少列宽,或者使用 full 表示占用全部宽度:

protected int | string | array $columnSpan = 'full';

响应式 Widget 宽度

你可能希望根据浏览器的响应式临界点,修改 Widget 宽度。可以使用包含各个临界点对应数字的数组实现:

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

当使用响应式插件网格时,尤其有用。

自定义插件网格

你可以修改有多少网格数被用于展示插件。

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

然后,在新建的 app/Filament/Pages/Dashboard.php 文件中,你可以重写 getColumns() 方法,来返回占用的网格列数:

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

响应式 Widget 网格

你可能希望根据浏览器的响应式临界点,调整 Widget 占用的网格数。返回一个类似如下数组,包含各个临界点对应的列数:

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

可以和响应式插件宽度配合使用。

条件性隐藏插件

你可以重写 Widget 的静态 canView() 方法,条件性地对其进行隐藏:

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

表格 Widget

添加表格到仪表盘非常简单。通过如下命令创建一个 Widget:

php artisan make:filament-widget LatestOrders --table

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

自定义插件

创建一个名为 BlogPostsOverview 的 widget:

php artisan make:filament-widget BlogPostsOverview

该命令会创建两个文件 - 一个插件类文件位于 Filament 目录下的 /Widgets 文件夹中,以及一个位于 Filament 视图目录 /widgets 文件夹中的视图文件。

过滤 widget 数据

你可以添加表单到仪表盘,以允许用户过滤所有 widget 上显示的数据。过滤器更新时,Widget 会使用新数据重新加载。

首先,你需要替换原有的仪表盘页面

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

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

class Dashboard extends BaseDashboard
{
use HasFiltersForm;

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

在需要过滤器的数据的 Widget 类中,你需要添加 InteractsWithPageFilters trait,以允许使用 $this->filters 属性来访问过滤器表单那的原始数据:

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->filters['startDate'] ?? null;
$endDate = $this->filters['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->filters 数组总是反射当前表单数据。请注意,这个数据是未经验证的,因为它是实时且不会用于查询数据库之外的其他用途。你必须在使用前确保这个数据是有效。本例中,我们会在查询中使用前检测开始日期是否已设置。

使用 Action 模态框过滤 widget 数据

此外,你可以将过滤器表单换成 Action 模态框,通过单击页面标题中的按钮可以打开该模态框。使用这种方法有很多好处:

  • 过滤器表单不总是可见,这样允许你让 Widget 使用页面的全高。
  • 过滤器不会更新 Wiget,除非用户点击了"应用(Apply)"按钮,这意味着过滤器不会重新加载,除非用户准备好了。如果 widget 加载的开销大,这可以改进性能。
  • 验证可以在过滤器表单上执行,这意味着 widget 可以依赖于有效的数据 —— 用户在验证有效之前无法提交表单。取消模态框将丢弃用户的更改。

要将过滤器表单替换成 Action 模态框,你可以使用 HasFiltersAction trait 替换 HasFiltersForm。然后在 getHeaderActions() 中注册 FilterAction 类:

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Form;
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'),
// ...
]),
];
}
}

处理来自过滤器 Action 的数据根处理来自过滤器头部表单那的数据一样,只是数据在传递到 widget 之前要经过验证。InteractsWithPageFilters trait 仍然适用。

禁用默认 Widget

默认情况下,仪表盘上展示了两个 Widget。这些插件可以通过更新配置widgets() 数组禁用:

use Filament\Panel;

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

自定义仪表盘页面

如果你想要自定义 Dashboard 类,比如修改 Widget 宽度,请新建文件 app/Filament/Pages/Dashboard.php

<?php

namespace App\Filament\Pages;

class Dashboard extends \Filament\Pages\Dashboard
{
// ...
}

最后,在配置文件中移除原本的 Dashboard 类:

use Filament\Panel;

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

创建多个仪表盘

如果你需要创建多个仪表盘,你可以重复上面描述的过程。创建继承 Dashboard 类的新页面,你可以根据需要创建多个仪表盘。

你也需要定义到面板的 URL 路径,否则它将会是 / :

protected static string $routePath = 'finance';

你也可以重写 $title 属性修改仪表盘的标题:

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

显示给用户的主仪表盘是,根据定义的导航排序,用户有权访问(由 canAccess() 方法控制)的第一个仪表盘。

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

protected static ?int $navigationSort = 15;