Laravel Nova中如何计算两文本字段乘积并自动赋值给另一字段
Laravel Nova SimpleRepeatable 字段自动计算金额实现方案
针对采购订单条目里数量、单价乘积自动填充金额的需求,因为基于SimpleRepeatable实现动态行,需要同时做前端实时交互+后端数据兜底,避免数据异常。
1. 调整字段配置
首先给三个计算相关的字段加标识类、数字输入属性,同时把金额字段设为只读,避免手动修改:
SimpleRepeatable::make('Purchase Order Items', 'purchase_order_items', [ Select::make('Purchase_Order_Id') ->options(\App\Models\PurchaseOrder::pluck('serial_number', 'id')) ->displayUsingLabels()->rules('required'), Select::make('Product_id')->options(\App\Models\Product::pluck('product_name', 'id')) ->displayUsingLabels()->rules('required'), // 数量字段 Text::make('Quantity') ->rules('required', 'numeric', 'min:0') ->withMeta(['extraAttributes' => [ 'class' => 'form-input item-quantity', 'type' => 'number', 'step' => '0.01' ]]), // 单价字段 Text::make('Unit_Price') ->rules('required', 'numeric', 'min:0') ->withMeta(['extraAttributes' => [ 'class' => 'form-input item-unit-price', 'type' => 'number', 'step' => '0.01' ]]), // 金额字段,只读 Text::make('Amount') ->rules('required', 'numeric', 'min:0') ->readonly() ->withMeta(['extraAttributes' => [ 'class' => 'form-input item-amount', 'type' => 'number', 'step' => '0.01' ]]), Select::make('Variant_id') ->options(\App\Models\Variant::pluck('productName', 'id')) ->displayUsingLabels()->rules('required'), ])
2. 前端实时计算逻辑
用事件委托的方式监听输入,适配SimpleRepeatable动态新增的行,不需要重复绑定事件。把下面的JS放到你自定义的Nova全局脚本里即可:
// 全局事件委托,适配动态新增的重复行 document.addEventListener('input', function (e) { // 仅处理数量、单价输入框的变更 if (e.target.matches('.item-quantity, .item-unit-price')) { // 定位到当前输入框所在的重复行容器 const currentRow = e.target.closest('.simple-repeatable-row'); if (!currentRow) return; // 获取当前行的三个字段DOM const quantityEl = currentRow.querySelector('.item-quantity'); const priceEl = currentRow.querySelector('.item-unit-price'); const amountEl = currentRow.querySelector('.item-amount'); if (!quantityEl || !priceEl || !amountEl) return; // 空值按0计算,保留2位小数(可根据业务调整精度) const quantity = parseFloat(quantityEl.value) || 0; const unitPrice = parseFloat(priceEl.value) || 0; const total = (quantity * unitPrice).toFixed(2); // 赋值后触发input事件,让Nova的Vue层能识别值变更,否则保存时会丢失计算结果 amountEl.value = total; amountEl.dispatchEvent(new Event('input', { bubbles: true })); } });
3. 后端兜底计算(必加)
前端计算仅做体验优化,必须在后端强制重算金额,防止前端篡改、漏算导致数据错误。在对应PurchaseOrder模型的启动方法中加保存事件即可:
protected static function booted() { static::saving(function ($purchaseOrder) { $items = $purchaseOrder->purchase_order_items ?? []; foreach ($items as &$item) { $quantity = (float)($item['Quantity'] ?? 0); $unitPrice = (float)($item['Unit_Price'] ?? 0); // 强制覆盖前端传入的金额值 $item['Amount'] = number_format($quantity * $unitPrice, 2, '.', ''); } $purchaseOrder->purchase_order_items = $items; }); }
注意事项
- 三个数值字段必须加
numeric校验规则,避免非数字输入导致计算异常 - 小数保留位数要和业务财务规则对齐,默认保留两位小数适配人民币等常用货币场景
- 不要省略后端兜底逻辑,所有前端交互都不能作为数据正确性的唯一保障
内容的提问来源于stack exchange,提问作者ijse govindu
相关产品推荐
相关产品推荐

