瀏覽代碼

节假日活动转盘

Tree 4 周之前
父節點
當前提交
330cb2abe0

+ 254 - 0
app/Http/Controllers/Admin/HolidayWheelController.php

@@ -0,0 +1,254 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+class HolidayWheelController
+{
+    /**
+     * 节假日大转盘配置页
+     */
+    public function index(Request $request)
+    {
+        // 活动配置(只取一条最新的)
+        $activity = DB::connection('write')
+            ->table('agent.dbo.holiday_wheel_activity')
+            ->orderBy('id', 'desc')
+            ->first();
+
+        if ($activity) {
+            $activity = (array)$activity;
+            $activity['recharge_rules'] = $activity['recharge_rules'] ?? '';
+        } else {
+            $activity = [
+                'id' => 0,
+                'start_time' => null,
+                'end_time' => null,
+                'status' => 0,
+                'icon_url' => '',
+                'recharge_rules' => json_encode([
+                    ['amount' => 9.99, 'times' => 1],
+                    ['amount' => 19.99, 'times' => 3],
+                    ['amount' => 49.99, 'times' => 6],
+                ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
+            ];
+        }
+
+        // 解析充值规则为数组,供前端更友好编辑
+        $rules = [];
+        if (!empty($activity['recharge_rules'])) {
+            $decodedRules = json_decode($activity['recharge_rules'], true);
+            if (is_array($decodedRules)) {
+                $rules = $decodedRules;
+            }
+        }
+        if (empty($rules)) {
+            $rules = [
+                ['amount' => 9.99, 'times' => 1],
+                ['amount' => 19.99, 'times' => 3],
+                ['amount' => 49.99, 'times' => 6],
+            ];
+        }
+
+        // 16 档配置
+        $configs = DB::connection('write')
+            ->table('agent.dbo.holiday_wheel_config')
+            ->orderBy('sort_index', 'asc')
+            ->orderBy('slot_index', 'asc')
+            ->get();
+
+        // 确保有 0-15 共 16 个档位
+        $byIndex = [];
+        foreach ($configs as $cfg) {
+            $byIndex[(int)$cfg->slot_index] = $cfg;
+        }
+
+        $slots = [];
+        for ($i = 0; $i < 16; $i++) {
+            if (isset($byIndex[$i])) {
+                $row = $byIndex[$i];
+                $slots[] = [
+                    'id' => $row->id,
+                    'slot_index' => (int)$row->slot_index,
+                    'reward' => (float)$row->reward,
+                    'weight' => (int)$row->weight,
+                    'sort_index' => (int)$row->sort_index,
+                ];
+            } else {
+                $slots[] = [
+                    'id' => 0,
+                    'slot_index' => $i,
+                    'reward' => 0,
+                    'weight' => 0,
+                    'sort_index' => $i,
+                ];
+            }
+        }
+
+        return view('admin.holiday_wheel.index', [
+            'activity' => $activity,
+            'slots' => $slots,
+            'rules' => $rules,
+        ]);
+    }
+
+    /**
+     * 保存活动配置 + 16档权重
+     */
+    public function update(Request $request)
+    {
+        // 活动配置
+        $status = (int)$request->input('status', 0);
+        $start_time = $request->input('start_time');
+        $end_time = $request->input('end_time');
+        $icon_url = $request->input('icon_url', '');
+        $recharge_rules = $request->input('recharge_rules', '');
+
+        // 支持 datetime-local 格式(YYYY-MM-DDTHH:MM)
+        if ($start_time && strpos($start_time, 'T') !== false) {
+            $start_time = str_replace('T', ' ', $start_time) . ':00';
+        }
+        if ($end_time && strpos($end_time, 'T') !== false) {
+            $end_time = str_replace('T', ' ', $end_time) . ':00';
+        }
+
+        // 简单校验 JSON(来自前端构造)
+        if ($recharge_rules) {
+            $decoded = json_decode($recharge_rules, true);
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                return apiReturnFail('充值规则 JSON 格式错误:' . json_last_error_msg());
+            }
+            $recharge_rules = json_encode($decoded, JSON_UNESCAPED_UNICODE);
+        }
+
+        DB::connection('write')->beginTransaction();
+        try {
+            // upsert 活动配置(只保留一条)
+            $activity = DB::connection('write')
+                ->table('agent.dbo.holiday_wheel_activity')
+                ->orderBy('id', 'desc')
+                ->lockForUpdate()
+                ->first();
+
+            $data = [
+                'start_time' => $start_time ?: null,
+                'end_time' => $end_time ?: null,
+                'status' => $status,
+                'icon_url' => $icon_url,
+                'recharge_rules' => $recharge_rules,
+                'updated_at' => now(),
+            ];
+
+            if ($activity) {
+                DB::connection('write')
+                    ->table('agent.dbo.holiday_wheel_activity')
+                    ->where('id', $activity->id)
+                    ->update($data);
+            } else {
+                $data['created_at'] = now();
+                DB::connection('write')
+                    ->table('agent.dbo.holiday_wheel_activity')
+                    ->insert($data);
+            }
+
+            // 16 档配置
+            $slots = $request->input('slots', []);
+            if (!empty($slots) && is_array($slots)) {
+                foreach ($slots as $slotIndex => $row) {
+                    $slotIndex = (int)$slotIndex;
+                    if ($slotIndex < 0 || $slotIndex > 15) {
+                        continue;
+                    }
+                    $reward = isset($row['reward']) ? (float)$row['reward'] : 0;
+                    $weight = isset($row['weight']) ? (int)$row['weight'] : 0;
+                    $sortIndex = isset($row['sort_index']) ? (int)$row['sort_index'] : $slotIndex;
+
+                    $exists = DB::connection('write')
+                        ->table('agent.dbo.holiday_wheel_config')
+                        ->where('slot_index', $slotIndex)
+                        ->first();
+
+                    $cfgData = [
+                        'reward' => $reward,
+                        'weight' => $weight,
+                        'sort_index' => $sortIndex,
+                        'updated_at' => now(),
+                    ];
+
+                    if ($exists) {
+                        DB::connection('write')
+                            ->table('agent.dbo.holiday_wheel_config')
+                            ->where('slot_index', $slotIndex)
+                            ->update($cfgData);
+                    } else {
+                        $cfgData['slot_index'] = $slotIndex;
+                        $cfgData['created_at'] = now();
+                        DB::connection('write')
+                            ->table('agent.dbo.holiday_wheel_config')
+                            ->insert($cfgData);
+                    }
+                }
+            }
+
+            DB::connection('write')->commit();
+        } catch (\Throwable $e) {
+            DB::connection('write')->rollBack();
+            return apiReturnFail('保存失败:' . $e->getMessage());
+        }
+
+        return apiReturnSuc('保存成功');
+    }
+
+    /**
+     * 节假日大转盘 - 抽奖记录列表
+     */
+    public function history(Request $request)
+    {
+        $userId = (int)$request->input('user_id', 0);
+        $gameId = (int)$request->input('game_id', 0);
+        $startDate = $request->input('start_date', '');
+        $endDate = $request->input('end_date', '');
+
+        $query = DB::connection('write')
+            ->table('agent.dbo.holiday_wheel_history as h')
+            ->leftJoin('QPAccountsDB.dbo.AccountsInfo as ai', 'h.UserID', '=', 'ai.UserID')
+            ->select(
+                'h.id',
+                'h.UserID',
+                'ai.GameID',
+                'ai.NickName',
+                'h.slot_index',
+                'h.reward',
+                'h.created_at'
+            )
+            ->orderBy('h.id', 'desc');
+
+        if ($userId > 0) {
+            $query->where('h.UserID', $userId);
+        }
+
+        if ($gameId > 0) {
+            $query->where('ai.GameID', $gameId);
+        }
+
+        if ($startDate) {
+            $query->where('h.created_at', '>=', $startDate . ' 00:00:00');
+        }
+        if ($endDate) {
+            $query->where('h.created_at', '<=', $endDate . ' 23:59:59');
+        }
+
+        $list = $query->paginate(20);
+
+        return view('admin.holiday_wheel.history', [
+            'list' => $list,
+            'user_id' => $userId,
+            'game_id' => $gameId,
+            'start_date' => $startDate,
+            'end_date' => $endDate,
+        ]);
+    }
+}
+

+ 4 - 1
app/Http/Controllers/Admin/RechargeController.php

@@ -850,9 +850,10 @@ class RechargeController extends Controller
             $favorable_price = (float)$request->favorable_price;
             $give = (float)$request->give;
             $pay_methods = (int)$request->pay_methods ?: 0;  // 支付方式位掩码
+            $in_shop = (int)$request->input('in_shop', 1);   // 是否在商城展示
             
             $logic = new RechargeLogic();
-            $res = $logic->add($money, $status, '', $favorable_price, $give, $pay_methods);
+            $res = $logic->add($money, $status, '', $favorable_price, $give, $pay_methods, $in_shop);
             return apiReturnSuc();
         }
         return view('admin.recharge.add', ['list' => $list]);
