Files
webman_duanju/app/czg/app/controller/DiscSpinningController.php
2025-08-19 14:00:51 +08:00

322 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\czg\app\controller;
use app\api\model\CommonInfo;
use app\api\model\DiscSpinningRecord;
use app\api\model\Orders;
use app\api\model\TbUser;
use app\api\model\TbUserBlacklist;
use app\common\controller\Frontend;
use app\common\library\DatabaseRoute;
use app\exception\CzgException;
use app\exception\SysException;
use app\queue\redis\DiscReceiveQueue;
use extend\ba\Random;
use think\db\exception\DuplicateException;
use think\facade\Db;
use support\Log;
class DiscSpinningController extends Frontend
{
protected array $noNeedLogin = ['draw'];
protected array $noNeedPermission = [];
public function initialize(): void
{
parent::initialize();
}
/**
* 抽奖
*/
public function draw()
{
$params = $this->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),
]);
}
}