盲盒转盘-岁月之城,时空之旅,抽奖结果转落包。

This commit is contained in:
2025-12-19 18:40:29 +08:00
parent 1c2b981649
commit cd69ab6b73
6 changed files with 391 additions and 18 deletions

View File

@@ -158,12 +158,14 @@ class User extends adminApi
$total_coin = db::name('user')->alias('a') $total_coin = db::name('user')->alias('a')
->join('(SELECT * FROM fa_user_auth WHERE id IN (SELECT MAX(id) FROM fa_user_auth GROUP BY mobile)) b', 'a.mobile = b.mobile', 'LEFT') ->join('(SELECT * FROM fa_user_auth WHERE id IN (SELECT MAX(id) FROM fa_user_auth GROUP BY mobile)) b', 'a.mobile = b.mobile', 'LEFT')
->join('user_wallet c', 'a.id = c.user_id','LEFT') ->join('user_wallet c', 'a.id = c.user_id','LEFT')
->where(['a.delete_time'=>0])
->where($where) ->where($where)
->field($field) ->field($field)
->sum('c.coin'); ->sum('c.coin');
$total_earnings = db::name('user')->alias('a') $total_earnings = db::name('user')->alias('a')
->join('(SELECT * FROM fa_user_auth WHERE id IN (SELECT MAX(id) FROM fa_user_auth GROUP BY mobile)) b', 'a.mobile = b.mobile', 'LEFT') ->join('(SELECT * FROM fa_user_auth WHERE id IN (SELECT MAX(id) FROM fa_user_auth GROUP BY mobile)) b', 'a.mobile = b.mobile', 'LEFT')
->join('user_wallet c', 'a.id = c.user_id','LEFT') ->join('user_wallet c', 'a.id = c.user_id','LEFT')
->where(['a.delete_time'=>0])
->where($where) ->where($where)
->field($field) ->field($field)
->sum('c.earnings'); ->sum('c.earnings');

View File