@@ -866,6 +867,7 @@ class RechargeController extends Controller
             $give = (float)($request->give ?: 0);
             $second_give = (int)($request->second_give ?: 0);
             $pay_methods = (int)($request->pay_methods ?: 0);  // 支付方式位掩码
+            $in_shop = (int)$request->input('in_shop', 1);     // 是否在商城展示
             
             // 构建支付方式数组
             $gearData = [];
@@ -895,6 +897,7 @@ class RechargeController extends Controller
                 'favorable_price' => $favorable_price,
                 'second_give' => $second_give,
                 'give' => $give,
+                'in_shop' => $in_shop,
                 'gear' => \GuzzleHttp\json_encode($gearData)  // 存储到gear字段
             ];
             DB::table('agent.dbo.recharge_gear')->where('id', $id)->update($data);

+ 38 - 0
app/Http/Controllers/Game/ActivityController.php

@@ -27,6 +27,7 @@ use App\Models\RecordUserDataStatistics;
 use App\Models\Treasure\GameScoreInfo;
 use App\Notification\TelegramBot;
 use App\Services\OrderServices;
+use App\Services\HolidayWheelService;
 use App\Services\PayConfig;
 use App\Services\SmartFastPay;
 use App\Services\StoredProcedure;
@@ -46,6 +47,43 @@ class ActivityController extends Controller
     {
 
     }
