diff --git a/application/adminapi/controller/User.php b/application/adminapi/controller/User.php index 036a6513..d1c5f150 100644 --- a/application/adminapi/controller/User.php +++ b/application/adminapi/controller/User.php @@ -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'); diff --git a/application/api/controller/BlindBoxTurntable.php b/application/api/controller/BlindBoxTurntable.php index a40a692e..fe317a0d 100644 --- a/application/api/controller/BlindBoxTurntable.php +++ b/application/api/controller/BlindBoxTurntable.php @@ -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']); } /* diff --git a/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php index 6d0d9a9e..bd786b53 100644 --- a/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php +++ b/application/api/model/BlindBoxTurntableGiftDrawWorldNew.php @@ -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]; + } } \ No newline at end of file diff --git a/application/api/model/Nobility.php b/application/api/model/Nobility.php index 6c8a6e7f..b5e115e7 100644 --- a/application/api/model/Nobility.php +++ b/application/api/model/Nobility.php @@ -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(); diff --git a/application/api/model/UserGiftPack.php b/application/api/model/UserGiftPack.php index 4de60800..42206b06 100644 --- a/application/api/model/UserGiftPack.php +++ b/application/api/model/UserGiftPack.php @@ -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 => '盲盒转盘抽奖所得' ]; } diff --git a/application/cron/controller/Test.php b/application/cron/controller/Test.php index 3402960a..c05aa7c5 100644 --- a/application/cron/controller/Test.php +++ b/application/cron/controller/Test.php @@ -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"; +} + } \ No newline at end of file