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

基于同组输入值汇总jQuery Repeater输入值的问题

问题描述

我有一个页面,需要通过4个主输入框汇总jQuery Repeater中特定字段的总计。Repeater用于为项目分配员工及其费用比例,项目可分配1至多名员工,每位员工被分配Role #1至Role #4中的一个角色及对应费用百分比,同一角色可分配多名员工。提交表单前,需确保同一角色下所有员工的费用百分比总和为100%,未分配的角色总和可为0。目前编写的代码无法实现该功能,连Role 1的费用汇总都失败了,寻求解决方案。

解决方案

原代码问题分析

  1. 选择器错误:用$("#empFees")选择重复项,但empFees是类名而非ID,应改为.empFees;事件监听目标错误,需监听费用输入框和角色选择框的变化。
  2. 汇总逻辑缺失角色区分:原代码只是累加所有费用,没有按角色分类计算总和。
  3. 事件覆盖不全:未处理重复项添加/删除后的汇总更新,也没监听角色切换的变化。
  4. 重复赋值问题:在循环内重复给总计框赋值,应在循环结束后统一赋值。

修正后的完整代码

<!-- 角色费用总计展示区域 -->
<div class="row">
    <div class="input-group-text">Role 1 %</div><input id="TotalR1_Percentage" disabled>
    <div class="input-group-text">Role 2 %</div><input id="TotalR2_Percentage" disabled>
    <div class="input-group-text">Role 3 %</div><input id="TotalR3_Percentage" disabled>
    <div class="input-group-text">Role 4 %</div><input id="TotalR4_Percentage" disabled>
</div>

<!-- 员工分配重复器区域 -->
<div data-repeater-list="team">
    <div data-repeater-item class="row empFees" name="empFees">
        <label for="team_members" class="form-label">Team Member:</label>
        <select name="team_member" class="form-select" required>
            <option value="">Select Employee ...</option>
            @ForEach (item In eList) {
            <option value="@item.Value">@item.Text</option>
            }
        </select>

        <label class="form-label">Project Role:</label>
        <select name="proj_role" class="form-select" required>
            <option value="">Select Role ...</option>
            @ForEach (item In rList) {
            <option value="@item.Value">@item.Text</option>
            }
        </select>

        <label class="form-label">Fee:</label>
        <div class="input-group">
            <div class="input-group-text">%</div><input class="feeAllocation" type="number" min="0" max="100" required>
        </div>
        <button data-repeater-delete type="button">Remove Assignment</button>
    </div>
</div>
<button data-repeater-create type="button">Add Assignment</button>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.min.js"></script>
<script>
    $(document).ready(function () {
        "use strict";

        // 初始化jQuery Repeater
        $('[data-repeater-list="team"]').repeater({
            initEmpty: false,
            show: function() {
                $(this).slideDown();
                // 添加新项后更新总计
                updateRoleTotals();
            },
            hide: function(deleteElement) {
                if(confirm('确定要删除此分配吗?')) {
                    $(this).slideUp(deleteElement);
                    // 删除项后更新总计
                    setTimeout(updateRoleTotals, 300);
                }
            }
        });

        // 更新各角色费用总计的函数
        function updateRoleTotals() {
            let totals = { R1: 0, R2: 0, R3: 0, R4: 0 };

            // 遍历所有重复项
            $('.empFees').each(function() {
                const role = $(this).find('select[name="proj_role"]').val();
                const fee = parseFloat($(this).find('.feeAllocation').val()) || 0;

                // 根据角色分类累加费用(需与下拉框value值匹配,若value是数字则改为case '1'这类)
                switch(role) {
                    case 'Role 1':
                        totals.R1 += fee;
                        break;
                    case 'Role 2':
                        totals.R2 += fee;
                        break;
                    case 'Role 3':
                        totals.R3 += fee;
                        break;
                    case 'Role 4':
                        totals.R4 += fee;
                        break;
                }
            });

            // 更新总计输入框的值,保留两位小数
            $('#TotalR1_Percentage').val(totals.R1.toFixed(2));
            $('#TotalR2_Percentage').val(totals.R2.toFixed(2));
            $('#TotalR3_Percentage').val(totals.R3.toFixed(2));
            $('#TotalR4_Percentage').val(totals.R4.toFixed(2));
        }

        // 监听费用输入框和角色选择框的变化,实时更新总计
        $(document).on('input change', '.feeAllocation, select[name="proj_role"]', function() {
            updateRoleTotals();
        });

        // 表单提交验证:确保已分配的角色费用总和为100%
        $('form').on('submit', function(e) {
            let isValid = true;
            let assignedRoles = new Set();

            // 收集所有已分配的角色
            $('.empFees').each(function() {
                const role = $(this).find('select[name="proj_role"]').val();
                if(role) assignedRoles.add(role);
            });

            // 验证每个已分配角色的总和是否为100%(允许微小浮点误差)
            assignedRoles.forEach(role => {
                let sum = 0;
                $('.empFees').each(function() {
                    if($(this).find('select[name="proj_role"]').val() === role) {
                        sum += parseFloat($(this).find('.feeAllocation').val()) || 0;
                    }
                });

                if(Math.abs(sum - 100) > 0.01) {
                    alert(`角色 ${role} 的费用总和必须为100%,当前总和为${sum.toFixed(2)}%`);
                    isValid = false;
                }
            });

            if(!isValid) e.preventDefault(); // 验证不通过则阻止表单提交
        });

        // 页面加载时初始化总计
        updateRoleTotals();
    });
</script>

关键说明

  1. 重复器初始化:正确调用jquery.repeater插件,在添加/删除项后自动触发总计更新。
  2. 分类汇总逻辑:通过switch语句按角色分类累加费用,确保每个角色的总和计算准确。
  3. 事件监听优化:监听费用输入框的input事件和角色选择框的change事件,实现实时更新。
  4. 表单验证逻辑:提交前检查所有已分配角色的费用总和是否为100%,未分配角色无需验证,同时处理浮点精度问题。
  5. 元素选择规范:移除重复项中的重复ID,统一使用类名和name属性选择元素,避免DOM选择冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:45:29