+
+    /**
+     * 节假日大转盘 - 获取配置与用户状态
+     */
+    public function holidayWheelInfo(Request $request)
+    {
+        $user = $request->user();
+        $userId = $user ? $user->UserID : 0;
+
+        $service = new HolidayWheelService();
+        $info = $service->getWheelInfo($userId);
+
+        return apiReturnSuc($info);
+    }
+
+    /**
+     * 节假日大转盘 - 抽奖
+     */
+    public function holidayWheelSpin(Request $request)
+    {
+        $user = $request->user();
+        if (!$user) {
+            return apiReturnFail('请先登录');
+        }
+
+        $service = new HolidayWheelService();
+        try {
+            $result = $service->spin($user->UserID);
+            return apiReturnSuc($result);
+        } catch (\Throwable $e) {
+            \Log::error('holiday wheel spin failed', [
+                'user_id' => $user->UserID,
+                'error' => $e->getMessage(),
+            ]);
+            return apiReturnFail($e->getMessage());
+        }
+    }
     public function List(Request $request)
     {
 

+ 2 - 1
app/Http/logic/admin/RechargeLogic.php

@@ -262,7 +262,7 @@ class RechargeLogic extends BaseApiLogic
         }
     }
 
-    public function add($money, $status, $config_ids, $favorable_price, $give, $pay_methods = 0)
+    public function add($money, $status, $config_ids, $favorable_price, $give, $pay_methods = 0, $in_shop = 1)
     {
         // 构建支付方式数组
         $gearData = [];
@@ -290,6 +290,7 @@ class RechargeLogic extends BaseApiLogic
         $add_data = [
             'money' => round($money, 2),
             'status' => $status,
+            'in_shop' => (int)$in_shop,
             'gear' => \GuzzleHttp\json_encode($gearData),  // 存储到gear字段
             'created_at' => date('Y-m-d H:i:s'),
             'favorable_price' => round($favorable_price, 2),

+ 3 - 3
app/Http/logic/api/AiPayLogic.php

@@ -45,9 +45,9 @@ class AiPayLogic extends BaseApiLogic
 
         $methodMap = [
             1 => '1101',
-            2 => '1102',
-            4 => '1103',
-            8 => '1104',
+            2 => '1104',
+            4 => '1108',
+            8 => '1109',
         ];
         $paymentMethod = $methodMap[$pay_method] ?? ($config['paymentMethod'] ?? '1101');
 

+ 338 - 0
app/Services/HolidayWheelService.php

@@ -0,0 +1,338 @@
+<?php
+
+namespace App\Services;
+
+use App\Utility\SetNXLock;
+use App\Util;
+use Illuminate\Support\Facades\DB;
+
+class HolidayWheelService
+{
+    /**
+     * 获取节假日大转盘配置 + 用户状态
+     */
+    public function getWheelInfo(int $userId): array
+    {
+        $activity = DB::connection('write')
+            ->table('agent.dbo.holiday_wheel_activity')
+            ->orderBy('id', 'desc')
+            ->first();
+
+        $now = now();
+
+        $status = 0;
+        $startTime = null;
+        $endTime = null;
+        $iconUrl = '';
+        // 默认规则从活动配置 + 商城档位中计算(包含金额、次数和档位信息)
+        $rechargeRules = $this->getDefaultRechargeRules();
+
+        if ($activity) {
+            $status = (int)($activity->status ?? 0);
+            $startTime = $activity->start_time;
+            $endTime = $activity->end_time;
+            $iconUrl = $activity->icon_url ?? '';
+
+            // 如果当前时间不在活动时间范围内,则前端状态强制视为关闭(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.holiday_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.holiday_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,
+            'icon_url' => $iconUrl,
+            'slots' => $slots,
+            'user' => [
+                'left_times' => $leftTimes,
+                'total_times' => $totalTimes,
+            ],
+            'recharge_rules' => $rechargeRules,
+            'now' => $now->toDateTimeString(),
+        ];
+    }
+
+    /**
+     * 充值赠送转盘次数(在充值成功后调用)
+     * 有 gift_id(首充礼包301,破产礼包302)的充值不添加次数
+     */
+    public function grantTimesOnRecharge(int $userId, float $payAmt, int $giftId = 0): void
+    {
+        if (in_array($giftId, [301, 302], true)) {
+            return;
+        }
+
+        $activity = DB::connection('write')
+            ->table('agent.dbo.holiday_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.holiday_wheel_user')
+                ->where('UserID', $userId)
+                ->lockForUpdate()
+                ->first();
+
+            if ($row) {
+                DB::connection('write')
+                    ->table('agent.dbo.holiday_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.holiday_wheel_user')
+                    ->insert([
+                        'UserID' => $userId,
+                        'left_times' => $addTimes,
+                        'total_times' => $addTimes,
+                        'created_at' => now(),
+                        'updated_at' => now(),
+                    ]);
+            }
+        });
+    }
+
+    /**
+     * 执行一次转盘抽奖
+     */
+    public function spin(int $userId): array
+    {
+        $redisKey = 'holiday_wheel_spin_' . $userId;
+        $lock = SetNXLock::getExclusiveLock($redisKey, 5);
+        if (!$lock) {
+            throw new \RuntimeException('操作太频繁,请稍后再试');
+        }
+
+        try {
+            $activity = DB::connection('write')
+                ->table('agent.dbo.holiday_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.holiday_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.holiday_wheel_user')
+                ->where('UserID', $userId)
+                ->lockForUpdate()
+                ->first();
+
+            if (!$userRow || (int)$userRow->left_times <= 0) {
+                DB::connection('write')->rollBack();
+                throw new \RuntimeException('没有可用的转盘次数');
+            }
+
+            $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.holiday_wheel_user')
+                ->where('UserID', $userId)
+                ->update([
+                    'left_times' => (int)$userRow->left_times - 1,
+                    'updated_at' => now(),
+                ]);
+
+            DB::connection('write')
+                ->table('agent.dbo.holiday_wheel_history')
+                ->insert([
+                    'UserID' => $userId,
+                    'slot_index' => $slotIndex,
+                    'reward' => $reward,
+                    'created_at' => now(),
+                ]);
+
+            DB::connection('write')->commit();
+
+            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.holiday_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('in_shop', 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,
+                ];
+            } else {
+                $rule['gear'] = null;
+            }
+        }
+        unset($rule);
+
+        return $rules;
+    }
+}
+

