数量单价金额之间的故事

FrontJS.ready

:warning: 请不要随意将这个函数匹配所有路径,除非你的所用的实体数量单价金额的内部标识完全一致。

由于原生不支持单价数量和金额的互相计算,但是RB支持前端API,这里写一个集成FrontJS前端API实现数量、单价和金额之间的相互计算且联动主表总金额统计的函数。

联动主表总金额

FrontJS.ready(function () {
    var subTableId = 'SalesOrderDet';//你的明细实体名称
    var qtyField = 'Qty';     // 数量
    var priceField = 'Price';   //单价
    var amountField = 'Amount'; //金额
    var mainAmountField = 'TotalAmount'; // 主表金额字段名

    $(document).ready(function () {
        initSubTable();
        bindRowChange();
        calculateMainAmount(); // 页面加载后初始化一次主表金额
    });

    function initSubTable() {
        $('.detail-form-table[data-entity="' + subTableId + '"] tbody tr').each(function (index) {
            calculateRow(index);
        });
    }

    function bindRowChange() {
        // 使用委托监听 input 事件,兼容新增行
        $(document).on('input', '.detail-form-table[data-entity="' + subTableId + '"] input', function () {
            var $row = $(this).closest('tr');
            var rowIndex = $row.index();

            calculateRow(rowIndex, this);  // 把变化的 input 元素传进去
            calculateMainAmount();         // 每次子表变动都重新计算主表金额
        });
    }

    function calculateRow(rowIndex) {
        var changedInput = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
        var row = $('.detail-form-table[data-entity="' + subTableId + '"] tbody tr').eq(rowIndex);

        var $qtyInput = row.find('[data-field="' + qtyField + '"] input');
        var $priceInput = row.find('[data-field="' + priceField + '"] input');
        var $amountInput = row.find('[data-field="' + amountField + '"] input');

        var qty = parseFloat($qtyInput.val()) || 0;
        var price = parseFloat($priceInput.val()) || 0;
        var amount = parseFloat($amountInput.val()) || 0;

        function isValid(value) {
            return !isNaN(value) && isFinite(value) && value >= 0
        }

        // 判断用户改的是哪个字段
        var changedField = null;
        if (changedInput) {
            var fieldKey = $(changedInput).closest('[data-field]').attr('data-field');
            if (fieldKey === qtyField)
                changedField = 'qty';
            else if (fieldKey === priceField)
                changedField = 'price';
            else if (fieldKey === amountField)
                changedField = 'amount'
        }

        // 根据变化源执行不同逻辑
        switch (changedField) {
            case 'qty':
                if (isValid(qty) && isValid(price)) {
                    var newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - newAmount) > 0.001) {
                        $amountInput.val(newAmount.toFixed(2))
                    }
                } else if (isValid(amount) && isValid(price) && price !== 0) {
                    var newQty = amount / price;
                    if (!isValid(qty) || Math.abs(qty - newQty) > 0.001) {
                        $qtyInput.val(newQty.toFixed(2))
                    }
                }
                break;

            case 'price':
                if (isValid(qty) && isValid(price)) {
                    var _newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - _newAmount) > 0.001) {
                        $amountInput.val(_newAmount.toFixed(2))
                    }
                } else if (isValid(amount) && isValid(qty) && qty !== 0) {
                    var newPrice = amount / qty;
                    if (!isValid(price) || Math.abs(price - newPrice) > 0.001) {
                        $priceInput.val(newPrice.toFixed(2))
                    }
                }
                break;

            case 'amount':
                if (isValid(qty) && isValid(amount) && qty !== 0) {
                    var _newPrice = amount / qty;
                    if (!isValid(price) || Math.abs(price - _newPrice) > 0.001) {
                        $priceInput.val(_newPrice.toFixed(2))
                    }
                } else if (isValid(price) && isValid(amount) && price !== 0) {
                    var _newQty = amount / price;
                    if (!isValid(qty) || Math.abs(qty - _newQty) > 0.001) {
                        $qtyInput.val(_newQty.toFixed(2))
                    }
                } else if (isValid(qty) && isValid(price)) {
                    var _newAmount2 = qty * price;
                    if (!isValid(amount) || Math.abs(amount - _newAmount2) > 0.001) {
                        $amountInput.val(_newAmount2.toFixed(2))
                    }
                }
                break;

            default:
                // 默认情况按正向计算一次
                if (isValid(qty) && isValid(price)) {
                    var _newAmount3 = qty * price;
                    if (!isValid(amount) || Math.abs(amount - _newAmount3) > 0.001) {
                        $amountInput.val(_newAmount3.toFixed(2))
                    }
                }
                break;
        }
    }

    // 计算主表金额字段 jine
    function calculateMainAmount() {
        var total = 0;

        $('.detail-form-table[data-entity="' + subTableId + '"] tbody tr').each(function () {
            var $row = $(this);
            var $amountInput = $row.find('[data-field="' + amountField + '"] input');
            var amount = parseFloat($amountInput.val()) || 0;

            if (!isNaN(amount) && isFinite(amount) && amount >= 0) {
                total += amount;
            }
        });

        // 设置主表金额字段(使用 DOM 操作)
        var $mainAmountInput = $('[data-field="' + mainAmountField + '"] input');
        if ($mainAmountInput.length) {
            var currentVal = parseFloat($mainAmountInput.val()) || 0;
            if (Math.abs(currentVal - total) > 0.001) {
                $mainAmountInput.val(total.toFixed(2));
            }
        }
    }
});

