request->get(); $userInfo = $this->auth->getUser(); Log::info('抽奖'. json_encode($userInfo)); debounce("user:disc-spinning:interval:limit:user:".$userInfo['user_id'], 2); $userId = $userInfo['user_id']; $resp = []; runWithLock("user:disc-spinning:limit:user:lock:".$this->getUserId(), 60, function () use ($params, $userId, &$resp, $userInfo) { DatabaseRoute::transactionXa(function () use ($params, $userId, &$resp, $userInfo) { try { // 查询抽奖次数 $count = DiscSpinningRecord::countDraw($userId); // 免费两次之后校验实名 if ($count == 2 && !TbUser::checkEnable($userInfo)) { $this->error('请实名认证后继续抽奖'); } Log::info("用户id: $userId, 抽奖次数: $count"); // 订单抽奖 if (!isset($params['source']) || $params['source'] == 1) { $drawCount = (new CommonInfo())->getByCodeToInt(901); if ($count >= $drawCount) { $this->error('当日可抽奖次数已超限'); } // 校验订单笔数 $orders = Orders::selectOrdersByDay($userId); if (!$orders) { throw new SysException("无可用抽奖机会"); } $params['sourceId'] = $orders['orders_id']; }else{ $this->error("八嘎"); } if (!isset($params['sourceId'])) { throw new CzgException("异常请求"); } $draws = self::draws($count + 1, $orders['pay_money'], $params['sourceId'], $userId, $params['source']); $resp = $draws; // $this->receive($draws); pushQueue(DiscReceiveQueue::class, [ 'draws' => $resp ]); }catch (DuplicateException $e) { (new TbUserBlacklist())->addBlackUser($userId, "重复抽奖"); throw $e; } }); }); $resp = convertToCamelCase($resp); $resp['img'] = $resp['img_url'] ?? ''; $this->successWithData($resp); } public static function draws($drawCount, $orderAmount, $sourceId, $userId, $source) { $result = [ 'name' => '谢谢惠顾', 'source_id' => $sourceId, 'user_id' => $userId, 'img_url' => '', 'type' => 1, 'number' => 1, 'draw_day' => date('Y-m-d'), 'create_time' => date('Y-m-d H:i:s'), 'source' => $source == 1 ? 'order' : 'task' ]; // 查询奖项 $prizes = Db::name('disc_spinning')->where([ 'disc_type' => $source ])->order('number', 'asc')->select()->toArray(); if (empty($prizes)) { DatabaseRoute::getDb('disc_spinning_record', $userId, true, true)->insert($result); return $result; } // 获取最大概率 $maxNumber = array_reduce($prizes, function ($carry, $prize) { return bccomp($prize['number'], $carry) > 0 ? $prize['number'] : $carry; }, '0'); // 最大值为 0,直接谢谢惠顾 if (bccomp($maxNumber, '0') === 0) { $record = $result; DatabaseRoute::getDb('disc_spinning_record', $userId, true, true)->insert($record); return $record; } // 获取随机数(整数) if ($maxNumber > 1) { $randomNum = rand(0, (int)$maxNumber - 1); } else { $randomNum = rand(0, (int)$maxNumber); // 或者其它默认值 } // 查询奖励金额列表(模拟 redis 逻辑) $amounts = Db::name('disc_spinning_amount')->where([ 'status' => 1, 'type' => $source ])->order('max_amount', 'asc')->select()->toArray(); // 按 num 分组 $amountMaps = []; foreach ($amounts as $item) { $num = isset($item['num']) ? intval($item['num']) : 0; $amountMaps[$num][] = $item; } // 按照 drawCount 向下查找匹配组 $filteredAmounts = []; if (!empty($amountMaps)) { for ($i = $drawCount; $i >= 0; $i--) { if (isset($amountMaps["{$i}"])) { $filteredAmounts = $amountMaps["{$i}"]; break; } } } // 抽奖逻辑 $finalPrize = null; foreach ($prizes as $prize) { if (bccomp((string)$randomNum, $prize['number']) < 0) { if ($prize['type'] == 2) { // 金额类奖品 $maxAmount = (new CommonInfo())->getByCodeToInt(900); // 最大金额限制 $baseRandom = mt_rand() / mt_getrandmax(); $baseRandom = bccomp($baseRandom, "1", 2) ? 0.99 : $baseRandom; $baseAmount = 0; $resultAmount = 0; foreach ($filteredAmounts as $amount) { if ($baseRandom < $amount['random']) { $resultAmount = $baseAmount + (mt_rand() / mt_getrandmax()) * $amount['max_amount']; break; } $baseAmount = $amount['max_amount']; } if ($resultAmount < 0.01) { $resultAmount = 0.01; } $randomFactor = mt_rand(50, 90) / 100; // 生成 0.5 到 0.9 的随机数 $resultAmount = $resultAmount * $randomFactor; $resultAmount += $orderAmount; if ($resultAmount > $maxAmount) { $resultAmount = $maxAmount; } $finalPrize = [ 'name' => $prize['name'], 'type' => 2, 'number' => round($resultAmount, 2), 'id' => $prize['id'], 'url' => $prize['url'] ?? '' ]; break; } else { // 非金额奖品 if ($source != 1) { $finalPrize = [ 'name' => $prize['name'], 'type' => $prize['type'], 'number' => 1, 'id' => $prize['id'], 'url' => $prize['url'] ?? '' ]; break; } } } } if (!$finalPrize) { // 没抽中任何奖品,默认“谢谢惠顾” $finalPrize = [ 'name' => '谢谢惠顾', 'type' => 1, 'number' => 1, 'id' => null, 'url' => '' ]; } // 构建记录 $record = [ 'id' => Random::generateRandomPrefixedId(19), 'name' => $finalPrize['name'], 'source_id' => $sourceId, 'user_id' => $userId, 'img_url' => $finalPrize['url'] ?? '', 'type' => $finalPrize['type'], 'number' => $finalPrize['number'], 'draw_day' => date('Y-m-d'), 'create_time' => date('Y-m-d H:i:s'), 'source' => $source == 1 ? 'order' : 'task' ]; // 保存 DatabaseRoute::getDb('disc_spinning_record', $userId, true)->insert($record); $record['discSpinningId'] = $finalPrize['id']; return $record; } /** * 获取大转盘抽奖次数 */ public function drawCount() { $get = $this->request->get(); if(empty($get['source'])) { $soure = 1; }else { $soure = $get['source']; } $user = $this->auth->getUser(); $drawCount = (int)CommonInfo::where(['type' => 901])->find()->value; $data['sum'] = $drawCount; if(!empty($soure) && $soure != 1) { if($soure == 2) { $sourceType = 'taskW'; }else { $sourceType = 'taskM'; } $spinningCount = DatabaseRoute::getDb('disc_spinning_record', $user['user_id'])->where(['source' => $sourceType])->count(); if($spinningCount != null && $spinningCount > 0) { $data['count'] = 0; }else { $i = DiscSpinningRecord::countTaskDisc($user['user_id'], $soure); $data['count'] = $i>0?1:0; } }else { $i = DatabaseRoute::getDb('disc_spinning_record', $user['user_id'])->where(['source' => 'order'])->where([ 'draw_day' => ['between', date('Y-m-d 00:00:00'), date('Y-m-d 11:59:59')] ])->count(); if($drawCount - $i > 0) { $data['count'] = DiscSpinningRecord::selectOrdersCountStatisticsByDay($user['user_id'], $drawCount - $i); }else { $data['count'] = 0; } } $this->success('ok', $data); } // 查询大转盘 public function selectDiscSpinning() { $get = $this->request->get(); if(empty($get['source'])) { $this->error('参数不完整'); } $page = 1; $limit = 20; $db = Db::connect(config('think-orm.search_library')); $list = $db->name('disc_spinning') ->where(['disc_type' => $get['source']]); $count = $list->count(); $list = $list->order('disc_type', 'asc') ->order('odds', 'asc') ->limit(page($page, $limit), $limit) ->select()->toArray(); foreach ($list as $k => &$v) { $v['odds'] = null; $v['number'] = null; $v['discType'] = null; $v['img'] = $v['url']; } $this->success('ok', [ 'currPage' => $page, 'pageSize' => $limit, 'records' => convertToCamelCase($list), 'totalCount' => $count, 'totalPage' => ceil($count / $limit), ]); } }