+ 12 - 1
app/Services/OrderServices.php

@@ -16,6 +16,7 @@ use App\Jobs\AfEvent;
 use App\Models\AgentUser;
 use App\Models\RecordScoreInfo;
 use App\Models\RecordUserDataStatistics;
+use App\Services\HolidayWheelService;
 use App\Util;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
@@ -195,7 +196,17 @@ class  OrderServices
             DB::connection('write')->table('QPRecordDB.dbo.RecordUserTotalStatistics')
                 ->updateOrInsert(['UserID' => $user_id], ['LastRechargeValue' => $payAmt]);
 
-            
+            // 节假日大转盘:根据充值金额增加转盘次数(首充礼包/破产礼包不计入)
+            try {
+                (new HolidayWheelService())->grantTimesOnRecharge($user_id, $payAmt, (int)$GiftsID);
+            } catch (\Throwable $e) {
+                \Log::error('holiday wheel grant times failed', [
+                    'user_id' => $user_id,
+                    'payAmt' => $payAmt,
+                    'GiftsID' => $GiftsID,
+                    'error' => $e->getMessage(),
+                ]);
+            }
 
 
         }

+ 94 - 0
resources/views/admin/holiday_wheel/history.blade.php

@@ -0,0 +1,94 @@
+@extends('base.base')
+@section('base')
+<div class="main-panel">
+    <div class="content-wrapper">
+        <div class="page-header">
+            <h3 class="page-title">
+                <span class="page-title-icon bg-gradient-primary text-white mr-2">
+                    <i class="mdi mdi-history"></i>
+                </span>
+                节假日大转盘抽奖记录
+            </h3>
+        </div>
+
+        <div class="row mb-3">
+            <div class="col-12 grid-margin stretch-card">
+                <div class="card">
+                    <div class="card-body">
+                        <form class="form-inline" id="search-form" method="get" action="">
+                            <div class="form-group mr-3">
+                                <label class="mr-2">UserID</label>
+                                <input type="text" class="form-control" name="user_id" value="{{ $user_id ?? '' }}" placeholder="按 UserID 筛选">
+                            </div>
+                            <div class="form-group mr-3">
+                                <label class="mr-2">GameID</label>
+                                <input type="text" class="form-control" name="game_id" value="{{ $game_id ?? '' }}" placeholder="按 GameID 筛选">
+                            </div>
+                            <div class="form-group mr-3">
+                                <label class="mr-2">开始日期</label>
+                                <input type="date" class="form-control" name="start_date" value="{{ $start_date ?? '' }}">
+                            </div>
+                            <div class="form-group mr-3">
+                                <label class="mr-2">结束日期</label>
+                                <input type="date" class="form-control" name="end_date" value="{{ $end_date ?? '' }}">
+                            </div>
+                            <button type="submit" class="btn btn-sm btn-gradient-primary mr-2">筛选</button>
+                            <button type="button" class="btn btn-sm btn-gradient-warning" onclick="resetSearch()">重置</button>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="row">
+            <div class="col-lg-12 grid-margin stretch-card">
+                <div class="card">
+                    <div class="card-body">
+                        <h4 class="card-title">抽奖记录列表</h4>
+                        <div class="table-responsive">
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr>
+                                    <th>ID</th>
+                                    <th>UserID</th>
+                                    <th>GameID</th>
+                                    <th>昵称</th>
+                                    <th>档位索引 (slot_index)</th>
+                                    <th>奖励值 (reward)</th>
+                                    <th>抽奖时间</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                @forelse($list as $item)
+                                    <tr>
+                                        <td>{{ $item->id }}</td>
+                                        <td>{{ $item->UserID }}</td>
+                                        <td>{{ $item->GameID }}</td>
+                                        <td>{{ $item->NickName }}</td>
+                                        <td>{{ $item->slot_index }}</td>
+                                        <td>{{ number_format($item->reward, 2) }}</td>
+                                        <td>{{ $item->created_at }}</td>
+                                    </tr>
+                                @empty
+                                    <tr>
+                                        <td colspan="7" class="text-center text-muted">暂无记录</td>
+                                    </tr>
+                                @endforelse
+                                </tbody>
+                            </table>
+                        </div>
+                        <div class="mt-3">
+                            {{ $list->appends(request()->all())->links() }}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    function resetSearch() {
+        window.location.href = window.location.pathname;
+    }
+</script>
+@endsection

