盲盒转盘优化-重构-调试

This commit is contained in:
2025-10-28 18:07:28 +08:00
parent 590f5cb092
commit bbb3f85fee
3 changed files with 372 additions and 8 deletions

View File

@@ -93,7 +93,7 @@ class BlindBoxTurntable extends BaseCom
$user_id = $this->uid; $user_id = $this->uid;
$room_id = input('room_id',0); $room_id = input('room_id',0);
$num = input('num',1); $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']); return v($reslut['code'], $reslut['msg'], $reslut['data']);
} }
/* /*

View File

@@ -123,7 +123,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
$pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id); //总抽奖次数 $pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id); //总抽奖次数
$pan_total_remaining = $this->getCachedPanTotalRemaining($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); //预加载礼物信息 $giftInfoMap = cache::get("pan_gift_info_map".$gift_bag_id); //预加载礼物信息
$remaining_available_gifts = []; $remaining_available_gifts = [];
if (empty($availableGifts) ||$pan_total_remaining ==0) { if (empty($availableGifts) ||$pan_total_remaining ==0) {
@@ -173,7 +173,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
'gift_user_id' => $giftUserId, 'gift_user_id' => $giftUserId,
'gift_bag_detail' => $selectedGift, 'gift_bag_detail' => $selectedGift,
'gift' => $gift, 'gift' => $gift,
'draw_times' => $pan_total_draw_times, 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id),
'periods' => $periods, 'periods' => $periods,
]; ];
$this->getCachedXlhPeriodsNum("set");//添加寻乐会条件次数 $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)) { if ($newGiftsNeeded > 0 && !empty($availableGifts)) {
@@ -203,14 +203,14 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
'gift_user_id' => $giftUserId, 'gift_user_id' => $giftUserId,
'gift_bag_detail' => $selectedGift, 'gift_bag_detail' => $selectedGift,
'gift' => $gift, 'gift' => $gift,
'draw_times' => $pan_total_draw_times, 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id),
'periods' => $periods, 'periods' => $periods,
]; ];
$precomputedResultss[] = [ $precomputedResultss[] = [
'gift_user_id' => $giftUserId, 'gift_user_id' => $giftUserId,
'gift_bag_detail' => $selectedGift, 'gift_bag_detail' => $selectedGift,
'gift' => $gift, 'gift' => $gift,
'draw_times' => $pan_total_draw_times, 'draw_times' => $this->getCachedPanDrawTimes($gift_bag_id),
'periods' => $periods, '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];
}
}

View File

@@ -130,7 +130,7 @@ class RoomPan
// db::name("vs_room")->where('id',$value['room_id'])->update([ // db::name("vs_room")->where('id',$value['room_id'])->update([
// 'xlh_periods_num' => 0 // 'xlh_periods_num' => 0
// ]); // ]);
Cache::set("xlh_periods_num", 0, 0); Cache::set("pan_xlh_periods_num", 0, 0);
//推送礼物横幅 //推送礼物横幅
$text = "本轮巡乐会已结束,请大家重新开始下一轮巡乐会"; $text = "本轮巡乐会已结束,请大家重新开始下一轮巡乐会";
$push = new Push(0, $value['room_id']); $push = new Push(0, $value['room_id']);