JAVA微信大转盘模块实现

2017-09-06  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读