盲盒转盘-岁月之城,时空之旅,抽奖结果转落包。
This commit is contained in:
@@ -158,12 +158,14 @@ class User extends adminApi
|
||||
$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('user_wallet c', 'a.id = c.user_id','LEFT')
|
||||
->where(['a.delete_time'=>0])
|
||||
->where($where)
|
||||
->field($field)
|
||||
->sum('c.coin');
|
||||
$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('user_wallet c', 'a.id = c.user_id','LEFT')
|
||||
->where(['a.delete_time'=>0])
|
||||
->where($where)
|
||||
->field($field)
|
||||
->sum('c.earnings');
|
||||
|
||||
@@ -40,7 +40,15 @@ class BlindBoxTurntable extends BaseCom
|
||||
$num = input('num',1);
|
||||
$heart_id = input('heart_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']);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -391,16 +391,29 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||||
*/
|
||||
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')]);
|
||||
$lockKey = "reset_pool_lock_".$gift_bag_id;
|
||||
|
||||
// 清除缓存
|
||||
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)
|
||||
{
|
||||
Db::name("vs_gift_bag_detail")
|
||||
$result = Db::name("vs_gift_bag_detail")
|
||||
->where(['id' => $gift_bag_detail_id])
|
||||
->where('remaining_number', '>', 0) // 确保库存充足
|
||||
->setDec('remaining_number', 1);
|
||||
if (!$result) {
|
||||
throw new \Exception('礼物库存不足');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,7 +667,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||||
db::startTrans();
|
||||
// 按照固定顺序处理事务步骤
|
||||
// 1. 扣除用户金币(优先处理)
|
||||
$this->deductUserCoins($user_id, $total_price, $room_id);
|
||||
$this->deductUserCoins($user_id, $total_price, $room_id,$bag_data);
|
||||
// 2. 创建抽奖记录
|
||||
$boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([
|
||||
'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')
|
||||
@@ -711,7 +728,7 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||||
$room_id,
|
||||
1,
|
||||
10,
|
||||
'盲盒转盘抽奖消耗'
|
||||
$bag_data['gift_bag_name'] .'抽奖消耗'
|
||||
);
|
||||
if (!$walletUpdate) {
|
||||
throw new \Exception('扣除用户金币失败');
|
||||
@@ -1175,7 +1192,13 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||||
// 批量更新库存
|
||||
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);
|
||||
$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)) {
|
||||
@@ -1405,4 +1428,302 @@ class BlindBoxTurntableGiftDrawWorldNew extends Model
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class Nobility extends Model
|
||||
//购买爵位
|
||||
public function buyNobility($user_id,$lid){
|
||||
$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('lid', $lid)
|
||||
->find();
|
||||
|
||||
@@ -42,6 +42,8 @@ class UserGiftPack extends Model
|
||||
const TASK_REWARD = 11;
|
||||
//每日签到
|
||||
const DAILY_SIGN = 12;
|
||||
//盲盒转盘抽奖所得
|
||||
const BLANK_BOX_DRAW_GIFT_GET = 13;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
@@ -63,7 +65,8 @@ class UserGiftPack extends Model
|
||||
self::HOUR_RANK_GET => '小时榜获得',
|
||||
self::NEW_CHARGE_GIFT => '新人充值好礼',
|
||||
self::TASK_REWARD => '任务奖励',
|
||||
self::DAILY_SIGN => '每日签到'
|
||||
self::DAILY_SIGN => '每日签到',
|
||||
self::BLANK_BOX_DRAW_GIFT_GET => '盲盒转盘抽奖所得'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ class Test
|
||||
{
|
||||
// 设置脚本执行时间无限
|
||||
set_time_limit(0);
|
||||
echo "统计盲盒转盘错误数据\n";
|
||||
echo "清洗任务数据\n";
|
||||
// $this->blind_box_error();
|
||||
// $this->xlh_gift_send();
|
||||
// echo "\n";
|
||||
//
|
||||
$this->task_history_send();
|
||||
$this->clean_task_data();
|
||||
|
||||
}
|
||||
|
||||
@@ -455,4 +455,43 @@ class Test
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user