@@ -40,7 +40,15 @@ class BlindBoxTurntable extends BaseCom
$num = input('num',1); $num = input('num',1);
$heart_id = input('heart_id',0); $heart_id = input('heart_id',0);
$auction_id = input('auction_id',0); $auction_id = input('auction_id',0);
$reslut = model('BlindBoxTurntableGiftDrawWorldNew')->draw_gift($gift_bag_id, $user_id, $gift_user_ids,$num,$room_id,$heart_id,$auction_id); if(!in_array($gift_bag_id,[10,11,12])){
return v(0,'非法活动ID', null);
}
if($gift_bag_id==10){
$reslut = model('BlindBoxTurntableGiftDrawWorldNew')->draw_gift($gift_bag_id, $user_id, $gift_user_ids,$num,$room_id,$heart_id,$auction_id);
}else{
$reslut = model('BlindBoxTurntableGiftDrawWorldNew')->draw_gift_drop_bag($gift_bag_id, $user_id,$num,$room_id);
}
return v($reslut['code'], $reslut['msg'], $reslut['data']); return v($reslut['code'], $reslut['msg'], $reslut['data']);
} }
/* /*

View File

@@ -391,16 +391,29 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
*/ */
private function resetPoolAndReload($gift_bag_id) private function resetPoolAndReload($gift_bag_id)
{ {
// 重置剩余数量 $lockKey = "reset_pool_lock_".$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); if ($this->redis->set($lockKey, 1, ['NX', 'EX' => 10])) {
try {
// 重置剩余数量
Db::name("vs_gift_bag_detail")
->where(['gift_bag_id' => $gift_bag_id])
->update(['remaining_number' => Db::raw('quantity')]);
// 重新获取可用礼物 // 清除缓存
return $this->getAvailableGifts($gift_bag_id); Cache::rm("pan_gift_bag_detail".$gift_bag_id);
// 重新获取可用礼物
return $this->getAvailableGifts($gift_bag_id);
} finally {
// 释放锁
$this->redis->del($lockKey);
}
} else {
// 如果无法获取锁,等待一段时间后重试或返回错误
throw new \Exception('系统繁忙,请稍后再试');
}
} }
/** /**
@@ -496,9 +509,13 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
*/ */
private function updateGiftRemainingNumber($gift_bag_detail_id) private function updateGiftRemainingNumber($gift_bag_detail_id)
{ {
Db::name("vs_gift_bag_detail") $result = Db::name("vs_gift_bag_detail")
->where(['id' => $gift_bag_detail_id]) ->where(['id' => $gift_bag_detail_id])
->where('remaining_number', '>', 0) // 确保库存充足
->setDec('remaining_number', 1); ->setDec('remaining_number', 1);
if (!$result) {
throw new \Exception('礼物库存不足');
}
} }
/** /**
@@ -650,7 +667,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
db::startTrans(); db::startTrans();
// 按照固定顺序处理事务步骤 // 按照固定顺序处理事务步骤
// 1. 扣除用户金币(优先处理) // 1. 扣除用户金币(优先处理)
$this->deductUserCoins($user_id, $total_price, $room_id); $this->deductUserCoins($user_id, $total_price, $room_id,$bag_data);
// 2. 创建抽奖记录 // 2. 创建抽奖记录
$boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([ $boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([
'user_id' => $user_id, 'user_id' => $user_id,
@@ -696,7 +713,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
/** /**
* 扣除用户金币 * 扣除用户金币
*/ */
private function deductUserCoins($user_id, $bagGiftPrice, $room_id) private function deductUserCoins($user_id, $bagGiftPrice, $room_id , $bag_data=[])
{ {
// 使用悲观锁查询用户钱包 // 使用悲观锁查询用户钱包
$userWallet = db::name('user_wallet') $userWallet = db::name('user_wallet')
@@ -711,7 +728,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
$room_id, $room_id,
1, 1,
10, 10,
'盲盒转盘抽奖消耗' $bag_data['gift_bag_name'] .'抽奖消耗'
); );
if (!$walletUpdate) { if (!$walletUpdate) {
throw new \Exception('扣除用户金币失败'); throw new \Exception('扣除用户金币失败');
@@ -1175,7 +1192,13 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
// 批量更新库存 // 批量更新库存
ksort($inventory_updates); // 按ID排序 ksort($inventory_updates); // 按ID排序
foreach ($inventory_updates as $detail_id => $count) { foreach ($inventory_updates as $detail_id => $count) {
db::name("vs_gift_bag_detail")->where('id',$detail_id)->setDec('remaining_number', $count); $result = db::name("vs_gift_bag_detail")
->where('id',$detail_id)
->where('remaining_number', '>=', $count) // 确保库存充足
->setDec('remaining_number', $count);
if (!$result) {
throw new \Exception('礼物库存不足');
}
} }
// 处理主奖品更新 // 处理主奖品更新
if (!empty($main_prize_updates)) { if (!empty($main_prize_updates)) {
@@ -1405,4 +1428,302 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
return ['code' => 1, 'msg' => '成功', 'data' => $result_list]; return ['code' => 1, 'msg' => '成功', 'data' => $result_list];
} }
/** ***********2025-12-19*****************
* 盲盒转盘-11-12-直接落包抽奖
*/
public function draw_gift_drop_bag($gift_bag_id, $user_id, $num = 1, $room_id = 0)
{
try {
// 参数验证
$validation_result = $this->validateDrawParams($gift_bag_id, $user_id, $num);
if ($validation_result['code'] !== 1) {
return $validation_result;
}
// 获取转盘信息和用户钱包
$bag_data = $this->getCachedGiftBag($gift_bag_id);
$user_wallet = Db::name('user_wallet')->where(['user_id' => $user_id])->find();
if (!$user_wallet) {
return ['code' => 0, 'msg' => '用户钱包不存在', 'data' => null];
}
$total_price = $bag_data['gift_price'] * $num;
if ($user_wallet['coin'] < $total_price) {
return ['code' => 0, 'msg' => '用户金币不足', 'data' => null];
}
// 检查奖池状态并准备礼物
$pool_status = $this->prepareGiftPool($gift_bag_id, $num);
if ($pool_status['code'] !== 1) {
throw new \Exception($pool_status['msg']);
}
$available_gifts = $pool_status['data']['available_gifts'];
$remaining_available_gifts = $pool_status['data']['remaining_gifts'] ?? [];
$periods = $bag_data['periods'];
// 开始事务处理
Db::startTrans();
try {
// 扣除用户金币
$this->deductUserCoins($user_id, $total_price, $room_id, $bag_data);
// 抽取礼物
$draw_result = $this->performGiftDrawing(
$gift_bag_id,
$available_gifts,
$remaining_available_gifts,
$num,
$periods
);
if ($draw_result['code'] !== 1) {
throw new \Exception($draw_result['msg']);
}
$precomputed_results = $draw_result['data']['precomputed_results'];
$drawn_gifts = $draw_result['data']['drawn_gifts'];
$available_giftss = $draw_result['data']['available_giftss'];
// 创建抽奖记录
$log_id = $this->createDrawLog($user_id, $gift_bag_id, $num, $room_id, $bag_data);
if (!$log_id) {
throw new \Exception('添加盲盒转盘记录失败');
}
// 批量更新库存
$this->batchUpdateGiftInventory($gift_bag_id, $available_giftss);
// 批量插入礼包发放记录
$this->batchInsertGiftBagReceiveLog($bag_data, $user_id, $log_id, $room_id, $precomputed_results);
// 发送礼物给用户
$send_result = $this->sendGiftsToRecipientsPack($drawn_gifts, $user_id, $bag_data);
if (isset($send_result['code']) && $send_result['code'] !== 1) {
throw new \Exception($send_result['msg']);
}
$gift_counts = $send_result['data'];
// 插入抽奖结果
$this->batchInsertBlindBoxResults($precomputed_results, $log_id);
Db::commit();
// 返回结果
return $this->buildDrawResult($log_id, $gift_counts);
} catch (\Exception $e) {
Db::rollback();
return ['code' => 0, 'msg' => $e->getMessage(), 'data' => null];
}
} catch (\Exception $e) {
$key = 'blind_box_draw_errors_' . date('Y-m-d-H-i-s');
$error_data = [
'gift_bag_id' => $gift_bag_id,
'user_id' => $user_id,
'num' => $num,
'room_id' => $room_id
];
if ($this->redis) {
$this->redis->setex($key, 86400 * 7, $e->getMessage() . ' ' . json_encode($error_data));
}
return ['code' => 0, 'msg' => "网络加载失败,请重试!", 'data' => null];
}
}
/**
* 验证抽奖参数
*/
private function validateDrawParams($gift_bag_id, $user_id, $num)
{
if (empty($user_id)) {
return ['code' => 0, 'msg' => '用户ID不能为空', 'data' => null];
}
if (empty($gift_bag_id)) {
return ['code' => 0, 'msg' => '盲盒转盘ID不能为空', 'data' => null];
}
if ($num <= 0) {
return ['code' => 0, 'msg' => '抽奖数量必须大于0', 'data' => null];
}
return ['code' => 1, 'msg' => '验证通过', 'data' => null];
}
/**
* 准备奖池
*/
private function prepareGiftPool($gift_bag_id, $num)
{
$pan_total_draw_times = $this->getCachedPanDrawTimes($gift_bag_id);
$pan_total_remaining = $this->getCachedPanTotalRemaining($gift_bag_id);
$available_gifts = $this->getAvailableGifts($gift_bag_id, $pan_total_draw_times + $num);
$remaining_gifts = [];
// 如果没有可用礼物或者剩余数量为0重置奖池
if (empty($available_gifts) || $pan_total_remaining == 0) {
$available_gifts = $this->resetPoolAndReload($gift_bag_id);
if (empty($available_gifts)) {
return ['code' => 0, 'msg' => '奖池无可用礼物', 'data' => null];
}
$this->getCachedPanDrawTimes($gift_bag_id, "clear");
} else if ($pan_total_remaining < $num) {
// 如果剩余数量不足,保存当前剩余礼物作为上期剩余
$remaining_gifts = $available_gifts;
$available_gifts = $this->resetPoolAndReload($gift_bag_id);
if (empty($available_gifts)) {
return ['code' => 0, 'msg' => '奖池无可用礼物', 'data' => null];
}
$this->getCachedPanDrawTimes($gift_bag_id, "clear");
}
return [
'code' => 1,
'msg' => '奖池准备完成',
'data' => [
'available_gifts' => $available_gifts,
'remaining_gifts' => $remaining_gifts
]
];
}
/**
* 执行礼物抽取
*/
private function performGiftDrawing($gift_bag_id, $available_gifts, $remaining_gifts, $num, $periods)
{
$drawn_gifts = [];
$precomputed_results = [];
$available_giftss = [];
$inventory_updates = [];
// 先处理上期剩余的礼物
if (!empty($remaining_gifts)) {
foreach ($remaining_gifts as $remaining_gift) {
$gift_id = $remaining_gift['foreign_id'];
$drawn_gifts[$gift_id] = ($drawn_gifts[$gift_id] ?? 0) + 1;
$precomputed_results[] = [
'gift_id' => $gift_id,
'gift_detail_id' => $remaining_gift['id'],
'gift_bag_detail' => $remaining_gift,
'gift' => Db::name('vs_gift')->where(['gid' => $gift_id])->find(),
'gift_user_id' => 0,
'periods' => $periods,
];
}
}
// 计算还需要抽取的数量
$remaining_count = $num - count($remaining_gifts);
// 抽取新礼物
for ($i = 0; $i < $remaining_count; $i++) {
$selected_gift = $this->selectGiftFromAvailable($available_gifts);
if (!$selected_gift) {
$gift_bag_detail = $this->resetPoolAndReload($gift_bag_id);
$selected_gift = $this->selectGiftFromAvailable($gift_bag_detail);
if (!$selected_gift) {
return ['code' => 0, 'msg' => '预计算抽奖失败,重置后无可用礼物', 'data' => null];
}
}
// 记录库存变化
$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;
// 记录完整结果
$result_entry = [
'gift_id' => $gift_id,
'gift_detail_id' => $selected_gift['id'],
'gift_bag_detail' => $selected_gift,
'gift' => Db::name('vs_gift')->where(['gid' => $gift_id])->find(),
'gift_user_id' => 0,
'periods' => $periods,
];
$available_giftss[] = $result_entry;
$precomputed_results[] = $result_entry;
$this->updateCachedGiftBagDetail($gift_bag_id, $selected_gift['id']);
$this->getCachedPanTotalRemaining($gift_bag_id, "set");
$this->getCachedPanDrawTimes($gift_bag_id, "set");
}
// 检查是否需要重置奖池
$total_remaining = $this->getCachedPanTotalRemaining($gift_bag_id);
if ($total_remaining <= 0) {
$new_gifts = $this->resetPoolAndReload($gift_bag_id);
if (empty($new_gifts)) {
return ['code' => 0, 'msg' => '重置奖池后仍无可用礼物', 'data' => null];
}
}
return [
'code' => 1,
'msg' => '抽奖完成',
'data' => [
'drawn_gifts' => $drawn_gifts,
'precomputed_results' => $precomputed_results,
'available_giftss' => $available_giftss
]
];
}
/**
* 创建抽奖日志
*/
private function createDrawLog($user_id, $gift_bag_id, $num, $room_id, $bag_data)
{
return 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()
]);
}
/**
* 发送礼物给接收者
*/
private function sendGiftsToRecipientsPack($drawn_gifts,$user_id,$bag_data)
{
$giftCounts =[];
// 批量发送礼物
foreach ($drawn_gifts as $gift_id => $count) {
$res = model('api/UserGiftPack')->change_user_gift_pack(
$user_id,
$gift_id,
$count,
model('api/UserGiftPack')::BLANK_BOX_DRAW_GIFT_GET,
$bag_data['gift_bag_name']."抽奖所得"
);
if ($res['code'] != 1) {
throw new \Exception($res['msg']);
}
$giftCounts[]=[
'gift_id' => $gift_id,
'count' => $count
];
}
return ['code' => 1, 'msg' => '发送礼物成功', 'data' => $giftCounts];
}
} }

