From bbb3f85fee16f7a5c493c38a218c0abda607491d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E9=92=8A?= Date: Tue, 28 Oct 2025 18:07:28 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=B2=E7=9B=92=E8=BD=AC=E7=9B=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96-=E9=87=8D=E6=9E=84-=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/BlindBoxTurntable.php | 2 +- .../BlindBoxTurntableGiftDrawWorldNew.php | 376 +++++++++++++++++- application/cron/controller/RoomPan.php | 2 +- 3 files changed, 372 insertions(+), 8 deletions(-) diff --git a/application/api/controller/BlindBoxTurntable.php b/application/api/controller/BlindBoxTurntable.php index c86658a..a40a692 100644 --- a/application/api/controller/BlindBoxTurntable.php +++ b/application/api/controller/BlindBoxTurntable.php @@ -93,7 +93,7 @@ class BlindBoxTurntable extends BaseCom $user_id = $this->uid; $room_id = input('room_id',0); $num = input('num',1); - $reslut = model('BlindBoxTurntableGiftDrawWorld')->xlh_draw_gift($user_id,$num,$room_id); + $reslut = model('BlindBoxTurntableGiftDrawWorldNew')->xlh_draw_gift($user_id,$num,$room_id); return v($reslut['code'], $reslut['msg'], $reslut['data']); } /* diff --git a/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php index 371059e..6f09ebb 100644 --- a/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php +++ b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php @@ -123,7 +123,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id); //总抽奖次数 $pan_total_remaining = $this->getCachedPanTotalRemaining($gift_bag_id); //剩余数量 //获取可用礼物 - $availableGifts = $this->getAvailableGifts($gift_bag_id,$pan_total_draw_times); + $availableGifts = $this->getAvailableGifts($gift_bag_id,$pan_total_draw_times+$total_num); $giftInfoMap = cache::get("pan_gift_info_map".$gift_bag_id); //预加载礼物信息 $remaining_available_gifts = []; if (empty($availableGifts) ||$pan_total_remaining ==0) { @@ -173,7 +173,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model 'gift_user_id' => $giftUserId, 'gift_bag_detail' => $selectedGift, 'gift' => $gift, - 'draw_times' => $pan_total_draw_times, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), 'periods' => $periods, ]; $this->getCachedXlhPeriodsNum("set");//添加寻乐会条件次数 @@ -181,7 +181,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model } } } - Cache::set("pan_total_draw".$gift_bag_id, 0, $this->cache_time); + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"clear");//总抽奖次数重置 } // 再从新奖池中分配剩余所需礼物 if ($newGiftsNeeded > 0 && !empty($availableGifts)) { @@ -203,14 +203,14 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model 'gift_user_id' => $giftUserId, 'gift_bag_detail' => $selectedGift, 'gift' => $gift, - 'draw_times' => $pan_total_draw_times, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), 'periods' => $periods, ]; $precomputedResultss[] = [ 'gift_user_id' => $giftUserId, 'gift_bag_detail' => $selectedGift, 'gift' => $gift, - 'draw_times' => $pan_total_draw_times, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), 'periods' => $periods, ]; @@ -936,4 +936,368 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model ] ]; } -} + +/* + * 巡乐会抽奖----------------------------------------------------------------------------------------- + */ + /* + * 巡乐会抽奖(优化版) + */ + public function xlh_draw_gift($user_id, $num, $room_id) + { + $gift_bag_id = 13; + // 1. 获取并缓存盲盒配置 + $ext = $this->getCachedGiftBag($gift_bag_id); //获取转盘信息 + $bag_gift_price = $ext['xlh_box_price'] * $num; + // 3. 检查巡乐会状态 + $pan_xlh = db::name('vs_room_pan_xlh') + ->where(['send_time' => 0]) + ->order('id', 'desc') + ->find(); + if (empty($pan_xlh)) { + return ['code' => 0, 'msg' => '本轮未开始', 'data' => null]; + } + if ($pan_xlh['end_time'] <= time()) { + return ['code' => 0, 'msg' => '本轮已结束', 'data' => null]; + } + + // 6. 预计算抽奖结果 + $drawn_gifts = []; // 用于统计抽中结果 + $main_prize_updates = []; // 用于记录主奖品更新 + $is_zhong_jiang = 0; + + + // 批量处理配置 + $batch_size = min(10, $num); // 每批次处理10次 + $total_processed = 0; + $all_results = []; // 存储所有抽奖结果 + try { + db::startTrans(); + while ($total_processed < $num) { + $current_batch = min($batch_size, $num - $total_processed); // 当前批次处理数量 + // 批量扣除金币(只在第一次事务中处理) + if ($total_processed == 0) { + $user_waller = db::name('user_wallet')->where(['user_id' => $user_id])->find(); + if (!$user_waller || $user_waller['coin'] < $bag_gift_price) { + return ['code' => 0, 'msg' => '用户金币不足', 'data' => null]; + } + $wallet_update = model('GiveGift')->change_user_cion_or_earnings_log( + $user_id, + $bag_gift_price, + $room_id, + 1, + 10, + $ext['gift_bag_name'].'抽奖消耗' + ); + if (!$wallet_update) { + throw new \Exception('扣除用户金币失败'); + } + + $user_level = model('Level')->user_level_data_update( + $user_id, + $bag_gift_price, + 1, + $room_id + ); + if (!$user_level) { + throw new \Exception('用户等级更新失败'); + } + } + + // 处理当前批次的抽奖 + $inventory_updates = []; // 用于记录库存变化 + for ($i = 0; $i < $current_batch; $i++) { + $total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id) ?? 0; //已抽奖次数 + $availableGifts = $this->getAvailableGifts($gift_bag_id,$total_draw_times); //获取可用礼物 + if (empty($availableGifts)) { + $availableGifts = $this->resetPoolAndReload($gift_bag_id); + if (empty($availableGifts)) { + throw new \Exception('重置奖池后仍无可用礼物'); + } + } + // 从可用礼物中选择 + $selected_gift = $this->selectGiftFromAvailable($availableGifts); + if (!$selected_gift) { + $gift_bag_detail = $this->resetPoolAndReload($gift_bag_id); + $selected_gift = $this->selectGiftFromAvailable($gift_bag_detail); + if(!$selected_gift){ + throw new \Exception('预计算抽奖失败,重置后无可用礼物'); + } + } + // 记录库存变化 + $inventory_updates[$selected_gift['id']] = ($inventory_updates[$selected_gift['id']] ?? 0) + 1; + // 记录抽中结果 + $gift_id = $selected_gift['foreign_id']; + $drawn_gifts[$gift_id] = ($drawn_gifts[$gift_id] ?? 0) + 1; + // 处理主奖品 + if ($gift_id == $ext['locking_condition']['selected_gift_id']) { + $pan_xlh_num = cache::get('pan_xlh_num_'.$gift_bag_id.'_'.$pan_xlh['id']); + if(!$pan_xlh_num){ + $pan_xlh_num = $pan_xlh['num'] ?? 0; + } + $pan_xlh_num++; + cache::set('pan_xlh_num_'.$gift_bag_id.'_'.$pan_xlh['id'], $pan_xlh_num); + $main_prize_updates[] = [ + 'num' => $pan_xlh_num, + 'user_id' => $user_id, + 'gift_id' => $gift_id + ]; + + // 计算延长时间 + $add_end_time = $this->calculateEndTime($pan_xlh_num, $ext); + $end_time = time() + $add_end_time; + + // 记录主奖品更新 + $main_prize_updates[count($main_prize_updates) - 1]['end_time'] = $end_time; + } + + // 记录完整结果 + $all_results[] = [ + 'gift_id' => $gift_id, + 'gift_detail_id' => $selected_gift['id'], + 'gift_bag_detail' => $selected_gift + ]; + $this->updateCachedGiftBagDetail($gift_bag_id, $selected_gift['id']); // 更新缓存数据 + $this->getCachedPanTotalRemaining($gift_bag_id,"set"); //剩余数量-1 + $this->getCachedPanDrawTimes($gift_bag_id,"set"); //抽奖次数+1 + // 检查是否需要重置奖池 + $total_remaining = $this->getCachedPanTotalRemaining($gift_bag_id); + if ($total_remaining <= 0){// 剩余数量小于等于0且当前处理数量小于总数量 + $availableGifts = $this->resetPoolAndReload($gift_bag_id); + if (empty($availableGifts)) { + throw new \Exception('重置奖池后仍无可用礼物'); + } + } + } + // 批量更新库存 + ksort($inventory_updates); // 按ID排序 + foreach ($inventory_updates as $detail_id => $count) { + db::name("vs_gift_bag_detail")->where('id',$detail_id)->setDec('remaining_number', $count); + } + // 处理主奖品更新 + if (!empty($main_prize_updates)) { + $last_update = end($main_prize_updates); + $pan_xlh_num = cache::get('pan_xlh_num_'.$gift_bag_id.'_'.$pan_xlh['id']); + if($last_update['num'] >= $pan_xlh_num){ + db::name('vs_room_pan_xlh')->where('id', $pan_xlh['id'])->update([ + 'user_id' => $last_update['user_id'], + 'room_id' => $room_id, + 'pay_price' => $ext['xlh_box_price'], + 'locking_gift_id' => $last_update['gift_id'], + 'num' => $last_update['num'], + 'end_time' => $last_update['end_time'], + 'updatetime' => time() + ]); + } + db::name('vs_room_pan_xlh_log')->insert([ + 'xlh_id' => $pan_xlh['id'], + 'user_id' => $last_update['user_id'], + 'room_id' => $room_id, + 'num' => $last_update['num'], + 'locking_end_time' => $last_update['end_time'], + 'createtime' => time() + ]); + $is_zhong_jiang = 1; + }else{ + $is_zhong_jiang = 0; + } + $total_processed += $current_batch; + } + // 7. 批量处理结果记录 + if(count($drawn_gifts) > $num){ + $key = 'xlh_draw_gift_errors_' . date('Y-m-d-H-i-s'); + $errorData = [ + 'user_id' => $user_id, + 'gift_bag_id' => $gift_bag_id, + 'room_id' => $room_id, + 'num' => $num, + 'drawn_gifts_num' => count($drawn_gifts) + ]; + $this->redis->setex($key, 86400 * 7, "巡乐会抽奖失败-数量超限". ' ' .json_encode($errorData)); + return ['code' => 0, 'msg' => "抽奖中,请稍等...", 'data' => null]; + } + // 批量插入礼包发放记录 + $gift_records = []; + $periods = $this->getCachedXlhPeriods('get') ?? 0; + foreach ($drawn_gifts as $gift_id => $count) { + $gift_records[] = [ + 'user_id' => $user_id, + 'parent_id' => $pan_xlh['id'], + 'gift_bag_id' => $gift_bag_id, + 'gift_id' => $gift_id, + 'periods' => $periods, + 'room_id' => $room_id, + 'num' => $count, + 'gift_price' => $this->getGiftPrice($gift_id), + 'bag_price' => $ext['xlh_box_price'], + 'createtime' => time() + ]; + } + if (!empty($gift_records)) { + db::name("vs_gift_bag_receive_pan_log")->insertAll($gift_records); + } + // 批量处理用户礼物包 + foreach ($drawn_gifts as $gift_id => $count) { + $res = model('UserGiftPack')->change_user_gift_pack( + $user_id, + $gift_id, + $count, + model('UserGiftPack')::XLH_DRAW_GIFT_GET, + "巡乐会抽奖所得" + ); + if ($res['code'] != 1) { + throw new \Exception($res['msg']); + } + } + // 添加活动记录 + Db::name('vs_activities_receive')->insert([ + 'user_id' => $user_id, + 'activities_id' => 6, + 'room_id' => $room_id, + 'createtime' => time(), + 'updatetime' => time() + ]); + db::commit(); + } catch (\Exception $e) { + db::rollback(); + $key = 'xlh_draw_gift_errors_' . date('Y-m-d-H-i-s'); + $errorData = [ + 'user_id' => $user_id, + 'gift_bag_id' => $gift_bag_id, + 'room_id' => $room_id, + ]; + $this->redis->setex($key, 86400 * 7, $e->getMessage(). ' ' .json_encode($errorData)); + return ['code' => 0, 'msg' => "抽奖中,请稍等...", 'data' => null]; + } + // 8. 处理推送消息 + if ($is_zhong_jiang == 1) { + $pan_xlh_num = cache::get('pan_xlh_num_'.$gift_bag_id.'_'.$pan_xlh['id']); + $this->handlePrizeNotification($user_id, $room_id, $pan_xlh_num, $pan_xlh['id'],$ext['locking_condition']['locking_gift_id']); + } + //删除缓存 + cache::rm('pan_xlh_num_'.$gift_bag_id.'_'.$pan_xlh['id']); + // 9. 构建返回结果 + return $this->buildResult($drawn_gifts); + } + + /** + * 巡乐会抽奖-从可用礼物中选择一个 + */ + private function selectGiftFromAvailable(array &$available_gifts) + { + $remaining = array_sum(array_column($available_gifts, 'remaining_number')); + if ($remaining <= 0) { + return null; + } + // 循环尝试直到抽中有效礼物 + $max_attempts = 5; // 最大尝试次数,防止无限循环 + $attempt = 0; + $selected_gift = null; + while ($attempt < $max_attempts && !$selected_gift) { + $rand_value = mt_rand(1, $remaining); + $current_sum = 0; + + foreach ($available_gifts as $gift) { + if ($gift['remaining_number'] <= 0) { + continue; + } + $current_sum += $gift['remaining_number']; + if ($rand_value <= $current_sum) { + $selected_gift = $gift; + break; + } + } + $attempt++; + } + + return $selected_gift; + } + /** + * 巡乐会抽奖-计算结束时间 + */ + private function calculateEndTime($pan_xlh_num, $ext) + { + $cache_key = 'pna_xlh_selected_gift_id_' . $ext['locking_condition']['selected_gift_id']; + + if ($pan_xlh_num <= 1) { + $add_end_time = $ext['locking_time']['tow_no_locking_time'] * 60; + Cache::set($cache_key, $add_end_time, $add_end_time); + return $add_end_time; + } + + if (Cache::get($cache_key)) { + $erci_xlh_num = Cache::get($cache_key); + $add_end_time = $erci_xlh_num - $ext['locking_time']['next_time'] * 60; + Cache::set($cache_key, $add_end_time, $add_end_time); + } else { + $add_end_time = ($ext['locking_time']['tow_no_locking_time'] - $ext['locking_time']['next_time']) * 60; + } + + if ($add_end_time <= 30) { + Cache::set($cache_key, 30, 30); + return 30; + } + + return $add_end_time; + } + /** + * 巡乐会抽奖-处理中奖通知 + */ + private function handlePrizeNotification($user_id, $room_id, $pan_xlh_num, $pan_xlh_id,$locking_gift_id) + { + $FromUserInfo = db::name('user')->field('nickname,avatar')->where(['id' => $user_id])->find(); + $locking_gift = db::name('vs_gift')->field('gift_name')->where(['gid' => $locking_gift_id])->find(); + $room_data = db::name('vs_room')->field('room_name,user_id')->where(['id' => $room_id])->find(); + $room_user = db::name('user')->where('id',$room_data['user_id'])->field('nickname,avatar')->find(); + $end_time = db::name('vs_room_pan_xlh')->where('id',$pan_xlh_id)->value('end_time'); + //锁定礼物 + //推送礼物横幅 + $text = $FromUserInfo['nickname'] .' 巡乐会活动中锁定礼物'.$locking_gift['gift_name'].' x ' .$pan_xlh_num ; + $push = new Push(0, $room_id); + $text_list_new = [ + 'text' => $text, + 'room_id' => $room_id, + 'from_type' => 103, + 'gift_num' => $pan_xlh_num, + 'FromUserInfo' => $FromUserInfo, + 'end_time' => $end_time, + 'room_user' => $room_user + ]; + $push->xunlehui($text_list_new); + } + + /** + * 巡乐会抽奖-构建返回结果 + */ + private function buildResult($drawn_gifts) + { + $result_list = []; + $gift_info_cache = []; + + foreach ($drawn_gifts as $gift_id => $count) { + if (!isset($gift_info_cache[$gift_id])) { + $gift_info = db::name('vs_gift') + ->where(['gid' => $gift_id]) + ->find(); + $gift_info_cache[$gift_id] = $gift_info; + } else { + $gift_info = $gift_info_cache[$gift_id]; + } + + $result_list[] = [ + 'gift_id' => $gift_id, + 'gift_name' => $gift_info['gift_name'], + 'base_image' => $gift_info['base_image'], + 'gift_price' => $gift_info['gift_price'], + 'count' => $count, + ]; + } + + // 按价格降序排序 + usort($result_list, function($a, $b) { + return $b['gift_price'] <=> $a['gift_price']; + }); + + return ['code' => 1, 'msg' => '成功', 'data' => $result_list]; + } +} \ No newline at end of file diff --git a/application/cron/controller/RoomPan.php b/application/cron/controller/RoomPan.php index 411665a..b914981 100644 --- a/application/cron/controller/RoomPan.php +++ b/application/cron/controller/RoomPan.php @@ -130,7 +130,7 @@ class RoomPan // db::name("vs_room")->where('id',$value['room_id'])->update([ // 'xlh_periods_num' => 0 // ]); - Cache::set("xlh_periods_num", 0, 0); + Cache::set("pan_xlh_periods_num", 0, 0); //推送礼物横幅 $text = "本轮巡乐会已结束,请大家重新开始下一轮巡乐会"; $push = new Push(0, $value['room_id']);