where('id',$gift_bag_id)->find(); $gifts = db::name('vs_gift_bag_detail')->where('gift_bag_id',$gift_bag_id)->order("id desc")->select(); $gift_list = []; foreach ($gifts as $key => $value) { $gift_data = db::name('vs_gift')->where('gid',$value['foreign_id'])->where('delete_time',0)->find(); if($gift_data){ $gift_list[$key]['number'] = $key; $gift_list[$key]['gift_id'] = $gift_data['gid']; $gift_list[$key]['gift_name'] = $gift_data['gift_name']; $gift_list[$key]['base_image'] = $gift_data['base_image']; $gift_list[$key]['play_image'] = $gift_data['play_image']; $gift_list[$key]['gift_price'] = $gift_data['gift_price']; } } $ext = json_decode($box['ext'],true); $box_gift = Db::name('vs_gift')->where('gid',$ext['gift_id'])->find(); //巡乐会 $is_xlh = 0; $xlh_box = db::name('vs_gift_bag')->where('id',13)->find(); $xlh_ext = json_decode($xlh_box['ext'],true); $xlh = []; if($xlh_ext['inlet_bag_id'] == $box['id']){ $room = db::name('vs_room')->field('id,xlh_periods,xlh_periods_num')->where(['id'=>$room_id])->find(); $is_xlh = 1; $xlh['waiting_start_num'] = $xlh_ext['open_condition']['waiting_start_num'];//等待开奖次数 $xlh['start_num'] = $xlh_ext['open_condition']['start_num'];//开始开奖次数 //当前抽奖次数 $xlh['current_num'] = $room['xlh_periods_num']; //状态 if($xlh['current_num'] >= $xlh_ext['open_condition']['start_num']){ $xlh['status'] = 1;//状态 1:巡乐会开始 2:即将开始开始 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; } } $result_data = [ 'title' => $box['name'], 'rule_url' => get_system_config_value('web_site')."/api/Page/get_gift_box_rule?box_id=".$box["id"], 'box_price' => $box_gift['gift_price'], 'is_xlh' => $is_xlh, 'xlh_data' => $xlh, 'gift_list' => $gift_list, ]; return ['code' => 1, 'msg' => '获取成功', 'data' => $result_data]; } /* * 抽奖 */ public function draw_gift($gift_bag_id, $user_id, $gift_user_ids,$num=1,$room_id=0,$heart_id=0) { // 合并配置查询 $bag_data = db::name("vs_gift_bag") ->field('id,name,ext') ->where('id',$gift_bag_id) ->find(); if (!$bag_data) { return ['code' => 0, 'msg' => '盲盒配置不存在', 'data' => null]; } $ext = json_decode($bag_data['ext'],true); // 合并盲盒和礼物信息查询 $bag_gift = db::name("vs_gift") ->where(['gid'=>$ext['gift_id']]) ->find(); if (!$bag_gift) { return ['code' => 0, 'msg' => '盲盒礼物不存在', 'data' => null]; } // 合并巡乐会配置查询 $xlh_box = db::name('vs_gift_bag') ->where('id',13) ->find(); $xlh_ext = $xlh_box ? json_decode($xlh_box['ext'],true) : []; $xlh_is_piao_ping = 0; // 处理收礼用户数组(多个) $toarray = explode(',',$gift_user_ids); // 合并房间信息查询 $room = db::name('vs_room') ->field('id,room_name,xlh_periods,xlh_periods_num,is_open_blind_box_turntable') ->where(['id'=>$room_id]) ->find(); if (!$room) { return ['code' => 0, 'msg' => '房间不存在', 'data' => null]; } $this_xlh_periods_num = $room['xlh_periods_num'];//本期当前抽奖次数(巡乐会出发条件) // 判断是否有足够的金币 $user_waller = db::name('user_wallet') ->where(['user_id'=>$user_id]) ->find(); if (!$user_waller) { return ['code' => 0, 'msg' => '用户钱包不存在', 'data' => null]; } // 抽奖总消耗金币 $bag_gift_price = $bag_gift['gift_price'] * $num; if ($user_waller['coin'] < $bag_gift_price) { return ['code' => 0, 'msg' => '用户金币不足', 'data' => null]; } if ($room['is_open_blind_box_turntable'] != 1) { return ['code' => 0, 'msg' => '该房间未开启盲盒转盘', 'data' => null]; } // 预计算抽奖结果,减少数据库事务中的查询 // 计算期数和抽奖次数 // 合并奖池总抽奖次数和房间奖池信息查询 $room_pan_info = db::name("vs_gift_bag_detail") ->alias('a') ->join('vs_room_pan b', 'b.gift_bag_detail_id = a.id AND b.room_id = ' . $room_id) ->where(['a.gift_bag_id' => $gift_bag_id]) ->field('SUM(a.quantity) as total_quantity, SUM(b.remaining_number) as total_remaining, MAX(b.periods) as periods') ->find(); $total_quantity = $room_pan_info['total_quantity'] ?: 0; $total_remaining = $room_pan_info['total_remaining'] ?: 0; $periods = $room_pan_info['periods'] ?: 0; // 本期当前第多少次后抽奖 总的抽奖次数- 剩余数量 $total_draw_times = $total_quantity - $total_remaining; if($total_draw_times<0){ $total_draw_times = 0; } // 预计算所有抽奖结果 $precomputed_results = []; $current_draw_times = $total_draw_times; $current_periods = $periods; $current_xlh_periods_num = $this_xlh_periods_num; // 生成缓存键 $available_cache_key = 'blindbox_available_gifts_' . $gift_bag_id . '_' . $room_id; $last_remaining_cache_key = 'blindbox_last_remaining_' . $gift_bag_id . '_' . $room_id; // 获取所有可用礼物用于预计算 $available_gifts = $this->get_available_gifts_for_precompute($gift_bag_id, $room_id, $current_draw_times); if (empty($available_gifts)) { return ['code' => 0, 'msg' => '当前盲盒无可用礼物', 'data' => null]; } $should_reset_all_gifts = false; // 标记是否需要重置所有礼物 //如果本期奖池数量小于抽奖次数,则重置奖池,并把上期剩余数量加到本期奖池中 //接收礼物人数 $receive_num = count($toarray); //需要的礼物数量 $need_gift_num = $receive_num * $num; $last_periods_remaining = []; if ($total_remaining - $need_gift_num <= 0 ) { //上期剩余礼物 $last_periods_remaining = $available_gifts; //加入缓存 cache($last_remaining_cache_key, $last_periods_remaining); // 重置奖池 $current_periods++; $this->reset_gift_pool($room_id, $gift_bag_id, $current_periods); //补充上期剩余数量 foreach ($available_gifts as $gift_data) { db::name("vs_room_pan") ->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id,'gift_bag_detail_id'=>$gift_data['id']]) ->setInc('remaining_number', $gift_data['remaining_number']); } // 重新获取可用礼物 $current_draw_times = 0; $available_gifts = $this->get_available_gifts_for_precompute($gift_bag_id, $room_id, $current_draw_times); $should_reset_all_gifts = false; // 重置标记 } //加入缓存 cache($available_cache_key, $available_gifts); // 预计算所有抽奖结果 foreach ($toarray as $gift_user_id) { if($user_id == $gift_user_id){ return ['code' => 0, 'msg' => "收礼人不能包含自己", 'data' => null]; } for($i = 0; $i < $num; $i++){ // 使用加权随机算法预计算单次抽奖结果 //从缓存中取出可用礼物 if(cache($available_cache_key)){ $available_gifts = cache($available_cache_key); } if(cache($last_remaining_cache_key)){ $last_periods_remaining = cache($last_remaining_cache_key); } $draw_result = $this->precompute_single_draw($gift_bag_id,$room_id,$available_gifts,$last_periods_remaining); if (!$draw_result) { return ['code' => 0, 'msg' => '预计算抽奖失败', 'data' => null]; } $precomputed_results[] = [ 'gift_user_id' => $gift_user_id, 'gift_bag_detail' => $draw_result['gift_bag_detail'], 'gift' => $draw_result['gift'], 'draw_times' => $current_draw_times, 'periods' => $current_periods ]; $current_draw_times++; // 判断巡乐会飘屏判断 $current_xlh_periods_num++; if(!empty($xlh_ext) && $xlh_ext['inlet_bag_id'] == $gift_bag_id && $current_xlh_periods_num == $xlh_ext['open_condition']['waiting_start_num']){ $xlh_is_piao_ping = 1; } if(!empty($xlh_ext) && $xlh_ext['inlet_bag_id'] == $gift_bag_id && $current_xlh_periods_num == $xlh_ext['open_condition']['start_num']){ $xlh_is_piao_ping = 2; } // 更新可用礼物数量(模拟数据库更新) $total_remaining_after_update = 0; foreach ($available_gifts as &$gift) { if ($gift['id'] == $draw_result['gift_bag_detail']['id']) { $gift['remaining_number']--; } // 计算更新后的总剩余数量 $total_remaining_after_update += $gift['remaining_number']; } // 检查是否需要重置所有礼物 if ($total_remaining_after_update <= 0) { $should_reset_all_gifts = true; $current_periods++; // 增加期数 } } } // 清除相关缓存 cache($available_cache_key, null); cache($last_remaining_cache_key, null); // 开始数据库事务处理 db::startTrans(); try{ // 盲盒转盘抽奖记录 $box_turntable_log = db::name('vs_blind_box_turntable_log')->insertGetId([ 'user_id' => $user_id, 'gift_bag_id' => $gift_bag_id, 'num' => $num, 'room_id' => $room_id, 'bag_price' => $bag_gift['gift_price'], 'createtime' => time() ]); if (!$box_turntable_log) { db::rollback(); return ['code' => 0, 'msg' => '添加盲盒转盘记录失败', 'data' => null]; } // 处理预计算的抽奖结果 $result_draw_gift = []; $gift_counts = []; // 统计每个礼物的数量 $gift_user_counts = []; // 统计每个用户每个礼物的数量 foreach ($precomputed_results as $result) { $gift_user_id = $result['gift_user_id']; $gift_bag_detail = $result['gift_bag_detail']; $gift = $result['gift']; $pan_data = db::name("vs_room_pan") ->where(['room_id'=>$room_id,'gift_bag_detail_id'=>$gift_bag_detail['id']])->value("remaining_number"); if($pan_data < 1){ db::rollback(); return ['code' => 0, 'msg' => '礼物数量不足', 'data' => null]; } // 构造返回数据 $result_data = [ 'user_id' => $user_id, 'gift_user_id' => $gift_user_id, 'gift_id' => $gift_bag_detail['foreign_id'], 'gift_price' => $gift['gift_price'], 'is_public_screen' => $gift['is_public_screen'], 'periods' => $result['periods'], ]; $result_draw_gift[] = $result_data; // 统计礼物数量 $gift_id = $gift_bag_detail['foreign_id']; if (!isset($gift_counts[$gift_id])) { $gift_counts[$gift_id] = [ 'gift_id' => $gift_id, 'count' => 0, 'gift_price' => $gift['gift_price'] ]; } $gift_counts[$gift_id]['count']++; // 统计用户礼物数量 $user_gift_key = $gift_user_id . '_' . $gift_id; if (!isset($gift_user_counts[$user_gift_key])) { $gift_user_counts[$user_gift_key] = [ 'gift_user_id' => $gift_user_id, 'gift_id' => $gift_id, 'count' => 0, 'gift_price' => $gift['gift_price'] ]; } $gift_user_counts[$user_gift_key]['count']++; // 处理礼包发放记录表 $data = []; $data['user_id'] = $user_id; $data['gift_user_id'] = $gift_user_id; $data['parent_id'] = $box_turntable_log; $data['gift_bag_id'] = $gift_bag_id; $data['gift_id'] = $gift_bag_detail['foreign_id']; $data['periods'] = $result['periods']; $data['room_id'] = $room_id; $data['gift_price'] = $gift['gift_price']; $data['bag_price'] = $bag_gift['gift_price']; $data['createtime'] = time(); $insert_result = db::name("vs_gift_bag_receive_log")->insert($data); if(!$insert_result){ db::rollback(); return ['code' => 0, 'msg' => '插入礼包发放记录失败', 'data' => []]; } // 减去盲盒包礼物数量 $ret = db::name("vs_room_pan") ->where(['room_id'=>$room_id,'gift_bag_detail_id'=>$gift_bag_detail['id'],"remaining_number"=>["<>",0]]) ->setDec('remaining_number',1); if(!$ret){ db::rollback(); return ['code' => 0, 'msg' => '更新礼物剩余数量失败', 'data' => []]; } } // 扣除抽奖消耗的金币 // 扣除用户金币并记录日志 $wallet_update = model('GiveGift')->change_user_cion_or_earnings_log($user_id,$bag_gift_price,$room_id,1,10,'盲盒转盘抽奖消耗'); if(!$wallet_update){ Db::rollback(); return ['code' => 0, 'msg' => '扣除用户金币失败', 'data' => null]; } // 用户财富等级更新 $user_level = model('Level')->user_level_data_update($user_id,$bag_gift_price,1,$room_id); if(!$user_level){ Db::rollback(); return ['code' => 0, 'msg' => '用户等级更新失败', 'data' => null]; } db::commit(); } catch(\Exception $e) { db::rollback(); return V(0,$e->getMessage()); } // 批量插入盲盒转盘结果记录 foreach ($gift_user_counts as $user_gift) { $ret = db::name('vs_blind_box_turntable_results_log')->insert([ 'tid' => $box_turntable_log, 'gift_user_id' => $user_gift['gift_user_id'], 'gift_id' => $user_gift['gift_id'], 'count' => $user_gift['count'], 'gift_price' => $user_gift['gift_price'], 'all_gift_price' => $user_gift['gift_price'] * $user_gift['count'], 'createtime' => time(), 'heart_id' => $heart_id ]); if (!$ret) { return ['code' => 0, 'msg' => '添加盲盒转盘结果记录失败', 'data' => null]; } //给接收礼物的人送礼物 $give_gift_ext['gift_id'] = $user_gift['gift_id']; $give_gift_ext['count'] = $user_gift['count']; $give_gift_ext['gift_price'] = $user_gift['gift_price']; $give_gift_ext['all_gift_price'] = $user_gift['gift_price'] * $user_gift['count']; $give_gift_ext['is_draw_gift'] = 1; $res = model('Room')->room_gift($user_id, $user_gift['gift_user_id'], $user_gift['gift_id'], $user_gift['count'], 1, $room_id, 0,$heart_id,$give_gift_ext); if (isset($res) && $res['code'] != 1) { db::rollback(); return ['code' => 0, 'msg' => $res['msg'], 'data' => null]; } } // 巡乐会 $xlh = []; if(!empty($xlh_ext) && $xlh_ext['inlet_bag_id'] == $gift_bag_id){ // 巡乐会飘屏 db::name("vs_room")->where('id',$room_id)->update([ 'xlh_periods_num' => $current_xlh_periods_num ]);//加巡乐会条件次数 if($xlh_is_piao_ping == 1){ // 即将开始推送飘屏 $text = $room['room_name']."的巡乐会即将开始,请大家尽快参与哦!"; // 推送礼物横幅 $push = new Push(UID, $room_id); $text_list_new = [ 'text' => $text, 'room_id' => $room_id, 'from_type' => 1 ]; $push->xunlehui($text_list_new); } if($xlh_is_piao_ping == 2){ // 正式开始推送飘屏 $text = $room['room_name']."的巡乐会正式开始,请大家尽快参与哦!"; // 推送礼物横幅 $push = new Push(UID, $room_id); $text_list_new = [ 'text' => $text, 'room_id' => $room_id, 'from_type' => 2 ]; $push->xunlehui($text_list_new); // 巡乐会正式开始 $this_xlh_periods = db::name('vs_room')->where('id',$room_id)->value('xlh_periods'); $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' => []]; } db::name("vs_room")->where('id',$room_id)->setInc('xlh_periods');//修改巡乐会期数 } $xlh['waiting_start_num'] = $xlh_ext['open_condition']['waiting_start_num'];//等待开奖次数 $xlh['start_num'] = $xlh_ext['open_condition']['start_num'];//开始开奖次数 // 当前抽奖次数 $xlh['current_num'] = $current_xlh_periods_num; // 状态 if($xlh['current_num'] >= $xlh_ext['open_condition']['start_num']){ $xlh['status'] = 1;//状态 1:巡乐会开始 2:即将开始开始 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; } // 推送 $text = [ 'xlh_data' => $xlh, 'text' => "" ]; // 聊天室推送系统消息 model('Chat')->sendMsg(1056,$room_id,$text); } // 整理返回结果 $result_list = []; foreach ($gift_counts as $gift) { $result_list[] = [ 'gift_id' => $gift['gift_id'], 'count' => $gift['count'] ]; } $reslut = []; $reslut['blind_box_turntable_id'] = $box_turntable_log; $reslut['reslut_list'] = $result_list; return V(1,"成功", $reslut); } /** * 重置奖池 * @param int $room_id 房间ID * @param int $gift_bag_id 礼物包ID * @param int $periods 期数 */ private function reset_gift_pool($room_id, $gift_bag_id, $periods) { // 重置奖池中所有礼物数量 db::name("vs_room_pan") ->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id]) ->update([ 'remaining_number' => db::raw('(SELECT quantity FROM fa_vs_gift_bag_detail WHERE id = fa_vs_room_pan.gift_bag_detail_id)'), 'periods' => $periods ]); // 更新总期数 db::name("vs_gift_bag") ->where('id', $gift_bag_id) ->setInc('periods'); } /* * 获取可用礼物用于预计算 */ private function get_available_gifts_for_precompute($gift_bag_id, $room_id, $total_draw_times) { $where = [ 'a.gift_bag_id' => $gift_bag_id, 'a.quantity' => ['>',0], 'b.remaining_number' => ['>',0], 'b.room_id' => $room_id, 'a.weight' => ['<=', $total_draw_times], ]; return db::name("vs_gift_bag_detail") ->field('a.id,a.quantity,b.remaining_number,a.weight,a.foreign_id') ->alias('a') ->join('vs_room_pan b','b.gift_bag_detail_id = a.id','left') ->where($where) ->select(); } /* * 预计算单次抽奖结果 */ private function precompute_single_draw($gift_bag_id, $room_id, $available_gifts, $last_periods_remaining = []) { // 生成缓存键 $available_cache_key = 'blindbox_available_gifts_' . $gift_bag_id . '_' . $room_id; $last_remaining_cache_key = 'blindbox_last_remaining_' . $gift_bag_id . '_' . $room_id; // 保证有可用礼物 if (empty($available_gifts)) { return false; } $last_remaining_all = array_sum(array_column($last_periods_remaining, 'remaining_number')); if ($last_remaining_all == 0) { $last_periods_remaining = []; cache($last_remaining_cache_key, null); } $last_periods_remaining_flag = 0; if (!empty($last_periods_remaining)) { $available_gifts = $last_periods_remaining; $last_periods_remaining_flag = 1; } // 循环尝试直到抽中有效礼物 $max_attempts = 5; // 最大尝试次数,防止无限循环 $attempt = 0; $selected_gift = null; while ($attempt < $max_attempts && !$selected_gift) { // 实现加权随机算法:剩余数量越多,被抽中的概率越大 $remaining = 0; foreach ($available_gifts as $gift) { $remaining += $gift['remaining_number']; } if ($remaining <= 0) { break; // 如果没有剩余数量,跳出循环 } $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++; } if (!$selected_gift) { return false; } // 获取开出礼物的信息 $gift = db::name("vs_gift") ->where(['gid' => $selected_gift['foreign_id']]) ->find(); if (!$gift) { return false; } // 操作缓存,减去缓存中对应数据数量 foreach ($available_gifts as &$available_gifts_gift) { if ($selected_gift['id'] == $available_gifts_gift['id']) { $available_gifts_gift['remaining_number'] -= 1; } } if ($available_gifts_gift['remaining_number'] == 0) { unset($available_gifts_gift); } if ($last_periods_remaining_flag == 1) { // 操作上一轮奖池 cache($last_remaining_cache_key, $available_gifts); } else { cache($available_cache_key, $available_gifts); } return [ 'gift_bag_detail' => $selected_gift, 'gift' => $gift ]; } /* * 礼物特效播放 */ public function gift_send($send_id){ try{ $blind_box_turntable = db('vs_blind_box_turntable_log')->where(['id'=>$send_id,'is_sued'=>0])->find(); if(!$blind_box_turntable){ return ['code' => 1, 'msg' => '成功', 'data' => null]; } $room_id = $blind_box_turntable['room_id']; $blind_box_turntable_log = db('vs_blind_box_turntable_results_log')->where(['tid'=>$send_id])->select(); if(!$blind_box_turntable_log){ return ['code' => 0, 'msg' => '数据不存在','data' => null]; } $room_name = Db::name('vs_room')->where(['id' => $room_id, 'apply_status' => 2])->value('room_name'); $FromUserInfo = Db::name('user')->where(['id'=>$blind_box_turntable['user_id']])->find(); $FromUserInfo['icon'][0] = model('UserData')->user_wealth_icon($blind_box_turntable['user_id']);//财富图标 $FromUserInfo['icon'][1] = model('UserData')->user_charm_icon($blind_box_turntable['user_id']);//魅力图标 $user_nickname = $FromUserInfo['nickname']; $textMessage = $user_nickname; $text_message = []; foreach ($blind_box_turntable_log as $key => $value) { $ToUserInfo = Db::name('user')->where(['id' => $value['gift_user_id']])->field('id as user_id,nickname,avatar,sex')->find(); $draw_gift = Db::name('vs_gift')->where(['gid'=>$value['gift_id']])->find(); $textMessage = $textMessage . ' 送给 ' . $ToUserInfo['nickname']. ' 盲盒转盘礼物 ' . $draw_gift['gift_name'].' x ' .$value['count']."\n"; $play_image[] = $draw_gift['play_image']; $gift_names[] = $draw_gift['gift_name']; $text_message = $user_nickname . '在' . $room_name . '房间送给了' . $ToUserInfo['nickname'] . $draw_gift['gift_name'] . 'X' . $value['count']."\n"; if($draw_gift['is_public_server'] == 1) { $text_list_new[] = [ 'text' => $text_message, 'gift_picture' => $draw_gift['base_image'], 'room_id' => $room_id, 'fromUserName' => $FromUserInfo['nickname'], 'toUserName' => $ToUserInfo['nickname'], 'giftName' => $draw_gift['gift_name'], 'roomId' => $room_id, 'number' => $value['count'], ]; } $ToUserInfosList[$value['gift_user_id']] = $ToUserInfo; } foreach($ToUserInfosList as &$userInfo) { $userInfo['icon'][0] = model('UserData')->user_wealth_icon($userInfo['user_id']);//财富图标 $userInfo['icon'][1] = model('UserData')->user_charm_icon($userInfo['user_id']);//魅力图标 $userInfo['charm'] = db::name('vs_room_user_charm')->where(['user_id' => $userInfo['user_id'],'room_id' => $room_id])->value('charm');//魅力 $ToUserInfos[] = $userInfo; } $text = [ 'FromUserInfo' => $FromUserInfo, 'ToUserInfos' => $ToUserInfos, 'GiftInfo' => [ 'play_image' => implode(',',$play_image), 'gift_name' => implode(',',$gift_names), ], 'text' => rtrim($textMessage, "\n") ]; //聊天室推送系统消息 model('Chat')->sendMsg(1005,$room_id,$text); $roomtype = Db::name('vs_room')->where(['id' => $room_id])->value('type_id'); if($roomtype == 6){ //推送消息 $hot_value = db::name('vs_give_gift')->where('from_id', $room_id)->where('from',6) ->sum('total_price'); $text1 = [ 'room_id' => $room_id, 'hot_value' => $hot_value * 10, 'text' => '房间心动值变化' ]; //聊天室推送系统消息 model('Chat')->sendMsg(1028,$room_id,$text1); }else{ if(!empty($text_list_new)){ //推送礼物横幅 $push = new Push($blind_box_turntable['user_id'], $room_id); $push->giftBanner($text_list_new); } } db::name('vs_blind_box_turntable_log')->where('id', $send_id)->update(['is_sued' => 1, 'updatetime' => time()]); return ['code' => 1, 'msg' => '成功', 'data' => null]; } catch (\Exception $e) { return ['code' => 0, 'msg' => "网络请求错误,请重试!", 'data' => null]; } } /* * 获取用户抽奖记录 */ public function get_user_record($gift_bag_id,$user_id=0,$page=1,$page_size=12){ $where = []; $where['b.gift_bag_id'] = $gift_bag_id; if($user_id > 0){ $where['b.user_id'] = $user_id; } $list = db('vs_blind_box_turntable_results_log') ->alias('a') ->join('vs_blind_box_turntable_log b','b.id = a.tid','left') ->join('user c','a.gift_user_id = c.id','left') ->join('vs_gift d','d.gid = a.gift_id','left') ->field('a.gift_id,a.count,a.gift_user_id,a.createtime,c.nickname,d.gift_name as gift_name,d.base_image') ->where($where) ->order('a.createtime desc') ->page($page,$page_size) ->select(); foreach ($list as &$v){ $v['createtime'] = date('Y-m-d H:i:s',$v['createtime']); } return ['code' => 1, 'msg' => '成功', 'data' => $list]; } /* * 获取全服抽奖记录 */ public function get_all_record($gift_bag_id,$page=1,$page_size=12){ $where = []; $where['b.gift_bag_id'] = $gift_bag_id; $where['d.gift_bag_id'] = $gift_bag_id; $where['d.is_world_show'] = 1; $list = db('vs_blind_box_turntable_results_log') ->alias('a') ->join('vs_blind_box_turntable_log b','b.id = a.tid','left') ->join('user c','b.user_id = c.id','left') ->join('vs_gift_bag_detail d','d.foreign_id = a.gift_id','left') ->join('vs_gift e','e.gid = a.gift_id','left') ->field('a.gift_id,a.count,b.user_id,a.createtime,c.nickname,d.name as gift_name,e.base_image') ->where($where) ->order('a.createtime desc') ->page($page,$page_size) ->select(); foreach ($list as &$v){ $v['createtime'] = date('Y-m-d H:i:s',$v['createtime']); } return ['code' => 1, 'msg' => '成功', 'data' => $list]; } /* * 巡乐会 */ public function xlh_gift_list($room_id){ $room_data = db::name('vs_room')->field('xlh_periods,xlh_periods_num,user_id')-> where('id',$room_id)->find(); if(empty($room_data)){ return ['code' => 0, 'msg' => '房间不存在!', 'data' => null]; } $gift_bag_id = 13; $xlh_box = db::name('vs_gift_bag')->where('id',$gift_bag_id)->find(); $xlh_ext = json_decode($xlh_box['ext'],true); $gifts = db::name('vs_gift_bag_detail')->where('gift_bag_id',$gift_bag_id)->order("id desc")->select(); $gift_list = []; foreach ($gifts as $key => $value) { $gift_data = db::name('vs_gift')->where('gid',$value['foreign_id'])->where('delete_time',0)->find(); if($gift_data){ $gift_list[$key]['number'] = $key; $gift_list[$key]['gift_id'] = $gift_data['gid']; $gift_list[$key]['gift_name'] = $gift_data['gift_name']; $gift_list[$key]['base_image'] = $gift_data['base_image']; $gift_list[$key]['play_image'] = $gift_data['play_image']; $gift_list[$key]['gift_price'] = $gift_data['gift_price']; } } //房主信息 $room_user = db::name('user')->where('id',$room_data['user_id'])->find(); //房主礼物 $room_user_gift = db::name('vs_gift')->where('gid',$xlh_ext['locking_condition']['give_homeowner_gift_id'])->find(); //巡乐会主礼物 $xlh_main_gift = db::name('vs_gift')->where('gid',$xlh_ext['locking_condition']['locking_gift_id'])->find(); //中奖用户 $xlh_periods = $room_data['xlh_periods']??0; $pan_xlh = db::name('vs_room_pan_xlh')->where(['room_id'=>$room_id,'periods'=>$xlh_periods,'send_time'=>0])->find(); if(empty($pan_xlh)){ if($room_data['xlh_periods_num'] >= $xlh_ext['open_condition']['start_num']){ $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' => $xlh_periods+1, 'num' => 0, 'end_time' => time() + $xlh_ext['locking_time']['end_time'] * 60, 'createtime' => time() ]); db::name("vs_room")->where('id',$room_id)->setInc('xlh_periods');//修改巡乐会期数 $pan_xlh = db::name('vs_room_pan_xlh')->where(['id'=>$pan_xlh_id])->find(); }else{ return ['code' => 0, 'msg' => '未开始', 'data' => null]; } } $xlh_user_data= null; if($pan_xlh && $pan_xlh['user_id']){ $xlh_user = db::name('user')->where('id',$pan_xlh['user_id'])->find(); $xlh_user_data = [ 'user_id' => $xlh_user['id'], 'nickname' => $xlh_user['nickname'], 'avatar' => $xlh_user['avatar'], ]; } //$gift_list 按gift_price 升序排序 usort($gift_list, function($a, $b) { return $a['gift_price'] - $b['gift_price']; }); $result_data = [ 'title' => $xlh_box['name'], 'rule_url' => get_system_config_value('web_site')."/api/Page/get_gift_box_rule?box_id=".$xlh_box["id"], 'box_price' => $xlh_ext['xlh_box_price'], 'xlh_end_time' =>$pan_xlh['end_time']??0, 'give_homeowner_gift' => [ 'gift_id' => $room_user_gift['gid'], 'gift_name' => $room_user_gift['gift_name'], 'base_image' => $room_user_gift['base_image'], ], 'homeowner_user' => [ 'user_id' => $room_user['id'], 'nickname' => $room_user['nickname'], 'avatar' => $room_user['avatar'], ], 'locking_gift' => [ 'gift_id' => $xlh_main_gift['gid'], 'gift_name' => $xlh_main_gift['gift_name'], 'gift_price' => $xlh_main_gift['gift_price'], 'base_image' => $xlh_main_gift['base_image'], 'gift_num' => $pan_xlh['num']??0 ], 'xlh_user' => $xlh_user_data, 'gift_list' => $gift_list, ]; return ['code' => 1, 'msg' => '获取成功', 'data' => $result_data]; } /* * 巡乐会抽奖 */ public function xlh_draw_gift($user_id,$num,$room_id){ $gift_bag_id = 13; //获取盲盒配置 $bag_data = db::name("vs_gift_bag")->field('id,name,ext,periods')->where('id',$gift_bag_id)->find(); $ext = json_decode($bag_data['ext'],true); //判断是否有足够的金币 $bag_gift_price = $ext['xlh_box_price'] * $num; $user_waller = db::name('user_wallet')->where(['user_id'=>$user_id])->find(); if ($user_waller['coin'] < $bag_gift_price) { return ['code' => 0, 'msg' => '用户金币不足', 'data' => null]; } $room = db::name('vs_room')->where(['id'=>$room_id])->find(); if ($room['is_open_blind_box_turntable'] != 1) { return ['code' => 0, 'msg' => '该房间未开启盲盒转盘', 'data' => null]; } //开始抽奖 $pan_xlh = db::name('vs_room_pan_xlh')->where(['room_id'=>$room_id,'periods'=>$room['xlh_periods']])->find(); if(empty($pan_xlh)){ return ['code' => 0, 'msg' => '未开始', 'data' => null]; } if($pan_xlh['end_time']<=time()){ return ['code' => 0, 'msg' => '本轮已结束', 'data' => null]; } if($pan_xlh['send_time']!=0){ return ['code' => 0, 'msg' => '本轮已结束,礼物已发放', 'data' => null]; } $is_zhong_jiang = 0; $pan_xlh_num = $pan_xlh['num']; //奖池总的抽奖次数 $total_quantity = db::name("vs_gift_bag_detail")->where(['gift_bag_id' => $gift_bag_id])->sum('quantity'); db::startTrans(); try{ //扣除抽奖消耗的金币 //扣除用户金币并记录日志 $wallet_update = model('GiveGift')->change_user_cion_or_earnings_log($user_id,$bag_gift_price,$room_id,1,10,'巡乐会抽奖消耗'); if(!$wallet_update){ Db::rollback(); return ['code' => 0, 'msg' => '扣除用户金币失败', 'data' => null]; } //用户财富等级更新 $user_level = model('Level')->user_level_data_update($user_id,$bag_gift_price,1,$room_id); if(!$user_level){ Db::rollback(); return ['code' => 0, 'msg' => '用户等级更新失败', 'data' => null]; } //开始抽奖 for($i = 0; $i < $num; $i++){ //本期当前第多少次后抽奖 总的抽奖次数- 剩余数量 $room_pan = db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])->field('remaining_number,periods')->find(); if(empty($room_pan)){ return ['code' => 0, 'msg' => '当前房间未配置抽奖礼物,请联系管理员', 'data' => []]; } $total_remaining = db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])->sum('remaining_number'); $total_draw_times = $total_quantity - $total_remaining; //随机获取一个礼物 $where = [ 'a.gift_bag_id' => $gift_bag_id, 'b.room_id' => $room_id, 'a.quantity' => ['>',0], 'b.remaining_number' => ['>',0], 'a.weight' => ['<=', $total_draw_times], ]; // 使用闭包条件来处理复杂的 weight 逻辑 // $where['a.weight'] = ['exp', Db::raw('= 0 OR a.weight < '.$total_draw_times)]; // 优化:基于剩余数量的加权随机选择 $gift_bag_details = db::name("vs_gift_bag_detail") ->field('a.id,a.quantity,b.remaining_number,a.weight,a.foreign_id') ->alias('a') ->join('vs_room_pan b','b.gift_bag_detail_id = a.id','left') ->where($where) ->select(); if (empty($gift_bag_details)) { return ['code' => 0, 'msg' => '当前盲盒无可用礼物', 'data' => []]; } // 实现加权随机算法:剩余数量越多,被抽中的概率越大 $remaining = 0; foreach ($gift_bag_details as $gift) { $remaining += $gift['remaining_number']; } $rand_value = mt_rand(1, $remaining); $current_sum = 0; $gift_bag_detail = null; foreach ($gift_bag_details as $gift) { if($gift['remaining_number'] <= 0){ continue; } $current_sum += $gift['remaining_number']; if ($rand_value <= $current_sum) { $gift_bag_detail = $gift; break; } } if($gift_bag_detail){ //获取开出礼物的信息 $gift = db::name("vs_gift")->where(['gid'=>$gift_bag_detail['foreign_id']])->find(); //抽中礼物落包 $res = model('UserGiftPack')->change_user_gift_pack($user_id,$gift_bag_detail['foreign_id'],1,model('UserGiftPack')::XLH_DRAW_GIFT_GET,$bag_data['name']."抽奖所得"); if ($res['code'] != 1) { db::rollback(); return ['code' => 0, 'msg' => $res['msg'], 'data' => null]; } //处理抽中礼物命中主奖品逻辑 if($gift_bag_detail['foreign_id'] == $ext['locking_condition']['selected_gift_id']){ //中奖 $pan_xlh_num = $pan_xlh_num+1; $cache_key = 'selected_gift_id_'.$room_id.$gift_bag_detail['foreign_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); }else{ // $add_end_time = ($ext['locking_time']['tow_no_locking_time']-$ext['locking_time']['next_time']) * 60; 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); $add_end_time = 30; } $end_time = time() + $add_end_time; db::name('vs_room_pan_xlh')->where('id',$pan_xlh['id'])->update([ 'user_id' => $user_id, 'pay_price' =>$ext['xlh_box_price'], 'locking_gift_id' =>$gift_bag_detail['foreign_id'], 'num' => $pan_xlh_num, 'end_time' => $end_time, 'updatetime' => time() ]); db::name('vs_room_pan_xlh_log')->insertGetId([ 'xlh_id' => $pan_xlh['id'], 'user_id' => $user_id, 'num' => $pan_xlh_num, 'locking_end_time' => $end_time, 'createtime' => time() ]); $is_zhong_jiang = 1; } //减去盲盒包礼物数量 $ret = db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_detail_id'=>$gift_bag_detail['id']])->setDec('remaining_number',1); if(!$ret){ db::rollback(); return ['code' => 0, 'msg' => '失败.', 'data' => []]; } //判断剩余数量是否为0 为0重置,进入下一期 $gift_bag_num = db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])->sum('remaining_number'); if($gift_bag_num <= 0){ db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])->setInc('periods'); db::name("vs_room_pan")->where(['room_id'=>$room_id,'gift_bag_id'=>$gift_bag_id])->update( ['remaining_number' => db::raw('(SELECT quantity FROM fa_vs_gift_bag_detail WHERE id = fa_vs_room_pan.gift_bag_detail_id)')]); } }else{ db::rollback(); return ['code' => 0, 'msg' => '失败!', 'data' => []]; } $result_data[] = [ 'user_id' => $user_id, 'gift_id'=>$gift_bag_detail['foreign_id'], 'gift_price'=>$gift['gift_price'], 'gift_name'=>$gift['gift_name'], 'base_image'=>$gift['base_image'], ]; } $reslut_data = []; foreach ($result_data as $key => $value) { $gift_id = $value['gift_id']; if (!isset($reslut_data[$gift_id])) { $reslut_data[$gift_id] = [ 'gift_id' => $gift_id, 'gift_price'=>$value['gift_price'], 'gift_name'=>$value['gift_name'], 'base_image'=>$value['base_image'], 'count' => 1 ]; }else { $reslut_data[$gift_id]['count']++; } } $result_list = []; foreach ($reslut_data as $key => $value) { //处理礼包发放记录表 $data = []; $data['user_id'] = $user_id; $data['parent_id'] = $pan_xlh['id']; $data['gift_bag_id'] = $gift_bag_id; $data['gift_id'] = $value['gift_id']; $data['periods'] = $room_pan['periods']; $data['room_id'] = $room_id; $data['num'] = $value['count']; $data['gift_price'] = $value['gift_price']; $data['bag_price'] = $ext['xlh_box_price']; $data['createtime'] = time(); $result = db::name("vs_gift_bag_receive_log")->insert($data); if(!$result){ db::rollback(); return ['code' => 0, 'msg' => '失败,', 'data' => []]; } $result_list[]=[ 'gift_id'=>$value['gift_id'], 'gift_name'=>$value['gift_name'], 'base_image' =>$value['base_image'], 'gift_price'=>$value['gift_price'], 'count'=>$value['count'], ]; } // 添加活动记录 $reslut = 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(); return V(0,$e->getMessage()); } if($is_zhong_jiang == 1){ //推送 $FromUserInfo = db::name('user')->field('nickname,avatar')->where(['id'=>$user_id])->find(); $room_name = db::name('vs_room')->where(['id'=>$room_id])->value('room_name'); $gift_name = db::name('vs_gift')->where(['gid'=>$value['gift_id']])->value('gift_name'); $text = $FromUserInfo['nickname'] . ' 用户在 ' . $room_name.' 房间巡乐会中 ' .$gift_name.'礼物 x ' .$value['count']." 已收入背包"; $text = [ 'gift_num' => $pan_xlh_num, 'FromUserInfo' => $FromUserInfo, 'end_time' => $end_time, 'text' => $text ]; //聊天室推送系统消息 model('Chat')->sendMsg(1057,$room_id,$text); } //返回结果排序 usort($result_list, function($a, $b) { return $b['gift_price'] <=> $a['gift_price']; }); return ['code' => 1, 'msg' => '成功', 'data' => $result_list]; } /* * 巡乐会抽奖记录 */ public function xlh_get_user_record($user_id,$room_id,$page=1,$page_size=12){ $where = []; $where['a.gift_bag_id'] = 13; $where['a.user_id'] = $user_id; $where['a.room_id'] = $room_id; $list = db('vs_gift_bag_receive_log') ->alias('a') ->join('vs_room_pan_xlh b','b.id = a.parent_id','left') ->join('vs_gift c','c.gid = a.gift_id','left') ->field('a.gift_id,a.num as count,a.createtime,c.gift_name as gift_name,c.base_image') ->where($where) ->order('a.createtime desc') ->page($page,$page_size) ->select(); foreach ($list as &$v){ $v['createtime'] = date('Y-m-d H:i:s',$v['createtime']); } return ['code' => 1, 'msg' => '成功', 'data' => $list]; } /* * 巡乐会榜单 */ public function xlh_ranking($room_id,$page=1,$page_size=12){ $where = []; $where['a.gift_bag_id'] = 13; $where['a.room_id'] = $room_id; $where['e.is_world_show'] = 1; $list = db('vs_gift_bag_receive_log') ->alias('a') ->join('vs_room_pan_xlh b','b.id = a.parent_id','left') ->join('vs_gift c','c.gid = a.gift_id','left') ->join('fa_user d','d.id = a.user_id','left') ->join('vs_gift_bag_detail e','e.foreign_id = a.gift_id','left') ->field('a.gift_id,a.num as count,a.createtime,c.gift_name,c.base_image,d.nickname') ->where($where) ->order('a.createtime desc') ->page($page,$page_size) ->select(); foreach ($list as &$v){ $v['createtime'] = date('Y-m-d H:i:s',$v['createtime']); } return ['code' => 1, 'msg' => '成功', 'data' => $list]; } /* * 获取用户当前房间的巡乐会信息 */ public function get_user_xlh_info($room_id){ $gift_bag_id = 13; $xlh_box = db::name('vs_gift_bag')->where('id',$gift_bag_id)->find(); $xlh_ext = json_decode($xlh_box['ext'],true); $room_data = db('vs_room') ->where(['id'=>$room_id]) ->field('id,room_name,xlh_periods,xlh_periods_num') ->find(); $xlh_data = db('vs_room_pan_xlh') ->where(["room_id"=>$room_id,"periods"=>$room_data['xlh_periods']]) ->field('id,room_id,periods,end_time') ->find(); //寻乐会状态 $xlh_status = 0; // 状态 if($room_data['xlh_periods_num'] >= $xlh_ext['open_condition']['start_num']){ $xlh_status = 1;//状态 1:巡乐会开始 2:即将开始 0:等待开始 } elseif($room_data['xlh_periods_num'] >= $xlh_ext['open_condition']['waiting_start_num'] && $room_data['xlh_periods_num'] < $xlh_ext['open_condition']['start_num']){ $xlh_status = 2;//状态 1:巡乐会开始 2:即将开始开始 0:等待开始 }else{ $xlh_status = 0;//未开始 } return [ 'activities_name' => $xlh_box['name'], 'icon' => null, 'xlh_status'=>$xlh_status, 'end_time'=>$xlh_data['end_time'] ?? 0, ]; } }