巡乐会抽奖接口提交.-盲盒转盘抽奖方法重构。优化查询速度

This commit is contained in:
2025-09-11 20:47:00 +08:00
parent a1d2c4b24f
commit 50140b9339

View File

@@ -144,9 +144,9 @@ class BlindBoxTurntableGift extends Model
// 合并奖池总抽奖次数和房间奖池信息查询
$room_pan_info = db::name("vs_gift_bag_detail")
->alias('a')
->join('vs_room_pan b', 'b.gift_bag_id = a.gift_bag_id AND b.room_id = ' . $room_id)
->join('vs_room_pan b', 'b.gift_bag_detail_id = a.id AND b.room_id = ' . $room_id)
->where(['a.gift_bag_id' => $gift_bag_id])
->field('SUM(a.quantity) as total_quantity, SUM(b.remaining_number) as total_remaining, b.periods')
->field('SUM(a.quantity) as total_quantity, SUM(b.remaining_number) as total_remaining, MAX(b.periods) as periods')
->find();
$total_quantity = $room_pan_info['total_quantity'] ?: 0;
@@ -155,22 +155,54 @@ class BlindBoxTurntableGift extends Model
// 本期当前第多少次后抽奖 总的抽奖次数- 剩余数量
$total_draw_times = $total_quantity - $total_remaining;
if($total_draw_times<0){
$total_draw_times = 0;
}
// 预计算所有抽奖结果
$precomputed_results = [];
$current_draw_times = $total_draw_times;
$current_periods = $periods;
$current_xlh_periods_num = $this_xlh_periods_num;
// 生成缓存键
$available_cache_key = 'blindbox_available_gifts_' . $gift_bag_id . '_' . $room_id;
$last_remaining_cache_key = 'blindbox_last_remaining_' . $gift_bag_id . '_' . $room_id;
// 获取所有可用礼物用于预计算
$available_gifts = $this->get_available_gifts_for_precompute($gift_bag_id, $room_id, $current_draw_times);
if (empty($available_gifts)) {
return ['code' => 0, 'msg' => '当前盲盒无可用礼物', 'data' => null];
}
// 预计算所有抽奖结果
$should_reset_all_gifts = false; // 标记是否需要重置所有礼物
//如果本期奖池数量小于抽奖次数,则重置奖池,并把上期剩余数量加到本期奖池中
//接收礼物人数
$receive_num = count($toarray);
//需要的礼物数量
$need_gift_num = $receive_num * $num;
$last_periods_remaining = [];
if ($total_remaining < $need_gift_num) {
//上期剩余礼物
$last_periods_remaining = $available_gifts;
//加入缓存
cache($last_remaining_cache_key, $last_periods_remaining);
// 重置奖池
$current_periods++;
$this->reset_gift_pool($room_id, $gift_bag_id, $current_periods);
//补充上期剩余数量
foreach ($available_gifts as $gift_data) {
db::name("vs_room_pan")
->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id,'gift_bag_detail_id'=>$gift_data['id']])
->setInc('remaining_number', $gift_data['remaining_number']);
}
// 重新获取可用礼物
$current_draw_times = 0;
$available_gifts = $this->get_available_gifts_for_precompute($gift_bag_id, $room_id, $current_draw_times);
$should_reset_all_gifts = false; // 重置标记
}
//加入缓存
cache($available_cache_key, $available_gifts);
// 预计算所有抽奖结果
foreach ($toarray as $gift_user_id) {
if($user_id == $gift_user_id){
return ['code' => 0, 'msg' => "收礼人不能包含自己", 'data' => null];
@@ -178,7 +210,14 @@ class BlindBoxTurntableGift extends Model
for($i = 0; $i < $num; $i++){
// 使用加权随机算法预计算单次抽奖结果
$draw_result = $this->precompute_single_draw($available_gifts);
//从缓存中取出可用礼物
if(cache($available_cache_key)){
$available_gifts = cache($available_cache_key);
}
if(cache($last_remaining_cache_key)){
$last_periods_remaining = cache($last_remaining_cache_key);
}
$draw_result = $this->precompute_single_draw($gift_bag_id,$room_id,$available_gifts,$last_periods_remaining);
if (!$draw_result) {
return ['code' => 0, 'msg' => '预计算抽奖失败', 'data' => null];
@@ -221,6 +260,9 @@ class BlindBoxTurntableGift extends Model
}
}
}
// 清除相关缓存
cache($available_cache_key, null);
cache($last_remaining_cache_key, null);
// 开始数据库事务处理
db::startTrans();
@@ -315,17 +357,7 @@ class BlindBoxTurntableGift extends Model
// 处理奖池重置操作
if ($should_reset_all_gifts) {
// 重置奖池中所有礼物数量
db::name("vs_room_pan")
->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])
->update([
'remaining_number' => db::raw('(SELECT quantity FROM fa_vs_gift_bag_detail WHERE id = fa_vs_room_pan.gift_bag_detail_id)'),
'periods' => $current_periods
]);
// 更新总期数
db::name("vs_gift_bag")
->where('id', $gift_bag_id)
->setInc('periods');
$this->reset_gift_pool($room_id, $gift_bag_id, $current_periods);
}
// 批量插入盲盒转盘结果记录
@@ -370,7 +402,7 @@ class BlindBoxTurntableGift extends Model
$xlh = [];
if(!empty($xlh_ext) && $xlh_ext['inlet_bag_id'] == $gift_bag_id){
// 巡乐会飘屏
db::name("vs_room")->where('id',$room_id)->setInc('xlh_periods_num',$num);//加巡乐会条件次数
db::name("vs_room")->where('id',$room_id)->setInc('xlh_periods_num',$current_xlh_periods_num);//加巡乐会条件次数
if($xlh_is_piao_ping == 1){
// 即将开始推送飘屏
$text = $room['room_name']."的巡乐会即将开始,请大家尽快参与哦!";
@@ -445,6 +477,27 @@ class BlindBoxTurntableGift extends Model
return V(1,"成功", $reslut);
}
/**
* 重置奖池
* @param int $room_id 房间ID
* @param int $gift_bag_id 礼物包ID
* @param int $periods 期数
*/
private function reset_gift_pool($room_id, $gift_bag_id, $periods) {
// 重置奖池中所有礼物数量
db::name("vs_room_pan")
->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])
->update([
'remaining_number' => db::raw('(SELECT quantity FROM fa_vs_gift_bag_detail WHERE id = fa_vs_room_pan.gift_bag_detail_id)'),
'periods' => $periods
]);
// 更新总期数
db::name("vs_gift_bag")
->where('id', $gift_bag_id)
->setInc('periods');
}
/*
* 获取可用礼物用于预计算
*/
@@ -468,11 +521,24 @@ class BlindBoxTurntableGift extends Model
/*
* 预计算单次抽奖结果
*/
private function precompute_single_draw($available_gifts) {
private function precompute_single_draw($gift_bag_id,$room_id,$available_gifts,$last_periods_remaining=[]) {
// 生成缓存键
$available_cache_key = 'blindbox_available_gifts_' . $gift_bag_id . '_' . $room_id;
$last_remaining_cache_key = 'blindbox_last_remaining_' . $gift_bag_id . '_' . $room_id;
if (empty($available_gifts)) {
return false;
}
$last_remaining_all = array_sum(array_column($last_periods_remaining, 'remaining_number'));
if($last_remaining_all == 0){
$last_periods_remaining = [];
cache($last_remaining_cache_key, null);
}
$last_periods_remaining_flag = 0;
if(!empty($last_periods_remaining)){
$available_gifts = $last_periods_remaining;
//操作上期奖池标识
$last_periods_remaining_flag = 1;
}
// 实现加权随机算法:剩余数量越多,被抽中的概率越大
$remaining = 0;
foreach ($available_gifts as $gift) {
@@ -504,6 +570,23 @@ class BlindBoxTurntableGift extends Model
if (!$gift) {
return false;
}
//操作缓存,减去缓存中对应数据数量
foreach ($available_gifts as &$available_gifts_gift) {
if($selected_gift['id'] == $available_gifts_gift['id']){
$available_gifts_gift['remaining_number'] -= 1;
}
}
if($available_gifts_gift['remaining_number'] == 0){
unset($available_gifts_gift);
}
if($last_periods_remaining_flag == 1){
//操作上一轮奖池
cache($last_remaining_cache_key,$available_gifts);
}else{
cache($available_cache_key,$available_gifts);
}
return [
'gift_bag_detail' => $selected_gift,
'gift' => $gift