Filament PHP v3自定义页面添加交互过滤器至头部组件上方
在Filament PHP v3自定义页面实现过滤栏并与头部组件交互
核心问题原因
Filament的自定义页面不会自动渲染HasFiltersForm或getFormSchema定义的表单,必须手动在视图中渲染表单,并通过Livewire事件实现过滤参数与头部组件的联动。
完整实现步骤
1. 修改自定义页面类
添加InteractsWithForms trait,定义过滤表单、状态绑定及过滤逻辑:
use Filament\Forms\Concerns\InteractsWithForms; use Filament\Forms\Contracts\HasForms; use Filament\Forms\Form; use Illuminate\Support\Carbon; class ShowClicks extends Page implements HasForms { use InteractsWithForms; protected static string $resource = ShortUrlClickResource::class; protected static string $view = 'filament.resources.short-url-click-resource.pages.show-clicks'; // 存储过滤参数的公共属性,供视图和组件调用 public ?Carbon $startDate = null; public ?Carbon $endDate = null; // 定义过滤表单结构 protected function getFormSchema(): array { return [ \Filament\Forms\Components\DatePicker::make('startDate') ->label('开始日期') ->native(false), \Filament\Forms\Components\DatePicker::make('endDate') ->label('结束日期') ->native(false) ->afterOrEqual('startDate'), // 可添加其他过滤字段,比如下拉选择、文本输入等 ]; } // 将表单状态直接绑定到页面类的公共属性 protected function getFormStatePath(): string { return ''; } // 应用过滤:触发事件通知头部组件更新数据 public function applyFilters() { $this->dispatch('filters-updated', [ 'startDate' => $this->startDate?->toDateTimeString(), 'endDate' => $this->endDate?->toDateTimeString(), ]); } // 重置过滤参数 public function resetFilters() { $this->reset(['startDate', 'endDate']); $this->form->fill(); $this->dispatch('filters-updated', [ 'startDate' => null, 'endDate' => null, ]); } protected function getHeaderWidgets(): array { return [ ShortUrlClicksChart::make(), MostShortUrlClicks::make(), ]; } }
2. 修改自定义页面视图
在头部组件上方渲染过滤表单,添加应用/重置按钮:
<x-filament-panels::page> <!-- 过滤栏区域 --> <div class="mb-6 p-4 bg-white rounded-lg shadow-sm"> <x-filament-forms::form wire:submit="applyFilters" class="flex flex-wrap gap-4 items-center"> {{ $this->form }} <div class="mt-2 sm:mt-0"> <x-filament-panels::button type="submit" color="primary"> 应用过滤 </x-filament-panels::button> <x-filament-panels::button wire:click="resetFilters" color="secondary" class="ml-2"> 重置 </x-filament-panels::button> </div> </x-filament-forms::form> </div> <!-- 头部组件(图表+表格) --> {{ $this->headerWidgets }} <!-- 页面其他内容(如果有) --> <div class="mt-8"> {{-- 页面主体内容 --}} </div> </x-filament-panels::page>
3. 改造头部组件实现过滤联动
给图表和表格组件添加事件监听,接收过滤参数并更新查询逻辑:
图表组件示例(ShortUrlClicksChart):
use Filament\Widgets\ChartWidget; use Illuminate\Support\Facades\DB; use Illuminate\Support\Carbon; class ShortUrlClicksChart extends ChartWidget { protected static ?string $heading = '点击趋势'; public ?string $startDate = null; public ?string $endDate = null; protected function getOptions(): array { return [ 'responsive' => true, 'maintainAspectRatio' => false, ]; } protected function getData(): array { $query = DB::table('short_url_clicks'); // 应用过滤条件 if ($this->startDate) { $query->where('created_at', '>=', Carbon::parse($this->startDate)); } if ($this->endDate) { $query->where('created_at', '<=', Carbon::parse($this->endDate)->endOfDay()); } $data = $query->selectRaw('DATE(created_at) as date, COUNT(*) as clicks') ->groupBy('date') ->orderBy('date') ->get(); return [ 'datasets' => [ [ 'label' => '点击量', 'data' => $data->pluck('clicks')->toArray(), ], ], 'labels' => $data->pluck('date')->toArray(), ]; } // 监听过滤更新事件 protected function getListeners(): array { return [ 'filters-updated' => 'updateFilters', ]; } // 更新过滤参数并刷新数据 public function updateFilters(array $filters) { $this->startDate = $filters['startDate']; $this->endDate = $filters['endDate']; $this->refresh(); } }
表格组件示例(MostShortUrlClicks):
use Filament\Widgets\TableWidget; use App\Models\ShortUrlClick; use Filament\Tables; use Filament\Tables\Table; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; class MostShortUrlClicks extends TableWidget { protected static ?string $heading = '热门短链接点击排行'; public ?string $startDate = null; public ?string $endDate = null; public function table(Table $table): Table { return $table ->query(function () { $query = ShortUrlClick::query() ->select('short_url_id', DB::raw('COUNT(*) as total_clicks')) ->groupBy('short_url_id') ->orderBy('total_clicks', 'desc'); // 应用过滤条件 if ($this->startDate) { $query->where('created_at', '>=', Carbon::parse($this->startDate)); } if ($this->endDate) { $query->where('created_at', '<=', Carbon::parse($this->endDate)->endOfDay()); } return $query; }) ->columns([ Tables\Columns\TextColumn::make('short_url.url') ->label('短链接') ->url(fn ($record) => route('short-urls.show', $record->short_url_id)), Tables\Columns\TextColumn::make('total_clicks') ->label('总点击量') ->numeric(), ]); } // 监听过滤更新事件 protected function getListeners(): array { return [ 'filters-updated' => 'updateFilters', ]; } // 更新过滤参数并刷新表格 public function updateFilters(array $filters) { $this->startDate = $filters['startDate']; $this->endDate = $filters['endDate']; $this->refresh(); } }
关键说明
- 利用Livewire的事件系统实现页面与组件的通信,避免直接依赖;
- 表单状态绑定到页面类的公共属性,确保参数传递实时性;
- 组件通过
refresh()方法触发数据重新加载,实现过滤后的视图更新。
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

