diff --git a/application/api/model/BlindBoxTurntableGift.php b/application/api/model/BlindBoxTurntableGift.php index 3b875ee..0a6e711 100644 --- a/application/api/model/BlindBoxTurntableGift.php +++ b/application/api/model/BlindBoxTurntableGift.php @@ -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