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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:06:27