+ 216 - 0
resources/views/admin/holiday_wheel/index.blade.php

@@ -0,0 +1,216 @@
+@extends('base.base')
+@section('base')
+<div class="main-panel">
+    <div class="content-wrapper">
+        <div class="page-header">
+            <h3 class="page-title">
+                <span class="page-title-icon bg-gradient-primary text-white mr-2">
+                    <i class="mdi mdi-tumblr-reblog"></i>
+                </span>
+                节假日大转盘配置
+            </h3>
+        </div>
+
+        <div class="row">
+            <div class="col-12 grid-margin stretch-card">
+                <div class="card">
+                    <div class="card-body">
+                        <h4 class="card-title">活动配置</h4>
+                        <form class="forms-sample" id="activity-form">
+                            <div class="form-row">
+                                <div class="form-group col-md-4">
+                                    <label>活动开始时间</label>
+                                    <input type="datetime-local" class="form-control" name="start_time"
+                                           value="{{ !empty($activity['start_time']) ? \Carbon\Carbon::parse($activity['start_time'])->format('Y-m-d\TH:i') : '' }}">
+                                </div>
+                                <div class="form-group col-md-4">
+                                    <label>活动结束时间</label>
+                                    <input type="datetime-local" class="form-control" name="end_time"
+                                           value="{{ !empty($activity['end_time']) ? \Carbon\Carbon::parse($activity['end_time'])->format('Y-m-d\TH:i') : '' }}">
+                                </div>
+                                <div class="form-group col-md-4">
+                                    <label>活动状态</label>
+                                    <select class="form-control" name="status">
+                                        <option value="0" {{ ($activity['status'] ?? 0) == 0 ? 'selected' : '' }}>关闭</option>
+                                        <option value="1" {{ ($activity['status'] ?? 0) == 1 ? 'selected' : '' }}>开启</option>
+                                    </select>
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                <label>活动图标地址</label>
+                                <input type="text" class="form-control" name="icon_url"
+                                       placeholder="请输入活动图标URL"
+                                       value="{{ $activity['icon_url'] ?? '' }}">
+                            </div>
+                            <div class="form-group">
+                                <label>充值规则(充值金额 -> 次数)</label>
+                                <table class="table table-bordered" id="rules-table">
+                                    <thead>
+                                    <tr>
+                                        <th>充值金额 (amount)</th>
+                                        <th>赠送次数 (times)</th>
+                                        <th>操作</th>
+                                    </tr>
+                                    </thead>
+                                    <tbody>
+                                    @foreach($rules as $idx => $rule)
+                                        <tr>
+                                            <td>
+                                                <input type="number" step="0.01" class="form-control"
+                                                       name="rules[{{ $idx }}][amount]"
+                                                       value="{{ $rule['amount'] }}">
+                                            </td>
+                                            <td>
+                                                <input type="number" step="1" class="form-control"
+                                                       name="rules[{{ $idx }}][times]"
+                                                       value="{{ $rule['times'] }}">
+                                            </td>
+                                            <td>
+                                                <button type="button" class="btn btn-sm btn-danger" onclick="removeRuleRow(this)">删除</button>
+                                            </td>
+                                        </tr>
+                                    @endforeach
+                                    </tbody>
+                                </table>
+                                <button type="button" class="btn btn-sm btn-gradient-info" onclick="addRuleRow()">添加规则</button>
+                                <small class="form-text text-muted mt-2">
+                                    说明:这里配置充值金额与对应增加的大转盘次数,例如 9.99 → 1 次。
+                                </small>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="row mt-3">
+            <div class="col-12 grid-margin stretch-card">
+                <div class="card">
+                    <div class="card-body">
+                        <h4 class="card-title">16档转盘配置</h4>
+                        <p class="card-description">slot_index 0-15,每档一个 reward(奖励值)、weight(权重)、sort_index(排序索引)</p>
+                        <div class="table-responsive">
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr>
+                                    <th>档位索引 (slot_index)</th>
+                                    <th>奖励值 (reward)</th>
+                                    <th>权重 (weight)</th>
+                                    <th>排序索引 (sort_index)</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                @foreach($slots as $slot)
+                                    <tr>
+                                        <td>
+                                            <input type="text" class="form-control" value="{{ $slot['slot_index'] }}" disabled>
+                                        </td>
+                                        <td>
+                                            <input type="number" step="0.01" class="form-control"
+                                                   name="slots[{{ $slot['slot_index'] }}][reward]"
+                                                   value="{{ $slot['reward'] }}">
+                                        </td>
+                                        <td>
+                                            <input type="number" step="1" class="form-control"
+                                                   name="slots[{{ $slot['slot_index'] }}][weight]"
+                                                   value="{{ $slot['weight'] }}">
+                                        </td>
+                                        <td>
+                                            <input type="number" step="1" class="form-control"
+                                                   name="slots[{{ $slot['slot_index'] }}][sort_index]"
+                                                   value="{{ $slot['sort_index'] }}">
+                                        </td>
+                                    </tr>
+                                @endforeach
+                                </tbody>
+                            </table>
+                        </div>
+
+                        <button type="button" class="btn btn-sm btn-gradient-primary mt-3" onclick="saveConfig()">
+                            <i class="mdi mdi-content-save"></i> 保存配置
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script>
+    function saveConfig() {
+        var activityData = $("#activity-form").serializeArray();
+        var data = {};
+        activityData.forEach(function (item) {
+            data[item.name] = item.value;
+        });
+
+        var slots = {};
+        $("input[name^='slots']").each(function () {
+            var name = $(this).attr('name'); // slots[0][reward]
+            var match = name.match(/slots\[(\d+)]\[(\w+)]/);
+            if (match) {
+                var index = match[1];
+                var field = match[2];
+                if (!slots[index]) {
+                    slots[index] = {};
+                }
+                slots[index][field] = $(this).val();
+            }
+        });
+
+        data['slots'] = slots;
+
+        // 处理充值规则
+        var rules = {};
+        $("input[name^='rules']").each(function () {
+            var name = $(this).attr('name'); // rules[0][amount]
+            var match = name.match(/rules\[(\d+)]\[(\w+)]/);
+            if (match) {
+                var index = match[1];
+                var field = match[2];
+                if (!rules[index]) {
+                    rules[index] = {};
+                }
+                rules[index][field] = $(this).val();
+            }
+        });
+
+        // 转成数组并过滤空行
+        var rulesArr = [];
+        Object.keys(rules).forEach(function (k) {
+            var r = rules[k];
+            var amount = parseFloat(r.amount || 0);
+            var times = parseInt(r.times || 0);
+            if (!isNaN(amount) && amount > 0 && !isNaN(times) && times > 0) {
+                rulesArr.push({amount: amount, times: times});
+            }
+        });
+
+        data['recharge_rules'] = JSON.stringify(rulesArr);
+
+        myRequest('/admin/holiday-wheel/update', 'post', data, function (res) {
+            layer.msg(res.msg || (res.code === '200' ? '保存成功' : '保存失败'));
+            if (res.code === '200') {
+                setTimeout(function () {
+                    window.location.reload();
+                }, 1500);
+            }
+        });
+    }
+
+    function addRuleRow() {
+        var tbody = $("#rules-table tbody");
+        var index = tbody.children("tr").length;
+        var row = '<tr>' +
+            '<td><input type="number" step="0.01" class="form-control" name="rules[' + index + '][amount]" value=""></td>' +
+            '<td><input type="number" step="1" class="form-control" name="rules[' + index + '][times]" value=""></td>' +
+            '<td><button type="button" class="btn btn-sm btn-danger" onclick="removeRuleRow(this)">删除</button></td>' +
+            '</tr>';
+        tbody.append(row);
+    }
+
+    function removeRuleRow(btn) {
+        $(btn).closest('tr').remove();
+    }
+</script>
+@endsection

