新增游戏管理系统:①game_configs表+模型(forGame/isEnabled/param静态方法) ②GameConfigSeeder初始化5款游戏参数 ③后台卡片式管理页(开关+参数表单) ④侧边栏菜单「游戏管理」
This commit is contained in:
72
app/Http/Controllers/Admin/GameConfigController.php
Normal file
72
app/Http/Controllers/Admin/GameConfigController.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:游戏配置后台管理控制器
|
||||
*
|
||||
* 管理员可在此页面统一管理所有娱乐游戏的开关状态和核心参数。
|
||||
* 每个游戏的参数说明通过前端渲染,后台只做通用 JSON 存储。
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\GameConfig;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class GameConfigController extends Controller
|
||||
{
|
||||
/**
|
||||
* 游戏管理总览页面。
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
$games = GameConfig::orderBy('id')->get();
|
||||
|
||||
return view('admin.game-configs.index', compact('games'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换游戏开启/关闭状态。
|
||||
*/
|
||||
public function toggle(GameConfig $gameConfig): JsonResponse
|
||||
{
|
||||
$gameConfig->update(['enabled' => ! $gameConfig->enabled]);
|
||||
$gameConfig->clearCache();
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'enabled' => $gameConfig->enabled,
|
||||
'message' => $gameConfig->enabled
|
||||
? "「{$gameConfig->name}」已开启"
|
||||
: "「{$gameConfig->name}」已关闭",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存游戏核心参数。
|
||||
*
|
||||
* 接收前端提交的 params JSON 对象并合并至现有配置。
|
||||
*/
|
||||
public function updateParams(Request $request, GameConfig $gameConfig): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'params' => 'required|array',
|
||||
]);
|
||||
|
||||
// 合并参数,保留已有键,只更新传入的键
|
||||
$current = $gameConfig->params ?? [];
|
||||
$updated = array_merge($current, $request->input('params'));
|
||||
|
||||
$gameConfig->update(['params' => $updated]);
|
||||
$gameConfig->clearCache();
|
||||
|
||||
return back()->with('success', "「{$gameConfig->name}」参数已保存!");
|
||||
}
|
||||
}
|
||||
80
app/Models/GameConfig.php
Normal file
80
app/Models/GameConfig.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:游戏配置模型
|
||||
*
|
||||
* 集中管理所有娱乐游戏的开关与参数,提供统一的读取接口。
|
||||
* 游戏服务层通过 GameConfig::forGame($key) 读取当前配置。
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class GameConfig extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'game_key',
|
||||
'name',
|
||||
'icon',
|
||||
'description',
|
||||
'enabled',
|
||||
'params',
|
||||
];
|
||||
|
||||
/**
|
||||
* 属性类型转换。
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'enabled' => 'boolean',
|
||||
'params' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
// ─── 静态工具方法 ─────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* 根据游戏标识获取配置(带缓存)。
|
||||
*
|
||||
* @param string $key 游戏标识,如 'baccarat'
|
||||
*/
|
||||
public static function forGame(string $key): ?static
|
||||
{
|
||||
return Cache::remember("game_config:{$key}", 60, fn () => static::where('game_key', $key)->first());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断游戏是否已开启。
|
||||
*/
|
||||
public static function isEnabled(string $key): bool
|
||||
{
|
||||
return (bool) static::forGame($key)?->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定游戏的某个参数值,不存在时返回默认值。
|
||||
*
|
||||
* @param string $key 游戏标识
|
||||
* @param string $param 参数名
|
||||
* @param mixed $default 默认值
|
||||
*/
|
||||
public static function param(string $key, string $param, mixed $default = null): mixed
|
||||
{
|
||||
return static::forGame($key)?->params[$param] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除游戏配置缓存。
|
||||
*/
|
||||
public function clearCache(): void
|
||||
{
|
||||
Cache::forget("game_config:{$this->game_key}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:游戏配置表迁移
|
||||
*
|
||||
* 集中管理聊天室所有娱乐游戏的开关状态和核心参数。
|
||||
* 每个游戏对应一行记录,params 字段存储各游戏的 JSON 参数。
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* 创建 game_configs 表。
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('game_configs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('game_key', 50)->unique()->comment('游戏唯一标识(如 baccarat、slot_machine)');
|
||||
$table->string('name', 100)->comment('游戏中文名');
|
||||
$table->string('icon', 10)->default('🎮')->comment('游戏图标 Emoji');
|
||||
$table->text('description')->nullable()->comment('游戏简介');
|
||||
$table->boolean('enabled')->default(false)->comment('是否开启');
|
||||
$table->json('params')->nullable()->comment('游戏核心参数(JSON)');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 回滚迁移。
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('game_configs');
|
||||
}
|
||||
};
|
||||
128
database/seeders/GameConfigSeeder.php
Normal file
128
database/seeders/GameConfigSeeder.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:游戏默认配置数据填充器
|
||||
*
|
||||
* 初始化所有娱乐游戏的默认参数,管理员可在后台修改。
|
||||
* 所有游戏默认关闭,需要管理员手动开启。
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\GameConfig;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class GameConfigSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* 填充所有游戏默认配置。
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$games = [
|
||||
// ─── 百家乐(大小押注)────────────────────────────────────
|
||||
[
|
||||
'game_key' => 'baccarat',
|
||||
'name' => '百家乐',
|
||||
'icon' => '🎲',
|
||||
'description' => '系统每隔一段时间自动开一局,玩家在倒计时内押注大/小/豹子,骰子结果决定胜负。',
|
||||
'enabled' => false,
|
||||
'params' => [
|
||||
'interval_minutes' => 2, // 多少分钟开一局
|
||||
'bet_window_seconds' => 60, // 每局押注窗口(秒)
|
||||
'min_bet' => 100, // 最低押注金币
|
||||
'max_bet' => 50000, // 最高押注金币
|
||||
'payout_big' => 1, // 大:1:1 赔率
|
||||
'payout_small' => 1, // 小:1:1 赔率
|
||||
'payout_triple' => 24, // 豹子:1:24 赔率
|
||||
'kill_points' => [3, 18], // 庄家收割点数(全灭)
|
||||
],
|
||||
],
|
||||
|
||||
// ─── 老虎机 ──────────────────────────────────────────────
|
||||
[
|
||||
'game_key' => 'slot_machine',
|
||||
'name' => '老虎机',
|
||||
'icon' => '🎰',
|
||||
'description' => '消耗金币转动老虎机,三列图案匹配可获得不同倍率奖励,三个7大奖全服广播。',
|
||||
'enabled' => false,
|
||||
'params' => [
|
||||
'cost_per_spin' => 100, // 每次旋转消耗
|
||||
'house_edge_percent' => 15, // 庄家边际(%)
|
||||
'daily_limit' => 100, // 每日最多转动次数(0=不限)
|
||||
'jackpot_payout' => 100, // 三个7 赔率
|
||||
'triple_payout' => 50, // 三个💎 赔率
|
||||
'same_payout' => 10, // 其他三同 赔率
|
||||
'pair_payout' => 2, // 两同 赔率
|
||||
'curse_enabled' => true, // 是否开启诅咒(三💀扣双倍)
|
||||
],
|
||||
],
|
||||
|
||||
// ─── 神秘箱子 ────────────────────────────────────────────
|
||||
[
|
||||
'game_key' => 'mystery_box',
|
||||
'name' => '神秘箱子',
|
||||
'icon' => '📦',
|
||||
'description' => '管理员随时投放或系统定时自动投放神秘箱,最快发送暗号的用户开箱获得奖励。',
|
||||
'enabled' => false,
|
||||
'params' => [
|
||||
'auto_drop_enabled' => false, // 是否自动定时投放
|
||||
'auto_interval_hours' => 2, // 自动投放间隔(小时)
|
||||
'claim_window_seconds' => 60, // 领取窗口(秒)
|
||||
'min_reward' => 500, // 普通箱最低奖励
|
||||
'max_reward' => 2000, // 普通箱最高奖励
|
||||
'rare_min_reward' => 5000, // 稀有箱最低奖励
|
||||
'rare_max_reward' => 20000, // 稀有箱最高奖励
|
||||
'trap_chance_percent' => 10, // 黑化箱触发概率(%)
|
||||
],
|
||||
],
|
||||
|
||||
// ─── 赛马竞猜 ────────────────────────────────────────────
|
||||
[
|
||||
'game_key' => 'horse_racing',
|
||||
'name' => '赛马竞猜',
|
||||
'icon' => '🐎',
|
||||
'description' => '系统定期举办赛马,用户在倒计时内下注,按注池赔率结算,跑马过程 WebSocket 实时播报。',
|
||||
'enabled' => false,
|
||||
'params' => [
|
||||
'interval_minutes' => 30, // 多少分钟一场
|
||||
'bet_window_seconds' => 90, // 押注窗口(秒)
|
||||
'race_duration' => 30, // 跑马动画时长(秒)
|
||||
'horse_count' => 4, // 参赛马匹数量
|
||||
'min_bet' => 100, // 最低押注
|
||||
'max_bet' => 100000, // 最高押注
|
||||
'house_take_percent' => 5, // 庄家抽水(%)
|
||||
],
|
||||
],
|
||||
|
||||
// ─── 神秘占卜 ────────────────────────────────────────────
|
||||
[
|
||||
'game_key' => 'fortune_telling',
|
||||
'name' => '神秘占卜',
|
||||
'icon' => '🔮',
|
||||
'description' => '每日一次免费占卜,系统生成玄学签文并赋予当日加成效果(幸运/倒霉)。额外占卜消耗金币。',
|
||||
'enabled' => false,
|
||||
'params' => [
|
||||
'free_count_per_day' => 1, // 每日免费次数
|
||||
'extra_cost' => 500, // 额外次数消耗金币
|
||||
'buff_duration_hours' => 24, // 加成效果持续时间
|
||||
'jackpot_chance' => 5, // 上上签概率(%)
|
||||
'good_chance' => 20, // 上签概率(%)
|
||||
'bad_chance' => 20, // 下签概率(%)
|
||||
'curse_chance' => 5, // 大凶签概率(%)
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($games as $game) {
|
||||
GameConfig::updateOrCreate(
|
||||
['game_key' => $game['game_key']],
|
||||
$game,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
254
resources/views/admin/game-configs/index.blade.php
Normal file
254
resources/views/admin/game-configs/index.blade.php
Normal file
@@ -0,0 +1,254 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', '游戏管理')
|
||||
|
||||
@section('content')
|
||||
<div class="space-y-6">
|
||||
|
||||
{{-- 页头 --}}
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<h2 class="text-lg font-bold text-gray-800">🎮 游戏管理</h2>
|
||||
<p class="text-xs text-gray-500 mt-1">统一管理聊天室所有娱乐游戏的开关状态与核心参数,所有游戏默认关闭。</p>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-lg text-sm">
|
||||
✅ {{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- 游戏卡片列表 --}}
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
@foreach ($games as $game)
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden"
|
||||
id="game-card-{{ $game->game_key }}">
|
||||
|
||||
{{-- 卡片头部:游戏名 + 开关 --}}
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-100
|
||||
{{ $game->enabled ? 'bg-emerald-50' : 'bg-gray-50' }}">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-3xl">{{ $game->icon }}</span>
|
||||
<div>
|
||||
<div class="font-bold text-gray-800 flex items-center gap-2">
|
||||
{{ $game->name }}
|
||||
<span id="badge-{{ $game->game_key }}"
|
||||
class="text-xs px-2 py-0.5 rounded-full font-bold
|
||||
{{ $game->enabled ? 'bg-emerald-100 text-emerald-700' : 'bg-gray-200 text-gray-500' }}">
|
||||
{{ $game->enabled ? '运行中' : '已关闭' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-0.5">{{ $game->description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- 大开关按钮 --}}
|
||||
<button onclick="toggleGame('{{ $game->game_key }}', {{ $game->id }})"
|
||||
id="toggle-btn-{{ $game->game_key }}"
|
||||
class="px-5 py-2 rounded-lg font-bold text-sm transition shadow-sm
|
||||
{{ $game->enabled ? 'bg-red-500 hover:bg-red-600 text-white' : 'bg-emerald-500 hover:bg-emerald-600 text-white' }}">
|
||||
{{ $game->enabled ? '⏸ 关闭游戏' : '▶ 开启游戏' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- 参数配置区域 --}}
|
||||
<div class="p-5">
|
||||
<form action="{{ route('admin.game-configs.params', $game) }}" method="POST">
|
||||
@csrf
|
||||
|
||||
@php
|
||||
$params = $game->params ?? [];
|
||||
$labels = gameParamLabels($game->game_key);
|
||||
@endphp
|
||||
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||
@foreach ($params as $paramKey => $paramValue)
|
||||
@php $meta = $labels[$paramKey] ?? ['label' => $paramKey, 'type' => 'number', 'unit' => ''] @endphp
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">
|
||||
{{ $meta['label'] }}
|
||||
@if ($meta['unit'])
|
||||
<span class="font-normal text-gray-400">({{ $meta['unit'] }})</span>
|
||||
@endif
|
||||
</label>
|
||||
|
||||
@if ($meta['type'] === 'boolean')
|
||||
<select name="params[{{ $paramKey }}]"
|
||||
class="w-full border border-gray-300 rounded-lg p-2 text-sm focus:border-indigo-400">
|
||||
<option value="1" {{ $paramValue ? 'selected' : '' }}>是</option>
|
||||
<option value="0" {{ !$paramValue ? 'selected' : '' }}>否</option>
|
||||
</select>
|
||||
@elseif ($meta['type'] === 'array')
|
||||
<input type="text" name="params[{{ $paramKey }}]"
|
||||
value="{{ implode(',', (array) $paramValue) }}"
|
||||
class="w-full border border-gray-300 rounded-lg p-2 text-sm focus:border-indigo-400"
|
||||
placeholder="多个值用逗号分隔">
|
||||
@else
|
||||
<input type="{{ $meta['type'] }}" name="params[{{ $paramKey }}]"
|
||||
value="{{ $paramValue }}" step="{{ $meta['step'] ?? 1 }}"
|
||||
min="{{ $meta['min'] ?? 0 }}"
|
||||
class="w-full border border-gray-300 rounded-lg p-2 text-sm focus:border-indigo-400">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<button type="submit"
|
||||
class="px-6 py-2 bg-indigo-600 text-white rounded-lg font-bold hover:bg-indigo-700 transition text-sm shadow-sm">
|
||||
💾 保存参数
|
||||
</button>
|
||||
<span class="text-xs text-gray-400">修改后立即生效(缓存60秒刷新)</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@if ($games->isEmpty())
|
||||
<div class="bg-white rounded-xl border border-gray-100 p-12 text-center text-gray-400">
|
||||
暂无游戏配置,请先运行 <code class="bg-gray-100 px-2 py-1 rounded">php artisan db:seed
|
||||
--class=GameConfigSeeder</code>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 切换游戏开启/关闭状态
|
||||
*/
|
||||
function toggleGame(gameKey, gameId) {
|
||||
fetch(`/admin/game-configs/${gameId}/toggle`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.ok) return;
|
||||
|
||||
const enabled = data.enabled;
|
||||
const card = document.getElementById(`game-card-${gameKey}`);
|
||||
const badge = document.getElementById(`badge-${gameKey}`);
|
||||
const btn = document.getElementById(`toggle-btn-${gameKey}`);
|
||||
const header = card?.querySelector('.flex.items-center.justify-between');
|
||||
|
||||
// 更新徽章
|
||||
badge.textContent = enabled ? '运行中' : '已关闭';
|
||||
badge.className = `text-xs px-2 py-0.5 rounded-full font-bold ${enabled
|
||||
? 'bg-emerald-100 text-emerald-700'
|
||||
: 'bg-gray-200 text-gray-500'}`;
|
||||
|
||||
// 更新按钮
|
||||
btn.textContent = enabled ? '⏸ 关闭游戏' : '▶ 开启游戏';
|
||||
btn.className = `px-5 py-2 rounded-lg font-bold text-sm transition shadow-sm ${enabled
|
||||
? 'bg-red-500 hover:bg-red-600 text-white'
|
||||
: 'bg-emerald-500 hover:bg-emerald-600 text-white'}`;
|
||||
|
||||
// 更新头部背景
|
||||
if (header) {
|
||||
header.classList.toggle('bg-emerald-50', enabled);
|
||||
header.classList.toggle('bg-gray-50', !enabled);
|
||||
}
|
||||
|
||||
// Toast 提示
|
||||
alert(data.message);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@php
|
||||
/**
|
||||
* 返回各游戏参数的中文标签说明。
|
||||
*
|
||||
* @param string $gameKey
|
||||
* @return array<string, array{label: string, type: string, unit: string}>
|
||||
*/
|
||||
function gameParamLabels(string $gameKey): array
|
||||
{
|
||||
return match ($gameKey) {
|
||||
'baccarat' => [
|
||||
'interval_minutes' => ['label' => '开局间隔', 'type' => 'number', 'unit' => '分钟', 'min' => 1],
|
||||
'bet_window_seconds' => ['label' => '押注窗口', 'type' => 'number', 'unit' => '秒', 'min' => 10],
|
||||
'min_bet' => ['label' => '最低押注', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'max_bet' => ['label' => '最高押注', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'payout_big' => ['label' => '大赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'payout_small' => ['label' => '小赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'payout_triple' => ['label' => '豹子赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'kill_points' => ['label' => '庄家收割点数', 'type' => 'array', 'unit' => '逗号分隔'],
|
||||
],
|
||||
'slot_machine' => [
|
||||
'cost_per_spin' => ['label' => '每次旋转消耗', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'house_edge_percent' => [
|
||||
'label' => '庄家边际',
|
||||
'type' => 'number',
|
||||
'unit' => '%',
|
||||
'min' => 0,
|
||||
'step' => 0.1,
|
||||
],
|
||||
'daily_limit' => ['label' => '每日转动上限', 'type' => 'number', 'unit' => '次(0=不限)', 'min' => 0],
|
||||
'jackpot_payout' => ['label' => '三个7赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'triple_payout' => ['label' => '三💎赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'same_payout' => ['label' => '其他三同(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'pair_payout' => ['label' => '两同赔率(1:N)', 'type' => 'number', 'unit' => '', 'min' => 1],
|
||||
'curse_enabled' => ['label' => '开启诅咒(三💀)', 'type' => 'boolean', 'unit' => ''],
|
||||
],
|
||||
'mystery_box' => [
|
||||
'auto_drop_enabled' => ['label' => '自动定时投放', 'type' => 'boolean', 'unit' => ''],
|
||||
'auto_interval_hours' => ['label' => '自动投放间隔', 'type' => 'number', 'unit' => '小时', 'min' => 1],
|
||||
'claim_window_seconds' => ['label' => '领取窗口', 'type' => 'number', 'unit' => '秒', 'min' => 10],
|
||||
'min_reward' => ['label' => '普通箱最低奖励', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'max_reward' => ['label' => '普通箱最高奖励', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'rare_min_reward' => ['label' => '稀有箱最低奖励', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'rare_max_reward' => ['label' => '稀有箱最高奖励', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'trap_chance_percent' => [
|
||||
'label' => '黑化箱概率',
|
||||
'type' => 'number',
|
||||
'unit' => '%',
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
],
|
||||
],
|
||||
'horse_racing' => [
|
||||
'interval_minutes' => ['label' => '比赛间隔', 'type' => 'number', 'unit' => '分钟', 'min' => 5],
|
||||
'bet_window_seconds' => ['label' => '押注窗口', 'type' => 'number', 'unit' => '秒', 'min' => 10],
|
||||
'race_duration' => ['label' => '跑马动画时长', 'type' => 'number', 'unit' => '秒', 'min' => 10],
|
||||
'horse_count' => ['label' => '参赛马匹数', 'type' => 'number', 'unit' => '匹', 'min' => 2, 'max' => 8],
|
||||
'min_bet' => ['label' => '最低押注', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'max_bet' => ['label' => '最高押注', 'type' => 'number', 'unit' => '金币', 'min' => 1],
|
||||
'house_take_percent' => [
|
||||
'label' => '庄家抽水',
|
||||
'type' => 'number',
|
||||
'unit' => '%',
|
||||
'min' => 0,
|
||||
'max' => 20,
|
||||
],
|
||||
],
|
||||
'fortune_telling' => [
|
||||
'free_count_per_day' => ['label' => '每日免费次数', 'type' => 'number', 'unit' => '次', 'min' => 0],
|
||||
'extra_cost' => ['label' => '额外次数消耗', 'type' => 'number', 'unit' => '金币', 'min' => 0],
|
||||
'buff_duration_hours' => ['label' => '加成持续时间', 'type' => 'number', 'unit' => '小时', 'min' => 1],
|
||||
'jackpot_chance' => [
|
||||
'label' => '上上签概率',
|
||||
'type' => 'number',
|
||||
'unit' => '%',
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
],
|
||||
'good_chance' => ['label' => '上签概率', 'type' => 'number', 'unit' => '%', 'min' => 0, 'max' => 100],
|
||||
'bad_chance' => ['label' => '下签概率', 'type' => 'number', 'unit' => '%', 'min' => 0, 'max' => 100],
|
||||
'curse_chance' => [
|
||||
'label' => '大凶签概率',
|
||||
'type' => 'number',
|
||||
'unit' => '%',
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
],
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
@endphp
|
||||
@@ -79,6 +79,10 @@
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.holiday-events.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🎊 节日福利' . $ro !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.game-configs.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.game-configs.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🎮 游戏管理' . $ro !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.departments.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.departments.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🏛️ 部门管理' . $ro !!}
|
||||
|
||||
@@ -309,6 +309,13 @@ Route::middleware(['chat.auth', 'chat.has_position'])->prefix('admin')->name('ad
|
||||
Route::post('/{holidayEvent}/trigger-now', [\App\Http\Controllers\Admin\HolidayEventController::class, 'triggerNow'])->name('trigger-now');
|
||||
Route::delete('/{holidayEvent}', [\App\Http\Controllers\Admin\HolidayEventController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
|
||||
// 🎮 游戏管理(开关 + 核心参数配置)
|
||||
Route::prefix('game-configs')->name('game-configs.')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Admin\GameConfigController::class, 'index'])->name('index');
|
||||
Route::post('/{gameConfig}/toggle', [\App\Http\Controllers\Admin\GameConfigController::class, 'toggle'])->name('toggle');
|
||||
Route::post('/{gameConfig}/params', [\App\Http\Controllers\Admin\GameConfigController::class, 'updateParams'])->name('params');
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user