|
|
@@ -0,0 +1,417 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Services;
|
|
|
+
|
|
|
+use App\Game\Services\OuroGameService;
|
|
|
+use App\Http\helper\NumConfig;
|
|
|
+use App\Utility\SetNXLock;
|
|
|
+use App\Util;
|
|
|
+use App\Facade\TableName;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+
|
|
|
+class ChristmasWheelService
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 获取圣诞大转盘配置 + 用户状态
|
|
|
+ */
|
|
|
+ public function getWheelInfo(int $userId): array
|
|
|
+ {
|
|
|
+ $activity = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_activity')
|
|
|
+ ->orderBy('id', 'desc')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ $now = now();
|
|
|
+
|
|
|
+ $status = 0;
|
|
|
+ $startTime = null;
|
|
|
+ $endTime = null;
|
|
|
+ $logo = '';
|
|
|
+ $button_url = '';
|
|
|
+ $button_light_url = '';
|
|
|
+ $lunzi_url = '';
|
|
|
+ $dipan_url = '';
|
|
|
+ $freeTimes = 0;
|
|
|
+ // 默认规则从活动配置 + 商城档位中计算(包含金额、次数和档位信息)
|
|
|
+ $rechargeRules = $this->getDefaultRechargeRules();
|
|
|
+
|
|
|
+ if ($activity) {
|
|
|
+ $status = (int)($activity->status ?? 0);
|
|
|
+ $startTime = $activity->start_time;
|
|
|
+ $endTime = $activity->end_time;
|
|
|
+ $logo = $activity->icon_url ?? '';
|
|
|
+ $button_url = $activity->button_url ?? '';
|
|
|
+ $button_light_url = $activity->button_light_url ?? '';
|
|
|
+ $lunzi_url = $activity->lunzi_url ?? '';
|
|
|
+ $dipan_url = $activity->dipan_url ?? '';
|
|
|
+ $freeTimes = (int)($activity->free_times ?? 0);
|
|
|
+
|
|
|
+ // 如果当前时间不在活动时间范围内,则前端状态强制视为关闭(0)
|
|
|
+ if (!empty($startTime) && $now->lt($startTime)) {
|
|
|
+ $status = 0;
|
|
|
+ }
|
|
|
+ if (!empty($endTime) && $now->gt($endTime)) {
|
|
|
+ $status = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 前端展示时只需要简单的奖励值数组,例如 [177, 1, 0.2, ...],隐藏 slot_index 和 weight
|
|
|
+ $slots = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_config')
|
|
|
+ ->orderBy('sort_index', 'asc')
|
|
|
+ ->orderBy('slot_index', 'asc')
|
|
|
+ ->pluck('reward')
|
|
|
+ ->map(function ($reward) {
|
|
|
+ return (float)$reward;
|
|
|
+ })
|
|
|
+ ->values()
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ $userTimes = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ // 检查用户是否已充值
|
|
|
+// $userRecharge = DB::table(TableName::QPAccountsDB() . 'YN_VIPAccount')
|
|
|
+// ->where('UserID', $userId)
|
|
|
+// ->value('Recharge') ?: 0;
|
|
|
+// $hasRecharge = $userRecharge > 0;
|
|
|
+
|
|
|
+ // 如果用户未充值且有免费次数配置,且用户未领取过免费次数,则自动发放
|
|
|
+ if ($freeTimes > 0 && $activity && (int)$activity->status === 1) {
|
|
|
+ // 检查活动是否在有效期内
|
|
|
+ $activityValid = true;
|
|
|
+ if (!empty($startTime) && $now->lt($startTime)) {
|
|
|
+ $activityValid = false;
|
|
|
+ }
|
|
|
+ if (!empty($endTime) && $now->gt($endTime)) {
|
|
|
+ $activityValid = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($activityValid) {
|
|
|
+ if (!$userTimes || (int)($userTimes->free_times_granted ?? 0) === 0) {
|
|
|
+ // 发放免费次数
|
|
|
+ DB::connection('write')->transaction(function () use ($userId, $freeTimes) {
|
|
|
+ $existingUser = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->lockForUpdate()
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($existingUser) {
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->update([
|
|
|
+ 'left_times' => (int)$existingUser->left_times + $freeTimes,
|
|
|
+ 'total_times' => (int)$existingUser->total_times + $freeTimes,
|
|
|
+ 'free_times_granted' => 1,
|
|
|
+ 'updated_at' => now(),
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->insert([
|
|
|
+ 'UserID' => $userId,
|
|
|
+ 'left_times' => $freeTimes,
|
|
|
+ 'total_times' => $freeTimes,
|
|
|
+ 'free_times_granted' => 1,
|
|
|
+ 'created_at' => now(),
|
|
|
+ 'updated_at' => now(),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 重新查询用户数据
|
|
|
+ $userTimes = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->first();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $leftTimes = $userTimes ? (int)$userTimes->left_times : 0;
|
|
|
+ $totalTimes = $userTimes ? (int)$userTimes->total_times : 0;
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'status' => $status,
|
|
|
+ 'start_time' => $startTime,
|
|
|
+ 'end_time' => $endTime,
|
|
|
+ 'logo_url' => $logo,
|
|
|
+ 'button_url' => $button_url,
|
|
|
+ 'button_light_url' => $button_light_url,
|
|
|
+ 'lunzi_url' => $lunzi_url,
|
|
|
+ 'dipan_url' => $dipan_url,
|
|
|
+ 'free_times' => $freeTimes,
|
|
|
+ 'slots' => $slots,
|
|
|
+ 'user' => [
|
|
|
+ 'left_times' => $leftTimes,
|
|
|
+ 'total_times' => $totalTimes,
|
|
|
+ ],
|
|
|
+ 'recharge_rules' => $rechargeRules,
|
|
|
+ 'now' => $now->toDateTimeString(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 充值赠送转盘次数(在充值成功后调用)
|
|
|
+ * 有 gift_id=402 的充值添加次数
|
|
|
+ */
|
|
|
+ public function grantTimesOnRecharge(int $userId, float $payAmt, int $giftId = 0): void
|
|
|
+ {
|
|
|
+ if ($giftId != 402) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $activity = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_activity')
|
|
|
+ ->orderBy('id', 'desc')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$activity || (int)$activity->status !== 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = now();
|
|
|
+ if (!empty($activity->start_time) && $now->lt($activity->start_time)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!empty($activity->end_time) && $now->gt($activity->end_time)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统一使用默认规则(已基于活动配置 + 商城档位计算),保持金额与 times 一致
|
|
|
+ $rules = $this->getDefaultRechargeRules();
|
|
|
+
|
|
|
+ $payStr = number_format($payAmt, 2, '.', '');
|
|
|
+ $addTimes = 0;
|
|
|
+ foreach ($rules as $rule) {
|
|
|
+ $amount = isset($rule['amount']) ? number_format($rule['amount'], 2, '.', '') : null;
|
|
|
+ $times = (int)($rule['times'] ?? 0);
|
|
|
+ if ($amount !== null && $amount === $payStr && $times > 0) {
|
|
|
+ $addTimes += $times;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($addTimes <= 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ DB::connection('write')->transaction(function () use ($userId, $addTimes) {
|
|
|
+ $row = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->lockForUpdate()
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($row) {
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->update([
|
|
|
+ 'left_times' => (int)$row->left_times + $addTimes,
|
|
|
+ 'total_times' => (int)$row->total_times + $addTimes,
|
|
|
+ 'updated_at' => now(),
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->insert([
|
|
|
+ 'UserID' => $userId,
|
|
|
+ 'left_times' => $addTimes,
|
|
|
+ 'total_times' => $addTimes,
|
|
|
+ 'free_times_granted' => 0,
|
|
|
+ 'created_at' => now(),
|
|
|
+ 'updated_at' => now(),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行一次转盘抽奖
|
|
|
+ */
|
|
|
+ public function spin(int $userId): array
|
|
|
+ {
|
|
|
+ $redisKey = 'christmas_wheel_spin_' . $userId;
|
|
|
+ $lock = SetNXLock::getExclusiveLock($redisKey, 5);
|
|
|
+ if (!$lock) {
|
|
|
+ throw new \RuntimeException('操作太频繁,请稍后再试');
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ $activity = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_activity')
|
|
|
+ ->orderBy('id', 'desc')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$activity || (int)$activity->status !== 1) {
|
|
|
+ throw new \RuntimeException('活动未开启');
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = now();
|
|
|
+ if (!empty($activity->start_time) && $now->lt($activity->start_time)) {
|
|
|
+ throw new \RuntimeException('活动未开始');
|
|
|
+ }
|
|
|
+ if (!empty($activity->end_time) && $now->gt($activity->end_time)) {
|
|
|
+ throw new \RuntimeException('活动已结束');
|
|
|
+ }
|
|
|
+
|
|
|
+ $slots = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_config')
|
|
|
+ ->orderBy('sort_index', 'asc')
|
|
|
+ ->orderBy('slot_index', 'asc')
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ if ($slots->isEmpty()) {
|
|
|
+ throw new \RuntimeException('转盘配置不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ DB::connection('write')->beginTransaction();
|
|
|
+
|
|
|
+ $userRow = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->lockForUpdate()
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$userRow || (int)$userRow->left_times <= 0) {
|
|
|
+ DB::connection('write')->rollBack();
|
|
|
+ throw new \RuntimeException($userId.'没有可用的转盘次数');
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalWeight = 0;
|
|
|
+ $weights = [];
|
|
|
+ foreach ($slots as $slot) {
|
|
|
+ $w = (int)$slot->weight;
|
|
|
+ if ($w < 0) {
|
|
|
+ $w = 0;
|
|
|
+ }
|
|
|
+ $weights[] = $w;
|
|
|
+ $totalWeight += $w;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($totalWeight <= 0) {
|
|
|
+ DB::connection('write')->rollBack();
|
|
|
+ throw new \RuntimeException('转盘权重配置错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $rand = mt_rand(1, $totalWeight);
|
|
|
+ $cumulative = 0;
|
|
|
+ $selectedIndex = 0;
|
|
|
+ foreach ($slots as $idx => $slot) {
|
|
|
+ $cumulative += $weights[$idx];
|
|
|
+ if ($rand <= $cumulative) {
|
|
|
+ $selectedIndex = $idx;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $selectedSlot = $slots[$selectedIndex];
|
|
|
+ $reward = (float)$selectedSlot->reward;
|
|
|
+ $slotIndex = (int)$selectedSlot->slot_index;
|
|
|
+
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_user')
|
|
|
+ ->where('UserID', $userId)
|
|
|
+ ->update([
|
|
|
+ 'left_times' => (int)$userRow->left_times - 1,
|
|
|
+ 'updated_at' => now(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_history')
|
|
|
+ ->insert([
|
|
|
+ 'UserID' => $userId,
|
|
|
+ 'slot_index' => $slotIndex,
|
|
|
+ 'reward' => $reward,
|
|
|
+ 'created_at' => now(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ DB::connection('write')->commit();
|
|
|
+
|
|
|
+ OuroGameService::AddScore($userId,$reward*NumConfig::NUM_VALUE,111,false);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'slot_index' => $slotIndex,
|
|
|
+ 'reward' => $reward,
|
|
|
+ 'left_times' => (int)$userRow->left_times - 1,
|
|
|
+ ];
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ DB::connection('write')->rollBack();
|
|
|
+ throw $e;
|
|
|
+ } finally {
|
|
|
+ SetNXLock::release($redisKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 默认充值规则:
|
|
|
+ * - 基于固定金额和次数:[9.99=>1次, 19.99=>3次, 49.99=>6次]
|
|
|
+ * - 额外从 recharge_gear 中取出相同金额的档位详情(类似商城列表的数据),
|
|
|
+ * times 字段保持不变。
|
|
|
+ */
|
|
|
+ public function getDefaultRechargeRules(): array
|
|
|
+ {
|
|
|
+ // 固定的基础规则(金额+次数)
|
|
|
+ // 1) 先从活动配置中读取 recharge_rules
|
|
|
+ $rules = [];
|
|
|
+ $activity = DB::connection('write')
|
|
|
+ ->table('agent.dbo.christmas_wheel_activity')
|
|
|
+ ->orderBy('id', 'desc')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($activity && !empty($activity->recharge_rules)) {
|
|
|
+ $decoded = json_decode($activity->recharge_rules, true);
|
|
|
+ if (is_array($decoded)) {
|
|
|
+ $rules = $decoded;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2) 如果没有配置,则使用默认规则
|
|
|
+ if (empty($rules)) {
|
|
|
+ $rules = [
|
|
|
+ ['amount' => 9.99, 'times' => 1],
|
|
|
+ ['amount' => 19.99, 'times' => 3],
|
|
|
+ ['amount' => 19.99, 'times' => 3],
|
|
|
+ ['amount' => 49.99, 'times' => 6],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为每条规则附加与金额相同的 recharge_gear 配置(类似商城 gear 列表)
|
|
|
+ foreach ($rules as &$rule) {
|
|
|
+ $amount = $rule['amount'];
|
|
|
+
|
|
|
+ $item = DB::connection('write')
|
|
|
+ ->table('agent.dbo.recharge_gear')
|
|
|
+ ->where('status', 1)
|
|
|
+ ->where('money', $amount)
|
|
|
+ ->select('id', 'money', 'favorable_price', 'give', 'recommend', 'gear')
|
|
|
+ ->orderBy('id', 'asc')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($item) {
|
|
|
+ // 过滤 gear 支付方式,跟商城接口一致
|
|
|
+ if (!empty($item->gear)) {
|
|
|
+ $item->gear = Util::filterGearByDevice($item->gear);
|
|
|
+ }
|
|
|
+
|
|
|
+ $rule['gear'] = [
|
|
|
+ 'id' => $item->id,
|
|
|
+ 'money' => (float)$item->money,
|
|
|
+ 'favorable_price' => (float)$item->favorable_price,
|
|
|
+ 'give' => (float)$item->give,
|
|
|
+ 'recommend' => (int)($item->recommend ?? 0),
|
|
|
+ 'gear' => $item->gear,
|
|
|
+ 'gift_id' => 402,
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $rule['gear'] = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ unset($rule);
|
|
|
+
|
|
|
+ return $rules;
|
|
|
+ }
|
|
|
+}
|