+ 8 - 1
resources/views/admin/recharge/add.blade.php

@@ -61,6 +61,12 @@
                                     </div>
                                 </div>
 
+                                <div class="form-group">
+                                    <label for="in_shop">*是否在商城展示</label><br>
+                                    显示 <input type="radio" name="in_shop" value="1" checked>&nbsp;&nbsp;
+                                    隐藏 <input type="radio" name="in_shop" value="0">
+                                </div>
+
                                 <div class="form-group">
                                     <label for="account">*开关</label><br>
                                     {{ __('auto.开启') }} <input type="radio"   name="status" value="1" checked>&nbsp;&nbsp;
@@ -104,6 +110,7 @@
             var status = data.status
             var favorable_price = data.favorable_price
             var give = data.give
+            var in_shop = data.in_shop
             
             // 计算支付方式位掩码
             var pay_methods = 0;
@@ -111,7 +118,7 @@
                 pay_methods += parseInt($(this).val());
             });
             
-            myRequest("/admin/recharge/add","post", {money,status,favorable_price,give,pay_methods},function(res){
+            myRequest("/admin/recharge/add","post", {money,status,favorable_price,give,pay_methods,in_shop},function(res){
                 if(res.code == '200'){
                     layer.msg(res.msg)
                     setTimeout(function(){

+ 8 - 0
resources/views/admin/recharge/gear_list.blade.php

@@ -36,6 +36,7 @@
                                     <th width="5%">{{ __('auto.充值档位') }}</th>
                                     <th width="5%">{{ __('auto.赠送') }}</th>
                                     <th width="15%">{{ __('auto.支持的支付方式') }}</th>
+                                    <th width="8%">商城展示</th>
                                     <th width="8%">{{ __('auto.档位显示开关') }}</th>
                                     <th width="8%">{{ __('auto.修改配置') }}</th>
                                 </tr>
@@ -46,6 +47,13 @@
                                         <td>{{ $v->money }}{{ env('CONFIG_24680_CURRENCY') }}</td>
                                         <td>{{ $v->give }}{{ env('CONFIG_24680_CURRENCY') }}</td>
                                         <td>{{ $v->gear ?: '-' }}</td>
+                                        <td>
+                                            @if ($v->in_shop ?? 1)
+                                                <span style="color: #0b8e36">显示</span>
+                                            @else
+                                                <span style="color: #999999">隐藏</span>
+                                            @endif
+                                        </td>
                                         <td>
                                             @if ($v->status == 1)
                                                 <span style="color: #0bb20c">{{ __('auto.已开启') }}</span>

+ 8 - 1
resources/views/admin/recharge/update_config.blade.php

@@ -31,6 +31,12 @@
                                     <input type="text"  class="form-control required" name="second_give" placeholder="{{ __('auto.请输入充值档位') }}" value="{{$info->second_give}}">
                                 </div>
 
+                                <div class="form-group">
+                                    <label for="in_shop">*是否在商城展示</label><br>
+                                    显示 <input type="radio" name="in_shop" value="1" {{ ($info->in_shop ?? 1) == 1 ? 'checked' : '' }}>&nbsp;&nbsp;
+                                    隐藏 <input type="radio" name="in_shop" value="0" {{ ($info->in_shop ?? 1) == 0 ? 'checked' : '' }}>
+                                </div>
+
                                 <div class="form-group">
                                     <label for="pay_methods">*支持的支付方式</label><br>
                                     <div class="form-check form-check-inline">
@@ -98,6 +104,7 @@
             var favorable_price = data.favorable_price
             var give = data.give
             var second_give = data.second_give
+            var in_shop = data.in_shop
             
             // 计算支付方式位掩码
             var pay_methods = 0;
@@ -105,7 +112,7 @@
                 pay_methods += parseInt($(this).val());
             });
             
-            myRequest("/admin/recharge/update_config/"+id,"post", {money,favorable_price,give,second_give,pay_methods},function(res){
+            myRequest("/admin/recharge/update_config/"+id,"post", {money,favorable_price,give,second_give,pay_methods,in_shop},function(res){
                 if(res.code == '200'){
                     layer.msg(res.msg)
                     setTimeout(function(){

+ 4 - 0
routes/game.php

@@ -277,6 +277,10 @@ Route::group([
 //    $route->any('/redpack/receive', 'Game\ActivityController@RedReceive');
     $route->any('/turnplate/bonus', 'Game\ExtensionsController@kanBonus');//bonus
 
+    // 节假日大转盘
+    $route->any('/holiday_wheel/info', 'Game\ActivityController@holidayWheelInfo');
+    $route->any('/holiday_wheel/spin', 'Game\ActivityController@holidayWheelSpin');
+
     // VIP提现诱导任务
     $route->any('/vip-withdraw/tasks', 'Game\ActivityController@getVipWithdrawTasks');
     $route->any('/vip-withdraw/claim', 'Game\ActivityController@claimVipWithdrawReward');

+ 5 - 0
routes/web.php

@@ -737,6 +737,11 @@ Route::group([
         $route->any('/game-number-mapping/update/{id}', 'Admin\GameNumberMappingController@update')->name('admin.game-number-mapping.update');
         $route->post('/game-number-mapping/delete/{id}', 'Admin\GameNumberMappingController@delete')->name('admin.game-number-mapping.delete');
         
+        // 节假日大转盘配置
+        $route->any('/holiday-wheel', 'Admin\HolidayWheelController@index')->name('admin.holiday-wheel');
+        $route->post('/holiday-wheel/update', 'Admin\HolidayWheelController@update')->name('admin.holiday-wheel.update');
+        $route->get('/holiday-wheel/history', 'Admin\HolidayWheelController@history')->name('admin.holiday-wheel.history');
+        
         // Bonus购买回报配置
         $route->any('/game-buy-bonus-config', 'Admin\GameBuyBonusConfigController@index')->name('admin.game-buy-bonus-config');
         $route->post('/game-buy-bonus-config/update', 'Admin\GameBuyBonusConfigController@update')->name('admin.game-buy-bonus-config.update');