View File

@@ -130,7 +130,7 @@ class Nobility extends Model
//购买爵位 //购买爵位
public function buyNobility($user_id,$lid){ public function buyNobility($user_id,$lid){
$nobility_info = db::name('vs_nobility') $nobility_info = db::name('vs_nobility')
->field('lid,name,pay_price,pay_coin,day') ->field('lid,name,pay_price,renew_price,pay_coin,day,renew_coin')
->where('delete_time', 0) ->where('delete_time', 0)
->where('lid', $lid) ->where('lid', $lid)
->find(); ->find();

View File

@@ -42,6 +42,8 @@ class UserGiftPack extends Model
const TASK_REWARD = 11; const TASK_REWARD = 11;
//每日签到 //每日签到
const DAILY_SIGN = 12; const DAILY_SIGN = 12;
//盲盒转盘抽奖所得
const BLANK_BOX_DRAW_GIFT_GET = 13;
public static function init() public static function init()
{ {
@@ -63,7 +65,8 @@ class UserGiftPack extends Model
self::HOUR_RANK_GET => '小时榜获得', self::HOUR_RANK_GET => '小时榜获得',
self::NEW_CHARGE_GIFT => '新人充值好礼', self::NEW_CHARGE_GIFT => '新人充值好礼',
self::TASK_REWARD => '任务奖励', self::TASK_REWARD => '任务奖励',
self::DAILY_SIGN => '每日签到' self::DAILY_SIGN => '每日签到',
self::BLANK_BOX_DRAW_GIFT_GET => '盲盒转盘抽奖所得'
]; ];
} }

