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

如何在Laravel Filament中实现Material Selection-Quotation-Addendums嵌套资源?

三级嵌套Filament资源实现方案

针对Material Selection > Quotation > Addendums的三级关联需求,完全基于Filament原生资源系统实现层级跳转和关联过滤,无需自定义Livewire页面,步骤如下:

1. 确保模型关联正确

先确认三个模型的关联关系定义:

// MaterialSelection.php
public function quotations()
{
    return $this->hasMany(Quotation::class);
}

// Quotation.php
public function materialSelection()
{
    return $this->belongsTo(MaterialSelection::class);
}

public function addendums()
{
    return $this->hasMany(Addendum::class);
}

// Addendum.php
public function quotation()
{
    return $this->belongsTo(Quotation::class);
}

2. 第一层:Material Selection详情页添加跳转按钮

在MaterialSelectionResource的详情页(View/Edit页面)添加跳转至对应Quotation列表的按钮,携带关联ID参数:

// 比如在ViewMaterialSelection.php的headerActions方法中
use Filament\Pages\Actions\Action;

public function headerActions(): array
{
    return [
        // 其他原有按钮
        Action::make('viewQuotations')
            ->label('查看关联报价单')
            ->url(fn ($record) => QuotationResource::getUrl('index', ['material_selection_id' => $record->id]))
            ->icon('heroicon-o-document-text'),
    ];
}

3. 第二层:Quotation资源处理关联过滤与跳转

3.1 列表页过滤关联数据

修改QuotationResource的List页面,自动过滤当前Material Selection下的Quotation,同时添加返回上级的按钮:

// ListQuotations.php
use Filament\Resources\Pages\ListRecords;
use Illuminate\Database\Eloquent\Builder;

class ListQuotations extends ListRecords
{
    protected static string $resource = QuotationResource::class;

    // 过滤仅显示当前物料选择下的报价单
    protected function getTableQuery(): Builder
    {
        $query = parent::getTableQuery();
        if ($materialId = request()->query('material_selection_id')) {
            $query->where('material_selection_id', $materialId);
        }
        return $query;
    }

    // 添加返回上级的按钮
    protected function getHeaderActions(): array
    {
        $actions = parent::getHeaderActions();
        if ($materialId = request()->query('material_selection_id')) {
            $actions[] = Action::make('back')
                ->label('返回物料选择')
                ->url(MaterialSelectionResource::getUrl('view', ['record' => $materialId]))
                ->icon('heroicon-o-arrow-left');
        }
        return $actions;
    }
}

3.2 创建页自动填充关联ID

修改QuotationResource的Create页面,自动填充material_selection_id参数,创建后返回关联列表页:

// CreateQuotation.php
use Filament\Resources\Pages\CreateRecord;

class CreateQuotation extends CreateRecord
{
    protected static string $resource = QuotationResource::class;

    protected function mutateFormDataBeforeCreate(array $data): array
    {
        if ($materialId = request()->query('material_selection_id')) {
            $data['material_selection_id'] = $materialId;
        }
        return $data;
    }

    protected function getRedirectUrl(): string
    {
        if ($materialId = request()->query('material_selection_id')) {
            return QuotationResource::getUrl('index', ['material_selection_id' => $materialId]);
        }
        return parent::getRedirectUrl();
    }
}

3.3 详情页添加跳转至Addendums的按钮

在QuotationResource的详情页添加跳转按钮:

// ViewQuotation.php的headerActions方法中
Action::make('viewAddendums')
    ->label('查看关联附录')
    ->url(fn ($record) => AddendumResource::getUrl('index', ['quotation_id' => $record->id]))
    ->icon('heroicon-o-document-duplicate'),

4. 第三层:Addendum资源复用Quotation的逻辑

完全参照Quotation资源的处理方式,实现:

  • 列表页过滤当前Quotation下的Addendums
  • 创建页自动填充quotation_id
  • 列表页添加返回Quotation详情的按钮

示例代码(ListAddendums.php):

use Filament\Resources\Pages\ListRecords;
use Illuminate\Database\Eloquent\Builder;

class ListAddendums extends ListRecords
{
    protected static string $resource = AddendumResource::class;

    protected function getTableQuery(): Builder
    {
        $query = parent::getTableQuery();
        if ($quotationId = request()->query('quotation_id')) {
            $query->where('quotation_id', $quotationId);
        }
        return $query;
    }

    protected function getHeaderActions(): array
    {
        $actions = parent::getHeaderActions();
        if ($quotationId = request()->query('quotation_id')) {
            $actions[] = Action::make('back')
                ->label('返回报价单')
                ->url(QuotationResource::getUrl('view', ['record' => $quotationId]))
                ->icon('heroicon-o-arrow-left');
        }
        return $actions;
    }
}

5. 优化:隐藏嵌套资源的主导航入口

如果不需要在Filament主导航直接显示Quotation和Addendum,在对应资源类中添加:

// QuotationResource.php/AddendumResource.php
public static function navigation(): ?NavigationItem
{
    return null;
}

可选:自定义面包屑显示完整层级

在各层级列表页重写getBreadcrumbs方法,比如Quotation列表页:

protected function getBreadcrumbs(): array
{
    $breadcrumbs = [
        '/' => '仪表盘',
        MaterialSelectionResource::getUrl('index') => '物料选择',
    ];

    if ($materialId = request()->query('material_selection_id')) {
        $material = MaterialSelection::findOrFail($materialId);
        $breadcrumbs[MaterialSelectionResource::getUrl('view', ['record' => $materialId])] = $material->name;
    }

    $breadcrumbs[] = '报价单';
    return $breadcrumbs;
}

内容的提问来源于stack exchange,提问作者Ali Safi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:25:50