1182 lines
45 KiB
PHP
1182 lines
45 KiB
PHP
<?php
|
||
|
||
namespace app\api\model;
|
||
use app\common\controller\Push;
|
||
use think\Cache;
|
||
use think\Log;
|
||
use think\Model;
|
||
use think\Db;
|
||
use think\Session;
|
||
use Redis;
|
||
/*
|
||
* 盲盒转盘优化后方法
|
||
*
|
||
*/
|
||
class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||
{
|
||
private $redis;
|
||
|
||
public function __construct()
|
||
{
|
||
parent::__construct();
|
||
try {
|
||
$this->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);
|
||
$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' => $pan_total_draw_times,
|
||
'periods' => $periods,
|
||
];
|
||
$this->getCachedXlhPeriodsNum("set");//添加寻乐会条件次数
|
||
$pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id,"set"); // 总抽奖次数
|
||
}
|
||
}
|
||
}
|
||
Cache::set("pan_total_draw".$gift_bag_id, 0, $this->cache_time);
|
||
}
|
||
// 再从新奖池中分配剩余所需礼物
|
||
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' => $pan_total_draw_times,
|
||
'periods' => $periods,
|
||
];
|
||
$precomputedResultss[] = [
|
||
'gift_user_id' => $giftUserId,
|
||
'gift_bag_detail' => $selectedGift,
|
||
'gift' => $gift,
|
||
'draw_times' => $pan_total_draw_times,
|
||
'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 triggerPoolRegeneration($gift_bag_id)
|
||
// {
|
||
// // 检查是否已经在重新生成奖池
|
||
// $regenLockKey = "blind_box_pool_regen_lock:{$gift_bag_id}";
|
||
// $lockAcquired = $this->redis->setnx($regenLockKey, 1);
|
||
//
|
||
// if ($lockAcquired) {
|
||
// // 设置锁的过期时间
|
||
// $this->redis->expire($regenLockKey, 300); // 5分钟过期
|
||
//
|
||
// // 触发异步奖池生成
|
||
// // 这里可以使用队列系统来处理
|
||
// $this->regenerateResultPool($gift_bag_id);
|
||
// }
|
||
// }
|
||
/**
|
||
* 生成奖池并存入Redis
|
||
*/
|
||
// public function generateGiftPool($gift_bag_id)
|
||
// {
|
||
// try {
|
||
// // 获取奖池基本信息
|
||
// $poolKey = "blind_box_pool:{$gift_bag_id}";
|
||
// $poolInfoKey = "blind_box_pool_info:{$gift_bag_id}";
|
||
// // 检查Redis连接
|
||
// if (!$this->redis) {
|
||
// throw new \Exception('Redis连接不可用');
|
||
// }
|
||
// // 获取数据库中的期数信息
|
||
// $dbPeriods = db::name("vs_gift_bag")
|
||
// ->where(['id' => $gift_bag_id])
|
||
// ->value('periods');
|
||
// // 获取奖池详细信息
|
||
// $gift_bag_detail_data = $this->getCachedGiftBagDetail($gift_bag_id);
|
||
//
|
||
// // 获取可用礼物列表
|
||
// $availableGifts = [];
|
||
// foreach ($gift_bag_detail_data as $gift) {
|
||
// if ($gift['remaining_number'] > 0) {
|
||
// // 根据权重添加礼物到可选列表
|
||
// for ($i = 0; $i < $gift['weight']; $i++) {
|
||
// $availableGifts[] = $gift;
|
||
// }
|
||
// }
|
||
// }
|
||
// if (empty($availableGifts)) {
|
||
// throw new \Exception('没有可用的礼物');
|
||
// }
|
||
// // 生成大量抽奖结果(例如1000个)
|
||
// $results = [];
|
||
// for ($i = 0; $i < 1000; $i++) {
|
||
// $randomIndex = array_rand($availableGifts);
|
||
// $selectedGift = $availableGifts[$randomIndex];
|
||
//
|
||
// // 获取礼物详细信息
|
||
// $giftInfo = db::name("vs_gift")
|
||
// ->where(['gid' => $selectedGift['foreign_id']])
|
||
// ->find();
|
||
//
|
||
// $results[] = [
|
||
// 'gift_bag_detail' => $selectedGift,
|
||
// 'gift' => $giftInfo ?? []
|
||
// ];
|
||
// }
|
||
//
|
||
// // 使用事务确保原子操作
|
||
// $this->redis->watch($poolKey, $poolInfoKey);
|
||
// $this->redis->multi();
|
||
//
|
||
// // 清空现有奖池
|
||
// $this->redis->del($poolKey);
|
||
//
|
||
// // 添加新结果到奖池
|
||
// foreach ($results as $result) {
|
||
// $this->redis->rPush($poolKey, json_encode($result));
|
||
// }
|
||
//
|
||
// // 更新奖池信息
|
||
// $this->redis->hMSet($poolInfoKey, [
|
||
// 'periods' => $dbPeriods,
|
||
// 'draw_times' => 0,
|
||
// 'total_count' => count($results),
|
||
// 'last_update' => time()
|
||
// ]);
|
||
//
|
||
// $this->redis->exec();
|
||
//
|
||
// Log::record("奖池生成成功,gift_bag_id: {$gift_bag_id}", 'info');
|
||
// return true;
|
||
// } catch (\Exception $e) {
|
||
// Log::record('生成奖池失败: ' . $e->getMessage(), 'error');
|
||
// return false;
|
||
// }
|
||
// }
|
||
|
||
/**
|
||
* 从奖池中获取一个礼物
|
||
*/
|
||
// public function getGiftFromPool($gift_bag_id)
|
||
// {
|
||
// try {
|
||
// $poolKey = "blind_box_pool:{$gift_bag_id}";
|
||
//
|
||
// // 从Redis奖池中取出一个结果
|
||
// $result = $this->redis->lPop($poolKey);
|
||
//
|
||
// if (!$result) {
|
||
// // 奖池为空,重新生成
|
||
// $this->generateGiftPool($gift_bag_id);
|
||
// $result = $this->redis->lPop($poolKey);
|
||
// }
|
||
// return $result ? json_decode($result, true) : null;
|
||
// } catch (\Exception $e) {
|
||
// Log::record('从奖池获取礼物失败: ' . $e->getMessage(), 'error');
|
||
// return null;
|
||
// }
|
||
// }
|
||
|
||
/**
|
||
* 重置奖池
|
||
*/
|
||
// private function resetGiftPool($gift_bag_id)
|
||
// {
|
||
// try {
|
||
// // 更新数据库中各礼物的剩余数量为初始数量
|
||
// 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);
|
||
//
|
||
// // 删除Redis中的奖池数据
|
||
// $poolKey = "blind_box_pool:{$gift_bag_id}";
|
||
// $poolInfoKey = "blind_box_pool_info:{$gift_bag_id}";
|
||
// $this->redis->del($poolKey);
|
||
// $this->redis->del($poolInfoKey);
|
||
// // 重新生成奖池
|
||
// $this->regenerateResultPool($gift_bag_id);
|
||
// return true;
|
||
// } catch (\Exception $e) {
|
||
// Log::record('重置奖池失败: ' . $e->getMessage(), 'error');
|
||
// return false;
|
||
// }
|
||
// }
|
||
/**
|
||
* 重新生成结果奖池
|
||
*/
|
||
// private function regenerateResultPool($gift_bag_id)
|
||
// {
|
||
// try {
|
||
// // 计算奖池信息
|
||
// $poolInfo = $this->calculatePoolInfo($gift_bag_id);
|
||
// if ($poolInfo['code'] !== 1) {
|
||
// throw new \Exception('计算奖池信息失败');
|
||
// }
|
||
//
|
||
// $totalDrawTimes = $poolInfo['data']['total_draw_times'];
|
||
// $periods = $poolInfo['data']['periods'];
|
||
//
|
||
// // 获取可用礼物
|
||
// $availableGifts = $this->getAvailableGifts($gift_bag_id);
|
||
// if (empty($availableGifts)) {
|
||
// $availableGifts = $this->resetPoolAndReload($gift_bag_id);
|
||
// if (empty($availableGifts)) {
|
||
// throw new \Exception('重置奖池后仍无可用礼物');
|
||
// }
|
||
// $totalDrawTimes = 0;
|
||
// }
|
||
//
|
||
// // 预加载礼物信息
|
||
// $giftInfoMap = $this->preloadGiftInfo($availableGifts);
|
||
//
|
||
// // 构建Alias表(别名表算法用于权重随机)
|
||
// $aliasTable = $this->buildAliasTable($availableGifts);
|
||
// if (!$aliasTable) {
|
||
// throw new \Exception('构建Alias表失败');
|
||
// }
|
||
//
|
||
// // 生成大量抽奖结果(例如1000个)
|
||
// $results = [];
|
||
// $drawTimes = $totalDrawTimes;
|
||
//
|
||
// for ($i = 0; $i < 1000; $i++) {
|
||
// $selectedGift = $this->selectGiftWithAliasMethod($aliasTable, $giftInfoMap);
|
||
// if ($selectedGift) {
|
||
// $results[] = [
|
||
// 'gift_bag_detail' => $selectedGift,
|
||
// 'draw_times' => $drawTimes,
|
||
// 'gift' => $giftInfoMap[$selectedGift['foreign_id']] ?? []
|
||
// ];
|
||
//
|
||
// // 更新剩余数量
|
||
// $this->updateGiftRemainingNumber($selectedGift['id']);
|
||
// $drawTimes++;
|
||
// }
|
||
// }
|
||
//
|
||
// // 将结果存储到Redis奖池中
|
||
// $poolKey = "blind_box_pool:{$gift_bag_id}";
|
||
// $poolInfoKey = "blind_box_pool_info:{$gift_bag_id}";
|
||
//
|
||
// // 使用事务确保原子操作
|
||
// $this->redis->watch($poolKey, $poolInfoKey);
|
||
// $this->redis->multi();
|
||
//
|
||
// // 清空现有奖池
|
||
// $this->redis->del($poolKey);
|
||
//
|
||
// // 添加新结果到奖池
|
||
// foreach ($results as $result) {
|
||
// $this->redis->rPush($poolKey, json_encode($result));
|
||
// }
|
||
//
|
||
// // 更新奖池信息
|
||
// $this->redis->hMSet($poolInfoKey, [
|
||
// 'periods' => $periods,
|
||
// 'draw_times' => $drawTimes,
|
||
// 'total_count' => count($results),
|
||
// 'last_update' => time()
|
||
// ]);
|
||
//
|
||
// $this->redis->exec();
|
||
//
|
||
// // 释放重新生成锁
|
||
// $regenLockKey = "blind_box_pool_regen_lock:{$gift_bag_id}";
|
||
// $this->redis->del($regenLockKey);
|
||
//
|
||
// Log::record("奖池重新生成成功,gift_bag_id: {$gift_bag_id}", 'info');
|
||
//
|
||
// } catch (\Exception $e) {
|
||
// Log::record('重新生成奖池失败: ' . $e->getMessage(), 'error');
|
||
//
|
||
// // 释放重新生成锁
|
||
// $regenLockKey = "blind_box_pool_regen_lock:{$gift_bag_id}";
|
||
// $this->redis->del($regenLockKey);
|
||
// }
|
||
// }
|
||
|
||
/**
|
||
* 重置奖池并重新加载
|
||
*/
|
||
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) {
|
||
$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 = "pan_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
|
||
]
|
||
];
|
||
}
|
||
}
|