抽奖逻辑
这段时间大概做了很多这种类似抽奖的活动!苦逼的我本来是搞前端的!但是由于一些原因换了家公司后!现在前后端都得搞!所以就写一些逻辑性很多,很多的东西
不多扯了 说重点吧!
抽奖逻辑这块大概是这样的。每次抽奖都会从奖品表抽取一个送给用户,这里主要需要考虑到库存不足,和并发的可能。什么是并发呢?就是比如甲,乙两个人同时抽奖,但是商品只剩一个了,但是两个都中奖了,那么我该怎么发放奖品呢?
至于处理这个并发呢?我是通过sql实现的
UPDATE price_table set outnumber = outnumber + 1 , gmt_modified = "${curentTime()}"
WHERE id=${price_id} AND sumnumber > outnumber`
主要就是通过这句sql看它到底执行还是没执行,如果执行了说明那个人真的抽到奖了,如果没有执行就没有抽到奖!所以需要这句sql判断一下他到底真正的抽到奖了!这里最主要的就是后面where条件限制 让他sumnumer>outnumber 奖品总数大于你出奖数量 一旦出奖数量和这个总数相等那么意思库存不足,这句sql就不会执行,这时候在让用户不中奖!
具体抽奖核心代码
这个抽奖的话
通过抽奖表
[{ "sumnumber": 100, "outnumber": 13, "probability": "0.3", "name": "爱奇艺会员180天", "id": 1, "create_date": "2020-07-24T08:29:33.000Z", "update_date": "2020-07-24T11:21:01.000Z", "entity": 0 },
{ "sumnumber": 10, "outnumber": 2, "probability": "0.3", "name": "海贼王手办一套", "id": 2, "create_date": "2020-07-24T08:31:19.000Z", "update_date": "2020-07-24T08:31:19.000Z", "entity": 1 },
{ "sumnumber": 10, "outnumber": 2, "probability": "0.2", "name": "腾讯Q币20元", "id": 3, "create_date": "2020-07-24T08:33:01.000Z", "update_date": "2020-07-24T08:33:01.000Z", "entity": 0 }]
这是奖品数据 这个probability字段是中这个奖品的概率这个是你设置,你想设置多大就多大
以下是核心代码为了方便大家阅读我把他从项目中单独摘了出来
let pricelist = [{ "sumnumber": 100, "outnumber": 13, "probability": "0.3", "name": "爱奇艺会员180天", "id": 1, "create_date": "2020-07-24T08:29:33.000Z", "update_date": "2020-07-24T11:21:01.000Z", "entity": 0 },
{ "sumnumber": 10, "outnumber": 2, "probability": "0.3", "name": "海贼王手办一套", "id": 2, "create_date": "2020-07-24T08:31:19.000Z", "update_date": "2020-07-24T08:31:19.000Z", "entity": 1 },
{ "sumnumber": 10, "outnumber": 2, "probability": "0.2", "name": "腾讯Q币20元", "id": 3, "create_date": "2020-07-24T08:33:01.000Z", "update_date": "2020-07-24T08:33:01.000Z", "entity": 0 }]
// 0.3
// 0.3
// 0.2
let random = Math.random();
let price_id = 0;
let min = 0;
console.log(random);
for (let i = 0; i < pricelist.length; i++) {
if (random > min && random < (min + Number(pricelist[i].probability))) {
console.log('我是上限',min + Number(pricelist[i].probability));
price_id = pricelist[i].id;
break;
} else {
min = min + Number(pricelist[i].probability)
}
}
console.log(price_id);
这是具体详细项目代码 我想很多人 看不懂 因为业务不同嘛 我这里做的是淘宝小程序的云函数开发写的一个后端抽奖接口
'use strict';
/**
* @name 抽奖活动后端接口
* @version 1.0.0
* @author yangjie
* @Time 2020年07月24日14:55:51
*/
const DateFormat = require('dateformat-util')
exports.main = async (ctx) => {
const { mixNick, cloud, userNick } = ctx;
const retObj = {};
// 判断用户是否存在
let user_count = await cloud.dataspace.executeSql(`SELECT * FROM user_table WHERE mixnick = "${mixNick}"`);
//拿到用户id
let user_id = user_count[0].id;
//如果不存在则插入到用户表(由于时区原因插入的时候需要插入东八区时间)
if (user_count.length == 0) {
await cloud.dataspace.executeSql(`INSERT INTO user_table (mixnick,gmt_create,gmt_modified) VALUES ('${mixNick}','${DateFormat.format(new Date(), "yyyy-MM-dd hh:mm:ss")}','${DateFormat.format(new Date(), "yyyy-MM-dd hh:mm:ss")}')`);
}
//如果铭文昵称存在存入铭文昵称
if (userNick) {
await cloud.dataspace.executeSql(`UPDATE user_table SET nickname = "" WHERE user_id = ?`, [user_id]);
}
// // //通过用户id判断用户每天抽奖次数
let pricenumber = await cloud.dataspace.executeSql(`SELECT COUNT(1) AS number FROM luckdraw_table WHERE user_id = ${user_id} AND 'gmt_create' >= "${DateFormat.format(DateFormat.getDateStart(new Date()), "yyyy-MM-dd hh:mm:ss")}"`);
// retObj.pricenumber = pricenumber;
// //如果用户抽奖次数小于3的话可以继续抽奖
if (pricenumber[0].number < 3) {
//插入用户id到抽奖表
let priceid = await cloud.dataspace.executeSql(`INSERT INTO luckdraw_table (user_id,gmt_create,gmt_modified)
VALUES(${user_id},'${DateFormat.format(new Date(), "yyyy-MM-dd hh:mm:ss")}','${DateFormat.format(new Date(), "yyyy-MM-dd hh:mm:ss")}')`);
retObj.priceid = priceid;
// //拿到本次抽奖的id,后面做更新
let pricenumber = priceid.insertId
// // retObj.pricenumber = pricenumber;
//查询是否中过实物奖
let pricestage = await cloud.dataspace.executeSql(`SELECT COUNT(1) as number FROM luckdraw_table AS g LEFT JOIN price_table AS u ON g.Price_id=u.id WHERE u.entity=1 and user_id = ?`, [user_id]);
// retObj.pricestage = pricestage;
let select_user_winprice_sql = "SELECT * FROM price_table WHERE sumnumber>outnumber AND probability > 0 ";
if (pricestage[0].number > 0) {
select_user_winprice_sql += "AND entity=0 ";
}
// 开始抽奖
//确定奖池
let pricelist = await cloud.dataspace.executeSql(select_user_winprice_sql);
let random = Math.random();
let price_id = 0;
let min = 0;
retObj.random = random
// retObj.pricelist = pricelist;
// retObj.pricelisLength = pricelist.length;
// retObj.pricelis1 = pricelist[0].probability
for (let i = 0; i < pricelist.length; i++) {
if (random >= min && random < (min + Number(pricelist[i].probability))) {
price_id = pricelist[i].id;
break;
} else {
min = min + Number(pricelist[i].probability);
}
}
// retObj.price_id = price_id
if (price_id) {
//验证是否真正抽到奖了(更新出奖数量)
let update_price_outnumber_sql = await cloud.dataspace.executeSql(`UPDATE price_table set outnumber = outnumber + 1 , gmt_modified = "${curentTime()}" WHERE id=${price_id} AND sumnumber > outnumber`);
// retObj.op = update_price_outnumber_sql.affectedRows
//如果更新了为1即取反为false 如果没有更新为0 则取反为true
if (!update_price_outnumber_sql.affectedRows) {
price_id = 0
}
}
//重新把抽奖表赋值
await cloud.dataspace.executeSql(`UPDATE luckdraw_table SET price_id = ${price_id} , gmt_modified = "${curentTime()}" WHERE id = ${pricenumber} `);
//获取抽奖详情
if (price_id) {
let select_price_sql = await cloud.dataspace.executeSql(`SELECT * FROM price_table WHERE id =${price_id}`);
retObj.ispricedata = select_price_sql
}
retObj.price_id = price_id
} else {
return await basiCode(7000, retObj);
}
return await basiCode(0, retObj);
};
// 返回值处理
var basiCode = async (code, data) => {
let reobj = {
errCode: 0,
msg: 'ok',
data: data
};
if (code) {
reobj.data = data;
reobj.errCode = code;
switch (code) {
case 7000:
reobj.msg = '抽奖次数不足!';
break;
case 8000:
reobj.data = String(data);
reobj.msg = 'System error!';
break;
default:
reobj.msg = 'other error!';
break;
}
} else {
reobj.data = data;
}
try {
pool.releaseConnection(mysqlConn);
} catch (e) {
console.log(e);
}
return reobj;
};
// 获取东八区时间
var curentTime = function (time) {
var d = time ? new Date(time) : new Date();
var localTime = d.getTime();
var localOffset = d.getTimezoneOffset() * 60000; //获得当地时间偏移的毫秒数
var utc = localTime + localOffset + 3600000 * 8;
var now = new Date(utc);
var year = now.getFullYear(); //年
var month = now.getMonth() + 1; //月
var day = now.getDate(); //日
var hh = now.getHours(); //时
var mm = now.getMinutes(); //分
var ss = now.getSeconds(); //秒
var clock = year + "-";
if (month < 10)
clock += "0";
clock += month + "-";
if (day < 10)
clock += "0";
clock += day + " ";
if (hh < 10)
clock += "0";
clock += hh + ":";
if (mm < 10)
clock += "0";
clock += mm + ":";
if (ss < 10)
clock += "0";
clock += ss;
return (clock);
}