智能随机分组系统(代码带备注)

现在很多场景下都需要对现有人员进行随机分组,比如老师对班上的同学进行随机分组,以小组形式完成一项作业;再比如公司户外团建活动,对员工进行随机分组,组队玩游戏等等。今天给大家分享的就是一个随机分组案例,用户只需要输入总人数和每组人数,系统就可进行智能随机分组(效果如下图),之所以说智能,是因为该系统具备以下几点智能功能:

  1. 表单输入框非空验证;
  2. 输入框失去焦点时,自动将用户输入的数字进行四舍五入转换,防止用户输入小数;
  3. 单选按钮选择否时,将对最后分组剩余人数进行随机分配到已分配好的小组中,且每个小组人数差不会超过1人;
  4. 当用户输入分组不合理时(即最后分组剩余人数大于分组数时),系统会进行智能分析,并最后给出两个建议分组优化方案!用户可直接选择对应方案,使最终分组合理。比如:

下面献上该案列的全部代码:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Marco智能随机分组系统</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
<style>
    * {
    	margin:0;
    	padding:0;
    }
    html,body {
    	height:100%;
    	background:#3ba;
    }
    input {
    	overflow:hidden;
    }
    label.a {
    	float:left;
    	height:38px;
    	line-height:18px;
    }
    input[type="number"] {
    	width:100px;
    }
    table {
    	margin-top:10px;
    	border:1px solid #ccc;
    	border-collapse:collapse;
    }
    td {
    	text-align:center;
    	border:1px solid #ccc;
    }
    .box {
    	position:absolute;
    	min-width:500px;
    	border:4px solid #fc0;
    	padding:20px;
    	left:50%;
    	transform:translateX(-50%);
    	background:#fff;
    }
    h2 {
    	text-align:center;
    	color:#58bc58;
    	margin-bottom:20px;
    	font-weight:bold;
    }
    .form-group {
    	overflow:hidden;
    }
    .radio {
    	overflow:hidden;
    	margin-bottom:5px;
    }
    .radio .b {
    	float:left;
    	margin-right:10px;
    }