View File

@@ -19,12 +19,12 @@ class Test
{ {
// 设置脚本执行时间无限 // 设置脚本执行时间无限
set_time_limit(0); set_time_limit(0);
echo "统计盲盒转盘错误数据\n"; echo "清洗任务数据\n";
// $this->blind_box_error(); // $this->blind_box_error();
// $this->xlh_gift_send(); // $this->xlh_gift_send();
// echo "\n"; // echo "\n";
// //
$this->task_history_send(); $this->clean_task_data();
} }
@@ -455,4 +455,43 @@ class Test
echo "清除房间离线用户完成 (".$res_i.") \n"; echo "清除房间离线用户完成 (".$res_i.") \n";
} }
//清洗任务数据
public function clean_task_data(){
echo "开始清洗任务数据 \n";
$task_student = Db::name('vs_tasks_student')->where(['status'=>2,'delete_time'=>0])->select();
foreach ($task_student as $value) {
$tasks_bag_id = db::name('vs_tasks')->where(['id'=>$value['task_id']])->value('tasks_bag_id');
$insert_data =[
'user_id' => $value['user_id'],
'task_id' => $value['task_id'],
'tasks_bag_id' => $tasks_bag_id,
'is_completed' => 1,
'is_claimed' => 1,
'createtime' => time(),
'updatetime' => time(),
'completion_time' => $value['createtime'],
'collection_time' => $value['updatetime'],
];
Db::name('vs_tasks_user_daily')->insert($insert_data);
echo "清洗师徒任务数据成功:".$value['id']."\n";
}
$user_couple_task = Db::name('vs_user_cp_task')->where(['status'=>2 ,'delete_time'=>0])->select();
foreach ($user_couple_task as $value) {
$tasks_bag_id = db::name('vs_tasks')->where(['id'=>$value['tasks_bag_id']])->value('tasks_bag_id');
Db::name('vs_tasks_user_daily')->insert([
'user_id' => $value['user_id'],
'task_id' => $value['tasks_bag_id'],
'tasks_bag_id' => $tasks_bag_id,
'is_completed' => 1,
'is_claimed' => 1,
'createtime' => time(),
'updatetime' => time(),
'completion_time' => $value['createtime'],
'collection_time' => $value['createtime'],
]);
echo "清洗CP任务数据成功".$value['id']."\n";
}
echo "清洗任务数据完成 \n";
}
} }