diff --git a/application/adminapi/controller/User.php b/application/adminapi/controller/User.php index 793d7fe..774a6ca 100644 --- a/application/adminapi/controller/User.php +++ b/application/adminapi/controller/User.php @@ -72,7 +72,9 @@ class User extends adminApi if($v=='coin1'){ $where['c.coin'] = ['>=',$input_data]; }elseif($v=='coin2'){ - $where['c.coin'] = ['<=',$input_data]; + if($input_data){ + $where['c.coin'] = ['<=',$input_data]; + } }elseif($v=='createtime'){ $where['a.createtime'] = ['>=',strtotime($input_data)]; $where['a.createtime'] = ['<=',strtotime($input_data)]; diff --git a/application/api/controller/BlindBoxTurntable.php b/application/api/controller/BlindBoxTurntable.php index 0ce4750..a40a692 100644 --- a/application/api/controller/BlindBoxTurntable.php +++ b/application/api/controller/BlindBoxTurntable.php @@ -40,7 +40,7 @@ class BlindBoxTurntable extends BaseCom $num = input('num',1); $heart_id = input('heart_id',0); $auction_id = input('auction_id',0); - $reslut = model('BlindBoxTurntableGiftDrawWorld')->draw_gift($gift_bag_id, $user_id, $gift_user_ids,$num,$room_id,$heart_id,$auction_id); + $reslut = model('BlindBoxTurntableGiftDrawWorldNew')->draw_gift($gift_bag_id, $user_id, $gift_user_ids,$num,$room_id,$heart_id,$auction_id); return v($reslut['code'], $reslut['msg'], $reslut['data']); } /* @@ -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/BlindBoxTurntableGiftDrawWorld.php b/application/api/model/BlindBoxTurntableGiftDrawWorld.php index 90380e6..1e5c611 100644 --- a/application/api/model/BlindBoxTurntableGiftDrawWorld.php +++ b/application/api/model/BlindBoxTurntableGiftDrawWorld.php @@ -539,7 +539,6 @@ class BlindBoxTurntableGiftDrawWorld extends Model // 4. 批量插入礼包发放记录 $this->batchInsertGiftBagReceiveLog($user_id, $boxTurntableLog, $bag_data, $room_id, $precomputedResults); - // 5. 发送礼物 $result = $this->sendGiftsToRecipients($precomputedResults, $room_id,$user_id,$heart_id,$auction_id); if (isset($result['code']) && $result['code'] !== 1) { @@ -582,16 +581,16 @@ class BlindBoxTurntableGiftDrawWorld extends Model // 批量更新 foreach ($inventoryUpdates as $giftId => $count) { - $giftBagDetail = Db::name("vs_gift_bag_detail") - ->where('id', $giftId) - ->find(); - if (!$giftBagDetail) { - throw new \Exception("礼物详情不存在,ID: " . $giftId); - } - // 检查库存是否足够 - if ($giftBagDetail['remaining_number'] < $count) { - throw new \Exception("礼物库存不足,ID: " . $giftId); - } + // $giftBagDetail = Db::name("vs_gift_bag_detail") + // ->where('id', $giftId) + // ->find(); + // if (!$giftBagDetail) { + // throw new \Exception("礼物详情不存在,ID: " . $giftId); + // } + // // 检查库存是否足够 + // if ($giftBagDetail['remaining_number'] < $count) { + // throw new \Exception("礼物库存不足,ID: " . $giftId); + // } $ret = db::name("vs_gift_bag_detail")->where('id',$giftId) ->setDec('remaining_number', $count); if (!$ret) { @@ -783,6 +782,7 @@ class BlindBoxTurntableGiftDrawWorld extends Model return ['code' => 0, 'msg' => $res['msg'], 'data' => null]; } } + return ['code' => 1, 'msg' => '发送礼物成功', 'data' => null]; } @@ -1266,6 +1266,7 @@ class BlindBoxTurntableGiftDrawWorld extends Model 'createtime' => time() ]); $is_zhong_jiang = 1; + unset($main_prize_updates); }else{ $is_zhong_jiang = 0; } diff --git a/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php new file mode 100644 index 0000000..66238ae --- /dev/null +++ b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php @@ -0,0 +1,1307 @@ +redis = new Redis(); + // 连接到Redis服务器 + $this->redis->connect(config('redis.host'), config('redis.port')); // 根据实际配置调整主机和端口 + // 选择数据库1 + $this->redis->select(1); + $this->cache_time = 60 *24; + } catch (\Exception $e) { + Log::record('Redis连接失败: ' . $e->getMessage(), 'error'); + $this->redis = null; + } + } + + /** + * 重构后的抽奖方法 - 优化响应速度 + */ + public function draw_gift($gift_bag_id, $user_id, $gift_user_ids, $num = 1, $room_id = 0, $heart_id = 0,$auction_id = 0) + { + // 收礼人 + $gift_user_ids = explode(',', $gift_user_ids); + $total_num = $num * count($gift_user_ids); //总数量 + $bag_data = $this->getCachedGiftBag($gift_bag_id); //获取转盘信息 + $total_price = $bag_data['gift_price'] * $total_num; //礼包支付总价格 + $periods = $bag_data['periods']; //期数 + //1. 验证参数并提前处理错误 + $validationResult = $this->validateDrawParameters($gift_bag_id, $user_id, $gift_user_ids,$total_price); + if ($validationResult !== true) { + return $validationResult; + } + //2.预计算抽奖结果 + $precomputeResult = $this->precomputeDrawResults($gift_bag_id, $total_num, $gift_user_ids,$periods ); + $precomputedResults = $precomputeResult['precomputedResults']; //预计算结果集 + $availableGiftss = $precomputeResult['precomputedResultss']; //可用礼物/需更新的礼物/需更新 + + if (count($precomputedResults) != $total_num) { + // 记录错误到Redis + // 使用正确的Redis方法存储数据 + $key = 'blind_box_draw_world_errors_' . date('Y-m-d-H-i-s'); + $errorData = [ + 'total_num' => $total_num, + 'actual_num' => count($precomputedResults), + 'room_id' => $room_id, + 'user_id' => $user_id, + 'gift_bag_id' => $gift_bag_id, + 'num' => $num, + 'gift_user_ids' => $gift_user_ids, + 'precomputedResults' => $precomputedResults, + ]; + $this->redis->setex($key, 86400 * 7, "超出数量".json_encode($errorData)); + return ['code' => 0, 'msg' => '网络加载失败,请重试!', 'data' => null]; + } + $giftCounts = $this->countGifts($precomputedResults); + foreach ($giftCounts as $giftId => $count) { + if($count['count'] > $count['quantity']){ + $key = 'blind_box_draw_world_errors_' . date('Y-m-d-H-i-s'); + $errorData = [ + 'count' => $count['count'], + 'quantity' => $count['quantity'], + 'gift_bag_id' => $gift_bag_id, + 'user_id' => $user_id, + 'gift_user_ids' => $gift_user_ids, + 'num' => $num, + 'giftUserCountsJianCha' => $count, + ]; + $this->redis->setex($key, 86400 * 7, "礼物数量超出限制 ".json_encode($errorData)); + return ['code' => 0, 'msg' => '网络加载失败,请重试!', 'data' => null]; + } + } + + // 4. 执行抽奖事务(核心操作) + $transactionResult = $this->executeDrawTransaction( + $bag_data, + $user_id, + $room_id, + $num, + $total_price, + $precomputedResults, + $availableGiftss, + $heart_id, + $auction_id + ); + if ($transactionResult['code'] !== 1) { + return $transactionResult; + } + $boxTurntableLog = $transactionResult['data']['log_id']; + $giftCounts = $transactionResult['data']['gift_counts']; + + // 5. 处理后续操作(非事务性操作) + $this->handlePostDrawOperations( + $precomputedResults, + $boxTurntableLog, + $room_id + ); + // 6. 构建并返回结果 + return $this->buildDrawResult($boxTurntableLog, $giftCounts); + } + /** + * 预计算抽奖结果 + */ + private function precomputeDrawResults($gift_bag_id, $total_num, $gift_user_ids,$periods) + { + $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+$total_num); + $giftInfoMap = cache::get("pan_gift_info_map".$gift_bag_id); //预加载礼物信息 + $remaining_available_gifts = []; + if (empty($availableGifts) ||$pan_total_remaining ==0) { + //重置奖池 + $availableGifts = $this->resetPoolAndReload($gift_bag_id); + if (empty($availableGifts)) { + throw new \Exception('重置奖池后仍无可用礼物'); + } + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"clear");//总抽奖次数重置 + }else{ + if ($pan_total_remaining < $total_num) { + $remaining_available_gifts = $availableGifts; // 保存当前剩余礼物作为上期剩余 + //重置奖池 + $availableGifts = $this->resetPoolAndReload($gift_bag_id); + if (empty($availableGifts)) { + throw new \Exception('重置奖池后仍无可用礼物'); + } + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"clear");;//总抽奖次数重置 + + } + } + // 5. 使用Alias Method预计算抽奖结果(O(1)复杂度) + $precomputedResults = []; + $precomputedResultss = []; + + // 计算上期剩余礼物总数 + $remainingGiftCount = array_sum(array_column($remaining_available_gifts, 'remaining_number')); + $newGiftsNeeded = max(0, $total_num - $remainingGiftCount); // 计算还需要多少礼物从新奖池中抽取 + // 先从上期剩余礼物中分配 + if (!empty($remaining_available_gifts)) { + $aliasTableForRemaining = $this->buildAliasTable($remaining_available_gifts); + // 计算上期剩余礼物总数 + foreach ($gift_user_ids as $giftUserId) { + // 为每个用户先分配上期剩余礼物 + $userRemainingAllocation = floor($remainingGiftCount / $total_num); + if (count($gift_user_ids) > 0) { // 防止除零错误 + $extraGifts = $remainingGiftCount % count($gift_user_ids); + if (array_search($giftUserId, $gift_user_ids) < $extraGifts) { + $userRemainingAllocation++; + } + } + for ($i = 0; $i < $userRemainingAllocation; $i++) { + $selectedGift = $this->selectGiftWithAliasMethod($aliasTableForRemaining); + if ($selectedGift) { + $gift = $giftInfoMap[$selectedGift['foreign_id']]; + $precomputedResults[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), + 'periods' => $periods, + ]; + $this->getCachedXlhPeriodsNum("set");//添加寻乐会条件次数 + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"set"); // 总抽奖次数 + } + } + } + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"clear");//总抽奖次数重置 + } + // 再从新奖池中分配剩余所需礼物 + if ($newGiftsNeeded > 0 && !empty($availableGifts)) { + $aliasTableForNew = $this->buildAliasTable($availableGifts); + foreach ($gift_user_ids as $giftUserId) { + // 计算每个用户需要从新奖池获得的礼物数量 + $userNewAllocation = floor($newGiftsNeeded / count($gift_user_ids)); + if (count($gift_user_ids) > 0) { + $extraGifts = $newGiftsNeeded % count($gift_user_ids); + if (array_search($giftUserId, $gift_user_ids) < $extraGifts) { + $userNewAllocation++; + } + } + for ($i = 0; $i < $userNewAllocation; $i++) { + $selectedGift = $this->selectGiftWithAliasMethod($aliasTableForNew); + if ($selectedGift) { + $gift = $giftInfoMap[$selectedGift['foreign_id']]??[]; + $precomputedResults[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), + 'periods' => $periods, + ]; + $precomputedResultss[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id), + 'periods' => $periods, + ]; + + //更新相关缓存数据 + $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"set"); //总抽奖次数+1 + $pan_total_remaining = $this->getCachedPanTotalRemaining($gift_bag_id,"set"); //剩余数量-1 + // 更新房间巡乐会次数 + $this->getCachedXlhPeriodsNum("set"); + // 更新Alias表 + $this->updateAliasTable($aliasTableForNew, $selectedGift['id']); + } + } + } + } + return ['precomputedResults' => $precomputedResults, 'precomputedResultss' => $precomputedResultss]; + } + + /** + * 更新Alias表(模拟库存减少) + */ + private function updateAliasTable(&$aliasTable, $giftId) + { + // 查找礼物在Alias表中的位置 + $gifts = &$aliasTable['gifts']; + $indexMap = &$aliasTable['index_map']; + + foreach ($gifts as &$gift) { + if ($gift['id'] == $giftId) { + $gift['remaining_number']--; + break; + } + } + // 重新构建Alias表(当剩余数量变化较大时) + // 这里可以根据实际情况调整重建频率 + $totalRemaining = array_sum(array_column($gifts, 'remaining_number')); + if ($totalRemaining <= 0) { + $aliasTable = null; + } + } + + /** + * 验证抽奖参数 + */ + private function validateDrawParameters($gift_bag_id, $user_id, $gift_user_ids, $total_price) + { + // 提前验证收礼人 + if (in_array($user_id, $gift_user_ids)) { + return ['code' => 0, 'msg' => "收礼人不能包含自己", 'data' => null]; + } + // 验证用户ID + if (empty($user_id)) { + return ['code' => 0, 'msg' => '用户ID不能为空', 'data' => null]; + } + // 验证盲盒ID + if (empty($gift_bag_id)) { + return ['code' => 0, 'msg' => '盲盒ID不能为空', 'data' => null]; + } + // 检查用户金币 + $user_waller = db::name('user_wallet') + ->where(['user_id' => $user_id]) + ->find(); + if (!$user_waller) { + return ['code' => 0, 'msg' => '用户钱包不存在', 'data' => null]; + } + if ($user_waller['coin'] < $total_price) { + return ['code' => 0, 'msg' => '用户金币不足', 'data' => null]; + } + return true; + } + //获取转盘礼包详细信息【缓存】 + private function getCachedGiftBag($gift_bag_id,$is_cache = true) { + $cacheKey = "pan_gift_bag".$gift_bag_id; + $gift_bag_data = Cache::get($cacheKey); + if (!$gift_bag_data || !$is_cache) { + $bag_data = db::name("vs_gift_bag") + ->field('id,name,ext,periods') + ->where('id', $gift_bag_id) + ->find(); + if (!$bag_data) { + return []; + } + $gift_bag_data = json_decode($bag_data['ext'], true); + $gift_bag_data['gift_bag_id'] = $gift_bag_id; + $gift_bag_data['gift_bag_name'] = $bag_data['name']; + $gift_bag_data['periods'] = $bag_data['periods']; + $gift_bag_data['gift_price'] = DB::name("vs_gift") ->where(['gid' => $gift_bag_data['gift_id']])->value('gift_price'); + Cache::set($cacheKey, $gift_bag_data, $this->cache_time); + } + return $gift_bag_data; + } + //获取奖池详细信息【缓存】 + private function getCachedGiftBagDetail($gift_bag_id,$is_cache = true) { + $cacheKey = "pan_gift_bag_detail".$gift_bag_id; + $pan_gift_bag_detail = Cache::get($cacheKey); + if (empty($pan_gift_bag_detail) || !$is_cache) { + $pan_gift_bag_detail = db::name("vs_gift_bag_detail") + ->field('id,quantity,remaining_number,weight,foreign_id,gift_bag_id') + ->where(['gift_bag_id' => $gift_bag_id]) + ->select(); + if (!$pan_gift_bag_detail) { + return []; + } + $total_quantity = array_sum(array_column( $pan_gift_bag_detail, 'quantity')); + $total_remaining = array_sum(array_column($pan_gift_bag_detail, 'remaining_number')); + $total_draw_times = max(0, $total_quantity - $total_remaining); //总抽奖次数 + + $gift_info_map = []; + $gift_ids = array_unique(array_column($pan_gift_bag_detail, 'foreign_id')); + if (!empty($gift_ids)) { + foreach ($gift_ids as $gift_id) { + $gift_info_map[$gift_id] = db::name("vs_gift") + ->field('gid,gift_name,gift_price,base_image') + ->where(['gid' => $gift_id]) + ->find(); + } + } + Cache::set($cacheKey, $pan_gift_bag_detail, $this->cache_time); + Cache::set("pan_gift_info_map".$gift_bag_id, $gift_info_map, $this->cache_time); + Cache::set("pan_total_quantity".$gift_bag_id, $total_quantity, $this->cache_time); + Cache::set("pan_total_remaining".$gift_bag_id, $total_remaining, $this->cache_time); + Cache::set("pan_total_draw_times".$gift_bag_id, $total_draw_times, $this->cache_time); + } + return $pan_gift_bag_detail; + } + + /** + * 获取可用礼物 + * @param $gift_bag_id + * @param $total_draw_times 总抽奖次数 + */ + private function getAvailableGifts($gift_bag_id, $pan_total_draw_times = 0) + { + $gift_bag_detail_data = $this->getCachedGiftBagDetail($gift_bag_id); + $gift_detail_data = []; + foreach ($gift_bag_detail_data as $item) { + if($item['remaining_number'] > 0 && $item['weight']<=$pan_total_draw_times && $item['quantity'] > 0){ + $gift_detail_data[] = $item; + } + } + return $gift_detail_data; + } + + /** + * 重置奖池并重新加载 + */ + private function resetPoolAndReload($gift_bag_id) + { + // 重置剩余数量 + Db::name("vs_gift_bag_detail") + ->where(['gift_bag_id' => $gift_bag_id]) + ->update(['remaining_number' => Db::raw('quantity')]); + + // 清除缓存 + Cache::rm("pan_gift_bag_detail".$gift_bag_id); + + // 重新获取可用礼物 + return $this->getAvailableGifts($gift_bag_id); + } + + /** + * 使用Alias Method选择礼物(O(1)复杂度) + */ + private function selectGiftWithAliasMethod($aliasTable) + { + if (!$aliasTable) return null; + + $n = $aliasTable['n']; + $k = mt_rand(0, $n - 1); + + // 随机选择 + if (mt_rand() / mt_getrandmax() < $aliasTable['prob'][$k]) { + return $aliasTable['index_map'][$k]; + } else { + return $aliasTable['index_map'][$aliasTable['alias'][$k]] ?? null; + } + } + /** + * 构建Alias表(O(n)复杂度,只执行一次) + */ + private function buildAliasTable($gifts) + { + $n = count($gifts); + if ($n === 0) return null; + + $totalRemaining = array_sum(array_column($gifts, 'remaining_number')); + if ($totalRemaining <= 0) return null; + + // 初始化Alias表 + $small = []; + $large = []; + $prob = []; + $alias = []; + $indexMap = []; + + // 归一化概率并填充索引映射 + foreach ($gifts as $i => $gift) { + if ($gift['remaining_number'] <= 0) continue; + $indexMap[$i] = $gift; + $prob[$i] = $gift['remaining_number'] * $n / $totalRemaining; + if ($prob[$i] < 1.0) { + $small[] = $i; + } else { + $large[] = $i; + } + } + + // 构建Alias表 + while (!empty($small) && !empty($large)) { + $s = array_pop($small); + $l = array_pop($large); + $alias[$s] = $l; + $prob[$l] = ($prob[$l] + $prob[$s]) - 1.0; + + if ($prob[$l] < 1.0) { + $small[] = $l; + } else { + $large[] = $l; + } + } + + return [ + 'n' => $n, + 'prob' => $prob, + 'alias' => $alias, + 'index_map' => $indexMap, + 'gifts' => $gifts + ]; + } + + + /** + * 更新礼物剩余数量 + */ + private function updateGiftRemainingNumber($gift_bag_detail_id) + { + Db::name("vs_gift_bag_detail") + ->where(['id' => $gift_bag_detail_id]) + ->setDec('remaining_number', 1); + } + + /** + * 更新缓存中的奖池信息 + */ + private function updateCachedGiftBagDetail($gift_bag_id, $detail_id, $decrement = 1) { + $cacheKey = "pan_gift_bag_detail".$gift_bag_id; + $gift_bag_detail_data = Cache::get($cacheKey); + + if ($gift_bag_detail_data) { + foreach ($gift_bag_detail_data as &$item) { + if ($item['id'] == $detail_id) { + $item['remaining_number'] -= $decrement; + break; + } + } + Cache::set($cacheKey, $gift_bag_detail_data, $this->cache_time); + } + } + /** + * 获取奖池总库存 + */ + private function getCachedPanTotalQuantity($gift_bag_id) { + $cacheKey = "pan_total_quantity".$gift_bag_id; + $pan_total_quantity = Cache::get($cacheKey); + if(!$pan_total_quantity) { + $pan_total_quantity = Db::name("vs_gift_bag_detail") + ->where(['gift_bag_id' => $gift_bag_id]) + ->sum('quantity'); + Cache::set($cacheKey, $pan_total_quantity, $this->cache_time); + } + return $pan_total_quantity; + } + /** + * 获取奖池剩余库存 + */ + private function getCachedPanTotalRemaining($gift_bag_id, $type="get", $check_num=1) { + $cacheKey = "pan_total_remaining".$gift_bag_id; + $pan_total_quantity = Cache::get($cacheKey); + if($type == "set"){ + $pan_total_quantity = $pan_total_quantity-$check_num; + if($pan_total_quantity < 0){ + $pan_total_quantity = 0; + } + Cache::set($cacheKey, $pan_total_quantity, $this->cache_time); + }elseif($type == "clear"){ + $pan_total_quantity = 0; + Cache::set($cacheKey, $pan_total_quantity, $this->cache_time); + } else{ + if(!$pan_total_quantity) { + $pan_total_quantity = Db::name("vs_gift_bag_detail") + ->where(['gift_bag_id' => $gift_bag_id]) + ->sum('remaining_number'); + Cache::set($cacheKey, $pan_total_quantity, $this->cache_time); + } + } + + return $pan_total_quantity; + } + /** + * 获取缓存的抽奖次数 + */ + private function getCachedPanDrawTimes($gift_bag_id,$type="get") { + $cacheKey = "pan_total_draw".$gift_bag_id; + $total_draw_times = Cache::get($cacheKey) ?? 0; + if($type == "set"){ + $total_draw_times = $total_draw_times+1; + Cache::set($cacheKey, $total_draw_times, $this->cache_time); + }elseif($type == "clear"){ + $total_draw_times = 0; + Cache::set($cacheKey, $total_draw_times, $this->cache_time); + } + return $total_draw_times; + } + /** + * 获取缓存的巡乐会开启次数 + */ + private function getCachedXlhPeriodsNum($type="get",$num=1) { + $cacheKey = "xlh_periods_num"; + $xlh_periods_num = Cache::get($cacheKey) ?? 0; + if($type=="set"){ + $xlh_periods_num = $xlh_periods_num + $num; + Cache::set($cacheKey, $xlh_periods_num, 0); + } + return $xlh_periods_num; + } + /** + * 获取缓存的巡乐会期数 + */ + private function getCachedXlhPeriods($type="get",$periods=1) { + $cacheKey = "pan_this_xlh_periods"; + $xlh_periods_num = Cache::get($cacheKey) ?? 0; + if($type=="set"){ + $xlh_periods_num = $periods; + Cache::set($cacheKey, $xlh_periods_num, 0); + } + return $xlh_periods_num; + } + + //开始更新操作: + /** + * 执行抽奖事务(核心操作) + */ + private function executeDrawTransaction($bag_data, $user_id, $room_id, $num,$total_price, $precomputedResults,$availableGiftss,$heart_id,$auction_id) + { + try { + db::startTrans(); + // 按照固定顺序处理事务步骤 + // 1. 扣除用户金币(优先处理) + $this->deductUserCoins($user_id, $total_price, $room_id); + // 2. 创建抽奖记录 + $boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([ + 'user_id' => $user_id, + 'gift_bag_id' => $bag_data['gift_bag_id'], + 'num' => $num, + 'room_id' => $room_id, + 'bag_price' => $bag_data['gift_price'], + 'createtime' => time() + ]); + if (!$boxTurntableLog) { + throw new \Exception('添加盲盒转盘记录失败'); + } + // 3. 批量更新库存(按ID排序避免死锁) + $this->batchUpdateGiftInventory($availableGiftss); + + // 4. 批量插入礼包发放记录 + $this->batchInsertGiftBagReceiveLog($bag_data,$user_id, $boxTurntableLog,$room_id, $precomputedResults); + + // 5. 发送礼物 + $result = $this->sendGiftsToRecipients($precomputedResults, $room_id,$user_id,$heart_id,$auction_id); + if (isset($result['code']) && $result['code'] !== 1) { + throw new \Exception($result['msg']); + } + + db::commit(); + + // 统计礼物数量 + $giftCounts = $this->countGifts($precomputedResults); + + return [ + 'code' => 1, + 'msg' => '事务执行成功', + 'data' => [ + 'log_id' => $boxTurntableLog, + 'gift_counts' => $giftCounts + ] + ]; + } catch (\Exception $e) { + db::rollback(); + throw new \Exception($e->getMessage()); + } + } + /** + * 扣除用户金币 + */ + private function deductUserCoins($user_id, $bagGiftPrice, $room_id) + { + // 使用悲观锁查询用户钱包 + $userWallet = db::name('user_wallet') + ->where(['user_id' => $user_id]) + ->find(); + if (!$userWallet || $userWallet['coin'] < $bagGiftPrice) { + throw new \Exception('用户金币不足'); + } + $walletUpdate = model('GiveGift')->change_user_cion_or_earnings_log( + $user_id, + $bagGiftPrice, + $room_id, + 1, + 10, + '盲盒转盘抽奖消耗' + ); + if (!$walletUpdate) { + throw new \Exception('扣除用户金币失败'); + } + //更新用户等级 + $userLevel = model('Level')->user_level_data_update( + $user_id, + $bagGiftPrice, + 1, + $room_id + ); + if (!$userLevel) { + throw new \Exception('用户等级更新失败'); + } + } + /** + * 批量更新礼物库存 + */ + private function batchUpdateGiftInventory($precomputedResults) + { + // 按礼物ID分组统计需要减少的数量 + $inventoryUpdates = []; + foreach ($precomputedResults as $result) { + $giftId = $result['gift_bag_detail']['id']??0; + $inventoryUpdates[$giftId] = ($inventoryUpdates[$giftId] ?? 0) + 1; + } + + // 按ID排序避免死锁 + ksort($inventoryUpdates); + + // 批量更新 + foreach ($inventoryUpdates as $giftId => $count) { + $giftBagDetail = Db::name("vs_gift_bag_detail") + ->where('id', $giftId) + ->find(); + if (!$giftBagDetail) { + throw new \Exception("礼物详情不存在,ID: " . $giftId); + } + // 检查库存是否足够 + if ($giftBagDetail['remaining_number'] < $count) { + throw new \Exception("礼物库存不足,ID: " . $giftId); + } + $ret = db::name("vs_gift_bag_detail")->where('id',$giftId) + ->setDec('remaining_number', $count); + if (!$ret) { + throw new \Exception('更新礼物剩余数量失败'); + } + + // 同时更新缓存中的库存信息 + $this->updateCachedGiftBagDetail($giftBagDetail['gift_bag_id'], $giftId, $count); + } + } + + /** + * 批量插入礼包发放记录 + */ + private function batchInsertGiftBagReceiveLog($bag_data,$user_id, $boxTurntableLog,$room_id, $precomputedResults) + { + + $batchInsertData = []; + + foreach ($precomputedResults as $result) { + if(!isset($result['gift']['gift_price'])){ + Log::record('数据报错:'.json_encode($result),"info"); + } + $batchInsertData[] = [ + 'user_id' => $user_id, + 'gift_user_id' => $result['gift_user_id'], + 'parent_id' => $boxTurntableLog, + 'gift_bag_id' => $bag_data['gift_bag_id'], + 'gift_id' => $result['gift_bag_detail']['foreign_id'], + 'periods' => $result['periods'], + 'room_id' => $room_id, + 'gift_price' => $result['gift']['gift_price'], + 'bag_price' => $bag_data['gift_price'], + 'createtime' => time() + ]; + } + if (!empty($batchInsertData)) { + $insertResult = db::name("vs_gift_bag_receive_pan_log")->insertAll($batchInsertData); + if (!$insertResult) { + throw new \Exception('插入礼包发放记录失败'); + } + } + } + + /** + * 发送礼物给接收者 + */ + private function sendGiftsToRecipients($precomputedResults, $room_id,$user_id,$heart_id,$auction_id) + { + // 统计每个用户每个礼物的数量 + $giftUserCounts = []; + foreach ($precomputedResults as $result) { + $key = $result['gift_user_id'] . '_' . $result['gift_bag_detail']['foreign_id']; + if (!isset($giftUserCounts[$key])) { + $giftUserCounts[$key] = [ + 'gift_user_id' => $result['gift_user_id'], + 'gift_id' => $result['gift_bag_detail']['foreign_id'], + 'count' => 0, + 'gift_price' => $result['gift']['gift_price'] + ]; + } + $giftUserCounts[$key]['count']++; + } + + // 批量发送礼物 + foreach ($giftUserCounts as $userGift) { + if($userGift['count'] > 9){ //防止礼物超发,礼物超10个则不发送 + continue; + } + $giveGiftExt = [ + 'gift_id' => $userGift['gift_id'], + 'count' => $userGift['count'], + 'gift_price' => $userGift['gift_price'], + 'all_gift_price' => $userGift['gift_price'] * $userGift['count'], + 'is_draw_gift' => 1 + ]; + if(!empty($auction_id)){ //竞拍 + model('RoomAuction')->room_auction_join($auction_id,$user_id,$userGift['gift_id'],$userGift['count'],2,$giveGiftExt); + }else{ + $res = model('Room')->room_gift( + $user_id, + $userGift['gift_user_id'], + $userGift['gift_id'], + $userGift['count'], + 1, + $room_id, + 0, + $heart_id, + $giveGiftExt + ); + } + if (isset($res) && $res['code'] != 1) { + Log::record('发送礼物失败: ' . $res['msg'] . $userGift['gift_user_id'], "info"); + return ['code' => 0, 'msg' => $res['msg'], 'data' => null]; + } + } + return ['code' => 1, 'msg' => '发送礼物成功', 'data' => null]; + } + /** + * 统计礼物数量 + */ + private function countGifts($precomputedResults) + { + $giftCounts = []; + foreach ($precomputedResults as $result) { + $giftId = $result['gift_bag_detail']['foreign_id']; + if (!isset($giftCounts[$giftId])) { + $giftCounts[$giftId] = [ + 'gift_user_id' => $result['gift_user_id'], + 'gift_id' => $giftId, + 'count' => 0, + 'gift_price' => $result['gift']['gift_price'], + 'quantity' => $result['gift_bag_detail']['quantity'] + ]; + } + $giftCounts[$giftId]['count']++; + } + return $giftCounts; + } + /** + * 处理抽奖后的后续操作(非事务性) + */ + private function handlePostDrawOperations( + $precomputedResults, + $boxTurntableLog, + $room_id + ) { + // 获取巡乐会配置(使用缓存) + $xlh_ext = $this->getCachedGiftBag(13); + // 1. 批量插入盲盒转盘结果记录 + $this->batchInsertBlindBoxResults($precomputedResults, $boxTurntableLog); + // 2. 处理巡乐会相关操作 + if (!empty($xlh_ext) && $xlh_ext['inlet_bag_id'] == $precomputedResults[0]['gift_bag_detail']['gift_bag_id']) { + $this->handleXlhOperations($room_id, $xlh_ext); + } + } + /** + * 批量插入盲盒转盘结果记录 + */ + private function batchInsertBlindBoxResults($precomputedResults, $boxTurntableLog) + { + // 统计每个用户每个礼物的数量 + $giftUserCounts = $this->countGifts($precomputedResults); + // 批量插入 + $batchInsertData = []; + foreach ($giftUserCounts as $userGift) { + $batchInsertData[] = [ + 'tid' => $boxTurntableLog, + 'gift_user_id' => $userGift['gift_user_id'], + 'gift_id' => $userGift['gift_id'], + 'count' => $userGift['count'], + 'gift_price' => $userGift['gift_price'], + 'all_gift_price' => $userGift['gift_price'] * $userGift['count'], + 'createtime' => time(), + 'heart_id' => 0 + ]; + } + if (!empty($batchInsertData)) { + db::name('vs_blind_box_turntable_results_log')->insertAll($batchInsertData); + } + } + /** + * 处理巡乐会相关操作 + */ + private function handleXlhOperations($room_id, $xlh_ext) + { + $xlhIsPiaoPing = 0; + $xlhPeriodsNum = $this->getCachedXlhPeriodsNum("get"); + if($xlhPeriodsNum == $xlh_ext['open_condition']['waiting_start_num']){ + $xlhIsPiaoPing = 1; + } + if($xlhPeriodsNum == $xlh_ext['open_condition']['start_num']){ + $xlhIsPiaoPing = 2; + } + // 处理飘屏 + if ($xlhIsPiaoPing == 1 || $xlhIsPiaoPing == 2) { + $this->handleXlhPiaoPing($room_id, $xlh_ext, $xlhIsPiaoPing); + } + + $this->updateAndPushXlhStatus($room_id, $xlh_ext); + } + private function handleXlhPiaoPing($room_id, $xlh_ext, $xlhIsPiaoPing){ + if($xlhIsPiaoPing == 1){ + // 即将开始推送飘屏 + $text = "巡乐会即将开始..."; + // 推送礼物横幅 + $push = new Push(UID, $room_id); + $text_list_new = [ + 'text' => $text, + 'room_id' => $room_id, + 'from_type' => 101 + ]; + $push->xunlehui($text_list_new); + } + if($xlhIsPiaoPing == 2){ + // 正式开始推送飘屏 + $text = "巡乐会游戏已正式开启..."; + // 推送礼物横幅 + $push = new Push(UID, $room_id); + $text_list_new = [ + 'text' => $text, + 'room_id' => $room_id, + 'from_type' => 102 + ]; + $push->xunlehui($text_list_new); + // 巡乐会正式开始 + $this_xlh_periods = $this->getCachedXlhPeriods('get'); + $pan_xlh_id = db::name('vs_room_pan_xlh')->insertGetId([ + 'room_id' => $room_id, + 'gift_id' => $xlh_ext['locking_condition']['locking_gift_id'], + 'homeowner_gift_id' => $xlh_ext['locking_condition']['give_homeowner_gift_id'], + 'periods' => $this_xlh_periods+1, + 'num' => 0, + 'end_time' => time() + $xlh_ext['locking_time']['end_time'] * 60, + 'createtime' => time() + ]); + if(!$pan_xlh_id){ + return ['code' => 0, 'msg' => '创建巡乐会失败!', 'data' => []]; + } + $this->getCachedXlhPeriods('set', $this_xlh_periods+1);//修改巡乐会期数 + } + } + private function updateAndPushXlhStatus($room_id, $xlh_ext){ + $xlh['waiting_start_num'] = $xlh_ext['open_condition']['waiting_start_num'];//等待开奖次数 + $xlh['start_num'] = $xlh_ext['open_condition']['start_num'];//开始开奖次数 + // 当前抽奖次数 + $xlh['current_num'] = $this->getCachedXlhPeriodsNum("get"); + $xlh['end_time'] = 0; + // 状态 + if($xlh['current_num'] >= $xlh_ext['open_condition']['start_num']){ + $xlh['status'] = 1;//状态 1:巡乐会开始 2:即将开始开始 0:等待开始 + //查询巡乐会信息 + $pan_xlh = db::name('vs_room_pan_xlh')->where('send_time',0)->order('id desc')->find(); + if(empty($pan_xlh)){ + $this->handleXlhPiaoPing($room_id, $xlh_ext, 2); + $pan_xlh = db::name('vs_room_pan_xlh')->where('send_time',0)->order('id desc')->find(); + } + $xlh['end_time'] = $pan_xlh['end_time'] ?? 0; + } elseif($xlh['current_num'] >= $xlh_ext['open_condition']['waiting_start_num'] && $xlh['current_num'] < $xlh_ext['open_condition']['start_num']){ + $xlh['status'] = 2;//状态 1:巡乐会开始 2:即将开始开始 0:等待开始 + }else{ + $xlh['status'] = 0; + } + // 推送进度条 + $push = new Push(UID, $room_id); + $text_list_new = [ + 'xlh_data' => $xlh, + 'text' => "", + 'room_id' => $room_id, + 'from_type' => 100 + ]; + $push->xunlehui($text_list_new); + } + + /** + * 构建抽奖结果 + */ + private function buildDrawResult($boxTurntableLog, $giftCounts) + { + $resultList = []; + foreach ($giftCounts as $gift) { + $resultList[] = [ + 'gift_id' => $gift['gift_id'], + 'count' => $gift['count'] + ]; + } + return [ + 'code' => 1, + 'msg' => '成功', + 'data' => [ + 'blind_box_turntable_id' => $boxTurntableLog, + 'reslut_list' => $resultList + ] + ]; + } + +/* + * 巡乐会抽奖----------------------------------------------------------------------------------------- + */ + /* + * 巡乐会抽奖(优化版) + */ + 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() + ]); + } + + // 使用insertIgnore防止重复插入记录 + 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; + unset($main_prize_updates); + }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' => cache::get("pan_gift_info_map".$gift_bag_id)[$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