只处理一张表

FrontJS单表反复计算数量单价和金额
FrontJS.ready(function () {
    const subTableId = 'SalesOrder'; //你的实体名称,如果要联动主表统计金额,请用上面哪个函数
    const qtyField = 'Qty';     //数量 
    const priceField = 'Price';//单价
    const amountField = 'Amount';//金额

    $(document).ready(function () {
        initSubTable();
        bindRowChange();
    });

    function initSubTable() {
        $(`.detail-form-table[data-entity="${subTableId}"] tbody tr`).each(function (index) {
            calculateRow(index);
        });
    }

    function bindRowChange() {
        // 使用委托监听 input 事件,兼容新增行
        $(document).on('input', `.detail-form-table[data-entity="${subTableId}"] input`, function () {
            const $row = $(this).closest('tr');
            const rowIndex = $row.index();

            calculateRow(rowIndex, this);  // 把变化的 input 元素传进去
        });
    }

    function calculateRow(rowIndex, changedInput = null) {
        const row = $(`.detail-form-table[data-entity="${subTableId}"] tbody tr`).eq(rowIndex);

        const $qtyInput = row.find(`[data-field="${qtyField}"] input`);
        const $priceInput = row.find(`[data-field="${priceField}"] input`);
        const $amountInput = row.find(`[data-field="${amountField}"] input`);

        const qty = parseFloat($qtyInput.val()) || 0;
        const price = parseFloat($priceInput.val()) || 0;
        const amount = parseFloat($amountInput.val()) || 0;

        function isValid(value) {
            return !isNaN(value) && isFinite(value) && value >= 0;
        }

        // 判断用户改的是哪个字段
        let changedField = null;
        if (changedInput) {
            const fieldKey = $(changedInput).closest('[data-field]').attr('data-field');
            if (fieldKey === qtyField) changedField = 'qty';
            else if (fieldKey === priceField) changedField = 'price';
            else if (fieldKey === amountField) changedField = 'amount';
        }

        // 根据变化源执行不同逻辑
        switch (changedField) {
            case 'qty':
                if (isValid(qty) && isValid(price)) {
                    const newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - newAmount) > 0.001) {
                        $amountInput.val(newAmount.toFixed(2));
                    }
                } else if (isValid(amount) && isValid(price) && price !== 0) {
                    const newQty = amount / price;
                    if (!isValid(qty) || Math.abs(qty - newQty) > 0.001) {
                        $qtyInput.val(newQty.toFixed(2));
                    }
                }
                break;

            case 'price':
                if (isValid(qty) && isValid(price)) {
                    const newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - newAmount) > 0.001) {
                        $amountInput.val(newAmount.toFixed(2));
                    }
                } else if (isValid(amount) && isValid(qty) && qty !== 0) {
                    const newPrice = amount / qty;
                    if (!isValid(price) || Math.abs(price - newPrice) > 0.001) {
                        $priceInput.val(newPrice.toFixed(2));
                    }
                }
                break;

            case 'amount':
                if (isValid(qty) && isValid(amount) && qty !== 0) {
                    const newPrice = amount / qty;
                    if (!isValid(price) || Math.abs(price - newPrice) > 0.001) {
                        $priceInput.val(newPrice.toFixed(2));
                    }
                } else if (isValid(price) && isValid(amount) && price !== 0) {
                    const newQty = amount / price;
                    if (!isValid(qty) || Math.abs(qty - newQty) > 0.001) {
                        $qtyInput.val(newQty.toFixed(2));
                    }
                } else if (isValid(qty) && isValid(price)) {
                    const newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - newAmount) > 0.001) {
                        $amountInput.val(newAmount.toFixed(2));
                    }
                }
                break;

            default:
                // 默认情况按正向计算一次
                if (isValid(qty) && isValid(price)) {
                    const newAmount = qty * price;
                    if (!isValid(amount) || Math.abs(amount - newAmount) > 0.001) {
                        $amountInput.val(newAmount.toFixed(2));
                    }
                }
                break;
        }
    }
});