Laravel Filament:计算Repeater中所有商品总价并存入数据库
解决Laravel Filament中Repeater组件订单总价计算并存库问题
问题分析
你当前的代码仅能计算单个Repeater项的金额,且无法将所有商品的总价存入orders表的total_amount字段,核心问题在于没有遍历所有Repeater条目计算总和,也未在表单提交流程中正确将总和赋值给订单模型的对应属性。
解决方案
步骤1:修改表单,添加实时总价显示(可选,提升用户体验)
在Repeater组件外部添加一个只读字段,通过live()和reactive()实时计算所有商品的总价:
Forms\Components\Grid::make()->schema([ // 原有Repeater组件 Forms\Components\Repeater::make('items') ->relationship() ->required() ->label(false) ->addActionLabel('Add product') ->schema([ Select::make('product_id') ->options(Product::all()->pluck('name', 'id')) ->label('Product') ->reactive() ->searchable() ->required() ->columnStart(1) ->afterStateUpdated(function ($state, Set $set) { $set('unit_price', Product::find($state)?->price ?? 0); }), TextInput::make('unit_price')->columnStart(2)->readOnly(), TextInput::make('qty') ->numeric() ->default(1) ->minValue(1) ->required() ->live() ->reactive() ->dehydrated() ->columnStart(3), ])->columnSpan('full'), // 添加总价显示字段 Forms\Components\TextInput::make('total_amount') ->label('Total Amount') ->readOnly() ->live() ->reactive() ->default(function (Get $get) { $items = $get('items') ?? []; return collect($items)->sum(function ($item) { return ($item['qty'] ?? 0) * ($item['unit_price'] ?? 0); }); }), ])
步骤2:表单提交时自动计算并赋值总价
在Filament的Form组件中添加beforeSave回调,遍历所有订单条目计算总和,赋值给订单模型的total_amount字段:
// 在你的CreateOrderForm/EditOrderForm的form()方法末尾追加 ->beforeSave(function (Order $record, array $data) { $total = collect($data['items'])->sum(function ($item) { return ($item['qty'] ?? 0) * ($item['unit_price'] ?? 0); }); $record->total_amount = $total; })
备选方案:用模型事件自动计算(更通用)
如果希望在任何场景下创建/更新订单都自动计算总价,可以在Order模型中注册saving事件:
// app/Models/Order.php protected static function boot() { parent::boot(); static::saving(function (Order $order) { $order->total_amount = $order->items->sum(function ($item) { return $item->qty * $item->unit_price; }); }); }
注意:使用模型事件前,需确保订单与订单条目的关联关系已正确定义:
// Order模型中添加关联方法 public function items() { return $this->hasMany(OrderItem::class); }
关键注意事项
- 确保
Order模型的$fillable数组包含total_amount字段,否则无法正常赋值:// app/Models/Order.php protected $fillable = ['number', 'customer_id', 'total_amount']; - 实时总价显示依赖
live()和reactive(),能让用户操作时看到动态变化的金额 - 表单
beforeSave回调仅在Filament后台操作时生效,模型事件则覆盖所有订单创建/更新场景
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