</style>
</head>
<body>
    <div class="box">
        <h2>智能随机分组系统</h2>
        <div class="form-group">
            <label for="total" class="a">请输入总人数:</label>
            <input type="number" class="form-control" id="total" aria-describedby="emailHelp">
        </div>
        <div class="form-group">
            <label for="qty" class="a">请输入每组人数:</label>
            <input type="number" class="form-control" id="qty">
        </div>
        <div class="radio">
            <p class="b">最后一组人数不足时,是否成立一组:</p>
            <div class="custom-control custom-radio b">
                <input type="radio" id="customRadio1" name="single" class="custom-control-input" checked="" value="yes">
                <label class="custom-control-label" for="customRadio1">是</label>
            </div>
            <div class="custom-control custom-radio b">
                <input type="radio" id="customRadio2" name="single" class="custom-control-input" value="no">
                <label class="custom-control-label" for="customRadio2">否</label>
            </div>
        </div>
        <button class="btn btn-outline-success" id="btn">开始分组</button>
        <div id="output"></div>
    </div>
    <script>
        document.addEventListener("DOMContentLoaded", function() {
            $("input.form-control").blur(function(e) {
                $(this).val(Math.round(e.target.value));
            })
            $("#btn").click(function() {
                var total = $('#total').val() * 1;
                var qty = $("#qty").val() * 1;
                var $single = $('input[name=single]');
                var _single;
                $single.each((idx, item) => {
                    if (item.checked) { // 判断剩余人数是否独立生成一组
                        _single = item.value;
                    }
                })
                // 表单验证
                if (total == "") {
                    alert("请输入总人数!")
                    $('#total').focus();
                    return false;
                } else if (qty == "") {
                    alert("请输入每组人数!");
                    $("#qty").focus();
                    return false;
                }
                if (qty > total) {
                    alert("每组人数不能大于总人数!");
                    $("#qty").focus();
                    return false;
                } else {
                    var grounp = _single == "yes" ? Math.ceil(total / qty) : Math.floor(total / qty);
                    if (_single == "no") { // 如果剩余人数不单独生成一组,则需进行以下验证
                        var rem = total % qty;
                        if (rem > grounp) { // 如果剩余人数大于组数
                            // 建议增大人数
                            var adviceMore = qty + parseInt(rem / grounp);
                            // 建议减少人数
                            var adviceLess = qty - 1;
                            var lessGrounp = parseInt(total / adviceLess); //减1后的组数
                            var lessRem = total % adviceLess; // 减1后剩余人数
                            while (lessRem > lessGrounp) { // while 循环直到剩余人数小于组数
                                adviceLess--;
                                lessGrounp = parseInt(total / adviceLess);
                                lessRem = total % adviceLess;
                            }
                            var num = prompt("当前分组方式最后剩余人数" + rem + ",大于分组数" + grounp + ",您可选择: 1、增大每组人数(建议" + adviceMore + "人)或  2、减少每组人数(建议" + adviceLess + "人),以使分组合适!请选择(1或2):")
                            if (num == "1") {
                                $("#qty").val(adviceMore); // 增大人数
                            } else if (num == "2") {
                                $("#qty").val(adviceLess); // 减少人数
                            } else {
                                $("#qty").val(adviceMore);
                                alert("温馨提示:您的选择有误,已默认为您选择方案1!")
                            }
                            return false;
                        }
                    }
                    var total_arr = [];
                    for (var i = 1; i <= total; i++) { // 根据总人数生成总人数编号数组
                        total_arr.push(i);
                    }
                    var arr_big = []; // 用于存放所有分组,结果集
                    for (var i = 1; i <= grounp; i++) { // 遍历分组数
                        var arr_min = []; // 用于存放每个分组的人员编号
                        for (var j = 1; j <= qty; j++) { // 嵌套遍历每个分组的人数
                            if (total_arr.length <= 0) { // 若总人数数组已经被删光,证明已经全部分配完,此时可结束当前循环
                                break;
                            }
                            var randomIdx = parseInt(Math.random() * total_arr.length); // 生成一个 0?总人数 的随机数,用于在总人数数组中随机抽取编号
                            arr_min.push(total_arr[randomIdx]); // 将抽取的编号加入当前所循环的分组
                            total_arr.splice(randomIdx, 1); // 加入后,删除该编号
                        }
                        arr_big.push(arr_min); // 一个小分组添加完毕后,加入结果集
                    }
                    if (total_arr.length > 0) { // 若上面遍历完所有分组后,总人数数组还有编号,则这些编号是剩余人数,应随机分配给以上小分组
                        var randomArr = []; // 定义一个临时数组,用于存放已经有被分配到剩余编号的小分组
                        for (var i = 0; i < total_arr.length; i++) { //遍历剩余人数
                            var randomNum = parseInt(Math.random() * arr_big.length) // 生成一个 0?分组数 的随机数,用于在目前所有小分组中随机抽取一个小分组
                            while (randomArr.includes(randomNum)) { // while循环直到该小分组是没有被分配过剩余编号的
                                randomNum = parseInt(Math.random() * arr_big.length)
                            }
                            randomArr.push(randomNum); // 将分配过剩余编号的小分组记录到临时数组
                            arr_big[randomNum].push(total_arr[i]); // 将当前遍历的剩余编号加入随机筛选出来的小分组
                        }
                    }
                    //写入页面
                    var $table = $('<table class="table table-bordered"></table>');
                    arr_big.forEach((item, idx) => {
                        var $tr = $(`<tr><td scope="row">第${idx+1}组</td></tr>`);
                        item.forEach((item2, idx) => {
                            $tr.append($(`<td scope="row">${item2}</td>`))
                        })
                        $table.append($tr);
                    })
                    $("#output").html('');
                    $table.appendTo("#output");
                }
            })
        })
    </script>
</body>
</html>

主要的js代码我都写了备注说明,相信大家都看得懂,有什么问题欢迎一起探讨!

另外,该案例我在jq插件库发表过,案例地址:http://www.jq22.com/webqd4314,在这里也给大家推荐jq插件库(http://www.jq22.com/)这个网站,非常棒的一个开发资源网站,里面提供了很多的案例、插件、常用代码,你也可以在上面发布你的作品,喜欢开发的你不容错过哦!

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值