年底降至,各類年會都需用到抽獎,最近剛好寫了一個抽獎程序,總結一下,也為了方便日后溫故,也可給諸位一個開箱即用的抽獎demo參考
demo演示鏈接
先睹為快,傳送門
完整代碼地址
流程圖
說明
- 公平抽獎,沒有暗箱操作,代碼通過功能測試、壓測,經過多人review,可放心開箱即用。
- 這個抽獎程序是上周公司抽獎實際使用的,但是代碼我隱去了跟公司相關的信息,所以UI上效果基本沒有,但只要稍作修改,如設計一張背景圖即可。
- 分辨率1920*1080效果最佳,但需考慮實際使用地方的屏幕設備
- 有抽獎中、中獎兩個音樂,需要連接音頻效果更佳
- 獎品信息可以配置,一次抽獎可以分若干小次進行,這里抽獎暫時只按1桌/1次來,原因:刪除/放回這里需要優化一下
- 中獎后會將中獎人名單以及獎品信息寫入中獎記錄表,有頁面可查看,方便后面兌獎
- 暫時只放出抽桌號的代碼,其實將桌號的圖片換成員工頭像效果會更好,原還有一個簽到頁面,可簽到的人提前錄入了user表,只有簽到的人才在獎池中,這里還有一個nestjs寫的后台,代碼暫時沒有放出來,可以私聊溝通。流程可以參考
核心代碼
關鍵節點有相應注釋,請仔細閱讀,歡迎指正不足
//生成從minNum到maxNum的隨機數
randomNum(minNum, maxNum){
return parseInt(Math.random()* (maxNum - minNum + 1) + minNum);
},
//獎頭像動起來
doMove(start, end) {
console.log('start, end', start, end );
this.setIntervalFun = setInterval(() => {
for(let i = start; i < end; i ++ ) {
this.$set(this.currentPrizeUsers, i, this.keepNoRepeat(this.currentPrizeUsers, this.moveUsers));
}
}, 80)
},
//保證數字不重復
keepNoRepeat(currentPrizeUsers, userNoPrize) {
let user = userNoPrize[this.randomNum(0, userNoPrize.length)];
//由於分多小次抽獎,抽獎完成后獎池人數才變化,所以可能存在取值越界
if(!user) {
return this.keepNoRepeat(currentPrizeUsers, userNoPrize);
}
if(currentPrizeUsers.filter(item => item.userid == user.userid).length > 0) {
return this.keepNoRepeat(currentPrizeUsers, userNoPrize);
}else {
return user;
}
},
//停/繼續/完成點擊
handlePrizeClick: throttle(function() {
//單次抽獎的最后一小次暫停
if(this.movePrizeNum == this.currentPrizeInfo.count) {
this.choujiangId.pause();
this.zhongjiangId.play();
clearInterval(this.setIntervalFun);
this.movePrizeStatus = 2;
this.movePrizeNum += 1;
this.doPrize(this.currentPrizeUsers.filter(item => item.userid).map(item => item.userid).join(','));
return;
}
if(this.movePrizeStatus == 2) {//顯示狀態-完成抽獎
this.choujiangId.pause();
this.zhongjiangId.pause();
this.dialogTableVisible = false;
this.movePrizeStatus = 0;
}else if(this.movePrizeStatus == 3) {//再次啟動
this.choujiangId.play();
this.zhongjiangId.pause();
this.movePrizeStatus = 1;
this.doMove(this.movePrizeNum * this.currentPrizeInfo.everytime, this.currentPrizeInfo.everytime * (this.movePrizeNum + 1) );
this.movePrizeNum += 1;
}else if(this.movePrizeStatus == 1) {//暫停
this.choujiangId.pause();
this.zhongjiangId.play();
clearInterval(this.setIntervalFun);
this.movePrizeStatus = 3;
this.doPrize(this.currentPrizeUsers.filter(item => item.userid).map(item => item.userid).join(','));
}
}, 1000),
//洗牌
randomUser() {
let randomUser = setInterval(() => {
this.moveUsers = this.moveUsers.sort((a, b) => Math.random() > .5 ? -1 : 1);
}, 100)
setTimeout(() => {
clearInterval(randomUser);
}, 2000);
}
迭代思路(不足之處)
- 配置獎品信息應更豐富,單獨做一個后台配置頁面,支持配置獎品圖片、抽獎個數、次數、音樂等等
- 將獎品配置信息用數據表管理,而不是json
- 抽獎歷史記錄應可以回看,可以刪除(作廢),同時刪除中獎記錄表
- 如果獎池人數足夠多(1w人以上),可能有性能問題,前端循環可以持續優化
- 添加登錄/接口權限控制
后續考慮
- 空格鍵按暫停可能會更好操作,但是聲控呢?
- 洗牌效果做得更炫酷一些