You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:04:54