初始化

This commit is contained in:
2026-03-02 13:44:38 +08:00
commit 05b785083c
677 changed files with 58662 additions and 0 deletions

158
app/service/DrawService.php Normal file
View File

@@ -0,0 +1,158 @@
<?php
// 抽奖核心服务
namespace app\service;
use addons\webman\model\DrawRecord;
use addons\webman\model\Game;
use addons\webman\model\Prize;
use Exception;
use support\Db;
use support\Log;
class DrawService
{
/**
* 执行抽奖
* @param $player
* @param int $gameId
* @param int $departmentId
* @param string $ip 用户IP
* @return array 抽奖结果
*/
public function execute( $player, int $gameId, int $departmentId, string $ip): array
{
try {
DB::beginTransaction();
// 1. 查询有效奖品(加行锁防止并发问题)
$prizes = Prize::query()->where('game_id', $gameId)
->where('department_id', $departmentId)
->where('status', 1)
->where('total_remaining', '>', 0)
->where('daily_remaining', '>', 0)
->lockForUpdate()
->get()
->toArray();
if (empty($prizes)) {
DB::rollBack();
return [
'success' => false,
'message' => '当前游戏不可用'
];
}
$game = Game::query()->select('id', 'game_type', 'consume')->where('id', $gameId)->first()->toArray();
// 2. 计算中奖结果
$result = $this->calculateWinning($player,$prizes, $game['consume']);
$prizeId = $result['prize_id'];
$prizeName = $result['prize_name'];
$prizeType = $result['prize_type'];
$game['department_id'] = $departmentId;
// 3. 记录抽奖信息
$this->createRecord($player->id, $result, $game, $ip);
if ($result['prize_type'] == 3) {
$message = '很遗憾,未中奖';
} else {
$message = '恭喜获得' . $prizeName;
}
DB::commit();
return [
'prize_id' => $prizeId,
'prize_name' => $prizeName,
'prize_type' => $prizeType,
'consume' => $game['consume'],
'message' => $message
];
} catch (Exception $e) {
DB::rollBack();
Log::error("抽奖失败:{$e->getMessage()}", [
'user_id' => $player->id,
'trace' => $e->getTraceAsString()
]);
return [
'success' => false,
'message' => '抽奖过程异常,请稍后再试'
];
}
}
/**
* 计算中奖结果
* @param array $prizes 有效奖品列表
* @return array 中奖信息
* @throws Exception
*/
private function calculateWinning($player, array $prizes, $consume): array
{
// 计算总概率权重
$totalProb = array_sum(array_column($prizes, 'probability'));
if ($totalProb <= 0) {
return ['prize_id' => null, 'type' => Prize::PRIZE_TYPE_LOSE, 'prize_name' => '未中奖', 'prize_pic' => null];
}
$player->wallet->decrement('money', $consume);
// 生成随机数0到总权重之间
$random = mt_rand(1, $totalProb * 10000) / 10000; // 提高精度
$currentSum = 0;
foreach ($prizes as $prize) {
$currentSum += $prize['probability'];
if ($random <= $currentSum) {
// 检查并扣减库存
$this->deductStock($prize['id']);
return [
'prize_id' => $prize['id'],
'prize_type' => $prize['type'],
'prize_name' => $prize['name'],
'prize_pic' => $prize['pic']
];
}
}
return ['prize_id' => null, 'type' => Prize::PRIZE_TYPE_LOSE, 'prize_name' => '未中奖', 'prize_pic' => null];
}
/**
* 扣减库存
* @param int $prizeId 奖品ID
* @throws Exception
*/
private function deductStock(int $prizeId): void
{
$prize = Prize::query()->findOrFail($prizeId);
// 再次检查库存(防止并发超卖)
if ($prize->total_remaining <= 0 || $prize->daily_remaining <= 0) {
throw new \Exception("奖品库存不足");
}
$prize->decrement('total_remaining');
$prize->decrement('daily_remaining');
$prize->save();
}
/**
* 创建抽奖记录
* @param int $userId 用户ID
* @param array|null $prize 奖品
* @param string $ip IP地址
*/
private function createRecord(int $userId, ?array $prize, array $game, string $ip): void
{
DrawRecord::query()->create([
'uid' => $userId,
'prize_id' => $prize['prize_id'],
'prize_type' => $prize['prize_type'],
'prize_name' => $prize['prize_name'],
'prize_pic' => $prize['prize_pic'],
'game_id' => $game['id'],
'consume' => $game['consume'],
'game_type' => $game['game_type'],
'department_id' => $game['department_id'],
'draw_time' => date('Y-m-d H:i:s'),
'ip' => $ip
]);
}
}