美文网首页
JAVA微信大转盘模块实现

JAVA微信大转盘模块实现

作者: 薪火设计 | 来源:发表于2017-09-06 19:58 被阅读632次

    简介

    最近闲的无聊,将以前做的一个微信抽奖小demo拿来分享一下,以便加深印象。

    效果图

    1.gif

    业务要求

    在一个奖池中放一堆奖品,分别给它们设置不同的数量,比如一等奖A10个,二等奖B,30个,三等奖C10个,然后设置参与人数C人
    条件是:
    当奖品数大于参与人数,100%中奖。
    当奖品A发放完是,不能被抽中。
    当奖品发放完毕是,该抽奖活动自动下架。
    同一个用户如果中奖了,将不能继续参与该活动。
    这里只讨论下其中的核心算法的设计及一个示例函数,算法之外的系统控制暂不提及。
    实现抽奖的方法应该有很多,没有仔细去考察和搜索那些非常复杂的算法,这里仅做了一个简单的假设,并在此基础上推出后面所有的控制逻辑。

    实现方法

    java核心抽奖代码如下:

    public class LotteryUtil {
        /**
         * 
         * @param orignalRates  传人每一个奖品概率的集合,(集合的第一个参数是0.0 表示百分比中奖)
         * @return
         */
        public static int lottery(List<Double> orignalRates) {
            if (orignalRates == null || orignalRates.isEmpty()) {
                return -1;
            }
            int size = orignalRates.size();
            // 计算总概率,这样可以保证不一定总概率是1
            double sumRate = 0d;
            for (double rate : orignalRates) {
                sumRate += rate;
            }
            // 计算每个物品在总概率的基础下的概率情况
            List<Double> sortOrignalRates = new ArrayList<Double>(size);
            Double tempSumRate = 0d;
            /*遍历奖品概率的集合,计算每一个奖品的中间区间*/
            for (double rate : orignalRates) {
                tempSumRate += rate;
                sortOrignalRates.add(tempSumRate/sumRate);
            }
            // 根据区块值来获取抽取到的物品索引
            double nextDouble = Math.random();
            sortOrignalRates.add(nextDouble);
            Collections.sort(sortOrignalRates);
            return sortOrignalRates.indexOf(nextDouble);
        }
    }
    

    抽奖的业务逻辑代码如下

        /*awardItems获取奖品的一个集合*/
        if (activityUserDao.getCountByOpenId(Award.WHEEL_AWARD_TYPE, wid, open_id) <= 0) {
                                            /* awardItems获取奖品的一个集合 */
                                            List<Award> awardItems = awardDao.getByActivity(aw.getWheel_id(), Award.WHEEL_AWARD_TYPE);
                                            /* lotterys存放每一个奖品的中奖概率集合 */
                                            List<Double> lotterys = new ArrayList<Double>();
                                            /* 获取总的奖品数量 */
                                            int count = 0;
                                            for (Award a : awardItems) {
                                                count += a.getProvide_count();
                                            }
                                            if (aw.getPeople_count() <= count) {
                                                lotterys.add(0.0); // 100%中奖
                                            } else {
                                                /* 预计参与人数减去奖品数 除以参与人数 = 未中奖概率 */
                                                lotterys.add((double) (aw.getPeople_count() - count) / (double) aw.getPeople_count());
                                            }
                                            /* 遍历奖品集合,获取每一个奖品中奖概率 */
                                            for (Award a : awardItems) {
                                                if (a.getOver_count() > 0) {
                                                    lotterys.add((double) a.getProvide_count() / (double) aw.getPeople_count());
                                                } else {
                                                    lotterys.add(0.0);
                                                }
                                            }
                                            // 计算中奖概率
                                            int index = LotteryUtil.lottery(lotterys);
                                            if (index > 0) {// 中奖
                                                Award a = awardItems.get(index - 1);
                                                long key = Math.round(Math.random() * (999999 - 100000) + 100000); // 6位数中奖序列号
                                                // 修改商品剩余数量 + 记录序列号
                                                if (awardDao.doLowerOverCount(a.getAward_id()) > 0
                                                        && activityUserDao.doInsert(new ActivityUser(aw.getPublic_id(), Award.WHEEL_AWARD_TYPE, wid, a.getAward_id(), key + "", open_id)) > 0) {
                                                    rb.setCode(index);
                                                    rb.setData(key);
                                                    rb.setMessage(a.getAward_name());
                                                } else {
                                                    rb.setCode(0);
                                                }
                                            }
                                            // 抽奖记录
                                            activityRecordDao.doInsert(new ActivityRecord(open_id, Award.WHEEL_AWARD_TYPE, wid, request.getRemoteAddr()));                              
    

    前端抽奖工具类

    /**
     * 注意:本插件运用了rem屏幕适配方案,一律采用rem作为单位,若项目中不是采用这种方案的,此段代码不会影响功能使用,仅会影响控件样式
     */
    
    (function(win, doc, $) {
    
        var defaultOpt = {
    
            rotateNum: 5, //转盘转动圈数
            body: "", //大转盘整体的选择符或zepto对象
    
            disabledHandler: function() {}, //禁止抽奖时回调
    
            clickCallback: function() {}, //点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面
    
            KinerLotteryHandler: function(deg) {} //抽奖结束回调
    
        };
    
        function KinerLottery(opts) {
    
            this.opts = $.extend(true, {}, defaultOpt, opts);
    
            this.doing = false;
    
            this.init();
    
        }
    
        KinerLottery.prototype.setOpts = function(opts) {
    
            this.opts = $.extend(true, {}, defaultOpt, opts);
    
            this.init();
    
        };
    
        KinerLottery.prototype.init = function() {
    
            var self = this;
    
            this.defNum = this.opts.rotateNum * 360; //转盘需要转动的角度
            // console.log(this.defNum);
    
            // alert(this.defNum);
    
            //点击抽奖
            $('#box').on('click', ".KinerLotteryBtn", function() {
                if($(this).hasClass('start') && !self.doing) {
                    self.opts.clickCallback.call(self);
                } else {
    
                    var key = $(this).hasClass('no_start') ? "noStart" : $(this).hasClass('completed') ? "completed" : "illegal";
    
                    self.opts.disabledHandler(key);
    
                }
    
            });
    
            $(this.opts.body).find('.KinerLotteryContent').get(0).addEventListener('webkitTransitionEnd', function() {
    
                self.doing = false;
    
                var deg = $(self.opts.body).attr('data-deg');
    
                if(self.opts.direction == 0) {
                    $(self.opts.body).attr('data-deg', 360 - deg);
                    $(self.opts.body).find('.KinerLotteryContent').css({
                        '-webkit-transition': 'none',
                        'transition': 'none',
                        '-webkit-transform': 'rotate(' + (deg) + 'deg)',
                        'transform': 'rotate(' + (deg) + 'deg)'
                    });
                    self.opts.KinerLotteryHandler(360 - deg);
                } else {
                    $(self.opts.body).attr('data-deg', deg);
                    $(self.opts.body).find('.KinerLotteryContent').css({
                        '-webkit-transition': 'none',
                        'transition': 'none',
                        '-webkit-transform': 'rotate(' + (-deg) + 'deg)',
                        'transform': 'rotate(' + (-deg) + 'deg)'
                    });
                    self.opts.KinerLotteryHandler(deg);
                }
    
            });
    
        };
        KinerLottery.prototype.goKinerLottery = function(_deg) {
            if(this.doing) {
                return;
            }
            var deg = _deg + this.defNum;
            var realDeg = this.opts.direction == 0 ? deg : -deg;
            this.doing = true;
            $(this.opts.body).find('.KinerLotteryBtn').addClass('doing');
    
            $(this.opts.body).find('.KinerLotteryContent').css({
                '-webkit-transition': 'all 5s',
                'transition': 'all 5s',
                '-webkit-transform': 'rotate(' + (realDeg) + 'deg)',
                'transform': 'rotate(' + (realDeg) + 'deg)'
            });
            $(this.opts.body).attr('data-deg', _deg);
        };
        win.KinerLottery = KinerLottery;
    })(window, document, $);
    

    前端js调用抽奖类

    /**
     * @author wjb
     * @description 
     * @version 1.0.0 2017/2/11
     */
    app.controller("wheelOneController", ['$scope', '$stateParams', '$neu_', 'awardService', '$filter', '$timeout', 'util.alert', 'cfg', 'wxService', function($scope, $stateParams, $neu_, awardService, $filter, $timeout, alert, cfg, wxService) {
        /*中奖开始时间*/
        $scope.wheelStatu = {
                start: true,
                noStart: false,
                completed: false
            }
            /*错误信息提示*/
        $scope.errorMsg = "";
        /*定义奖品数据变量*/
        $scope.awards = [];
        /*活动的id和活动的微信公众号ID*/
        var activity_id = $neu_.isEmpty($stateParams.activity_id) ? 1 : $stateParams.activity_id;
        var public_id = $neu_.isEmpty($stateParams.public_id) ? 1 : $stateParams.public_id;
        var open_id = $neu_.isEmpty($stateParams.open_id) ? cfg.openId : $stateParams.open_id;
        cfg.public_id = public_id;
        cfg.open_id = open_id;
        cfg.activity_id = activity_id;
        //alert(cfg.public_id+"=="+cfg.activity_id+"=="+cfg.open_id );
        /*获取活动信息*/
        wxService.setConfig();
        awardService.getWheelInfo(activity_id, public_id).then(function(res) {
            //console.dir(res)
            if(res.success) {
                $scope.wheelStatu.start = true;
            } else {
                if(res.code == 1 || res.code == 3) {
                    $scope.wheelStatu.noStart = true;
                } else if(res.code == 2) {
                    $scope.wheelStatu.completed = true;
                }
                $scope.errorMsg = res.msg;
            }
            $scope.wheelInfo = res.data;
        });
        awardService.getAwards(activity_id, public_id).then(function(res) {
            $scope.awards = res.data;
        });
        /*奖品预览*/
        var result = [];
        $scope.showPic = function(pic) {
                if(result.length == 0) {
                    $neu_.each($scope.awards, function(item) {
                        result.push(cfg.resourcePath + item.img);
                    });
                }
                wxService.previewImage(cfg.resourcePath + pic, result);
            }
            /*中奖结果集*/
        $scope.result = [];
        $scope.user = {
            user_name: '',
            phone: '',
            activity_id: activity_id,
            user_openid: open_id
        };
        /**
         * 提交中奖人信息
         */
        $scope.submit = function() {
                $(".actBody_close").click();
                $scope.isLoading = true;
                awardService.updateLotteryUser($scope.user).then(function(res) {
                        $scope.isLoading = false;
                        if(res.success) {
                            alert('您的中奖信息已备案,我们的客服人员稍后会联系您,如何领取奖品');
                        } else {
                            alert('提交失败');
                        }
                    })
                    //alert('哈哈上当了吧^_^_^_^')
            }
        $scope.load = function() {
            $timeout(function() {
                ActBounced();
                $("#layer").hide();
                new KinerLottery({
                    rotateNum: 5, //转盘转动圈数
                    body: "#box", //大转盘整体的选择符或zepto对象
                    direction: 0, //0为顺时针转动,1为逆时针转动
                    disabledHandler: function(key) {
                        switch(key) {
                            case "noStart":
                                $scope.$apply(function() {
                                    alert($scope.errorMsg);
    
                                });
                                break;
                            case "completed":
                                $scope.$apply(function() {
                                    alert($scope.errorMsg);
                                });
                                break;
                        }
                    }, //禁止抽奖时回调
                    clickCallback: function() {
                        var this_ = this;
                        //此处访问接口获取奖品
                        $scope.isLoading = true;
                        awardService.startAweel(activity_id, open_id).then(function(res) {
                            $scope.isLoading = false;
                            if(isDebug){
                                this_.goKinerLottery(0);
                            }else{
                                if(res.success) {
                                var index = cfg.isDebug ? Math.floor(Math.random() * 5) : res.code;
                                $scope.result = $filter('awardToAngle')(index, $scope.awards);
                                if(index == 0) {
                                    this_.opts.disabledHandler("noStart");
                                } else {
                                    this_.goKinerLottery($scope.result[1]);
                                }
                            } else {
                                alert(res.msg);
                            }
                            }
                        })
                    }, //点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面
                    KinerLotteryHandler: function(deg) {
                        $("#smallActAdv").click();
                    }
                });
    
            }, 500);
            /*分享授权的地址*/
            $timeout(function(){
            var share ={shareUrl:"weixin/oauth.html?isBase=true&type=6&a_id="+activity_id+"&p_id="+public_id+"&appid="+cfg.appId};
            wxService.onMenuShareAppMessage(share);
            },3000)
        }
    }])
    

    以上是抽奖的主要代码,如果需要以上代码的联系本人qq:771534408

    相关文章

      网友评论

          本文标题:JAVA微信大转盘模块实现

          本文链接:https://www.haomeiwen.com/subject/quqejxtx.html