- 新建 vip_levels 表(名称、图标、颜色、经验/金币倍率、专属进入/离开模板) - 默认4个等级种子:白银🥈(×1.5)、黄金🥇(×2.0)、钻石💎(×3.0)、至尊👑(×5.0) - 后台 VIP 等级 CRUD 管理(新增/编辑/删除,配置模板和倍率) - 后台用户编辑弹窗支持设置 VIP 等级和到期时间 - ChatController 心跳经验按 VIP 倍率加成 - FishingController 正向奖励按 VIP 倍率加成(负面惩罚不变) - 在线名单显示 VIP 图标和管理员🛡️标识 - VIP 用户进入/离开使用专属颜色和标题 - 后台侧栏新增「👑 VIP 会员等级」入口
245 lines
13 KiB
PHP
245 lines
13 KiB
PHP
{{--
|
||
文件功能:后台 VIP 会员等级管理页面
|
||
提供会员等级的新增、编辑、删除功能
|
||
后台可自由管理所有会员等级配置
|
||
|
||
@author ChatRoom Laravel
|
||
@version 1.0.0
|
||
--}}
|
||
|
||
@extends('admin.layouts.app')
|
||
|
||
@section('title', 'VIP 会员等级管理')
|
||
|
||
@section('content')
|
||
|
||
<div x-data="{
|
||
showForm: false,
|
||
editing: null,
|
||
form: {
|
||
name: '',
|
||
icon: '⭐',
|
||
color: '#f59e0b',
|
||
exp_multiplier: 1.5,
|
||
jjb_multiplier: 1.2,
|
||
sort_order: 0,
|
||
price: 10,
|
||
duration_days: 30,
|
||
join_templates: '',
|
||
leave_templates: '',
|
||
},
|
||
|
||
openCreate() {
|
||
this.editing = null;
|
||
this.form = {
|
||
name: '',
|
||
icon: '⭐',
|
||
color: '#f59e0b',
|
||
exp_multiplier: 1.5,
|
||
jjb_multiplier: 1.2,
|
||
sort_order: 0,
|
||
price: 10,
|
||
duration_days: 30,
|
||
join_templates: '',
|
||
leave_templates: '',
|
||
};
|
||
this.showForm = true;
|
||
},
|
||
|
||
openEdit(level) {
|
||
this.editing = level;
|
||
this.form = {
|
||
name: level.name,
|
||
icon: level.icon,
|
||
color: level.color,
|
||
exp_multiplier: level.exp_multiplier,
|
||
jjb_multiplier: level.jjb_multiplier,
|
||
sort_order: level.sort_order,
|
||
price: level.price,
|
||
duration_days: level.duration_days,
|
||
join_templates: level.join_templates_text,
|
||
leave_templates: level.leave_templates_text,
|
||
};
|
||
this.showForm = true;
|
||
}
|
||
}">
|
||
|
||
{{-- 头部操作栏 --}}
|
||
<div class="flex justify-between items-center mb-6">
|
||
<div>
|
||
<h2 class="text-lg font-bold text-gray-800">会员等级列表</h2>
|
||
<p class="text-sm text-gray-500">管理赞助会员等级,配置名称、图标、倍率和专属提示语</p>
|
||
</div>
|
||
<button @click="openCreate()"
|
||
class="bg-indigo-600 text-white px-5 py-2.5 rounded-lg font-bold hover:bg-indigo-700 transition shadow-sm">
|
||
+ 新增等级
|
||
</button>
|
||
</div>
|
||
|
||
{{-- 等级卡片列表 --}}
|
||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
|
||
@foreach ($levels as $level)
|
||
<div class="bg-white rounded-xl shadow-sm border overflow-hidden hover:shadow-md transition">
|
||
<div class="p-5">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center space-x-2">
|
||
<span class="text-2xl">{{ $level->icon }}</span>
|
||
<span class="font-bold text-lg"
|
||
style="color: {{ $level->color }}">{{ $level->name }}</span>
|
||
</div>
|
||
<span
|
||
class="text-xs bg-gray-100 px-2 py-0.5 rounded text-gray-500">排序:{{ $level->sort_order }}</span>
|
||
</div>
|
||
|
||
<div class="space-y-2 text-sm">
|
||
<div class="flex justify-between">
|
||
<span class="text-gray-500">经验倍率</span>
|
||
<span class="font-bold text-green-600">×{{ $level->exp_multiplier }}</span>
|
||
</div>
|
||
<div class="flex justify-between">
|
||
<span class="text-gray-500">金币倍率</span>
|
||
<span class="font-bold text-yellow-600">×{{ $level->jjb_multiplier }}</span>
|
||
</div>
|
||
<div class="flex justify-between">
|
||
<span class="text-gray-500">赞助金额</span>
|
||
<span class="font-bold text-gray-700">¥{{ $level->price }}</span>
|
||
</div>
|
||
<div class="flex justify-between">
|
||
<span class="text-gray-500">有效天数</span>
|
||
<span class="font-bold">{{ $level->duration_days ?: '永久' }}</span>
|
||
</div>
|
||
<div class="flex justify-between">
|
||
<span class="text-gray-500">当前会员</span>
|
||
<span class="font-bold text-indigo-600">{{ $level->users()->count() }} 人</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="border-t bg-gray-50 px-5 py-3 flex justify-end space-x-2">
|
||
<button
|
||
@click="openEdit({
|
||
id: {{ $level->id }},
|
||
name: '{{ addslashes($level->name) }}',
|
||
icon: '{{ $level->icon }}',
|
||
color: '{{ $level->color }}',
|
||
exp_multiplier: {{ $level->exp_multiplier }},
|
||
jjb_multiplier: {{ $level->jjb_multiplier }},
|
||
sort_order: {{ $level->sort_order }},
|
||
price: {{ $level->price }},
|
||
duration_days: {{ $level->duration_days }},
|
||
join_templates_text: `{{ str_replace('`', '', implode("\n", $level->join_templates_array)) }}`,
|
||
leave_templates_text: `{{ str_replace('`', '', implode("\n", $level->leave_templates_array)) }}`,
|
||
requestUrl: '{{ route('admin.vip.update', $level->id) }}'
|
||
})"
|
||
class="text-xs bg-indigo-50 text-indigo-600 font-bold px-3 py-1.5 rounded hover:bg-indigo-600 hover:text-white transition">
|
||
编辑
|
||
</button>
|
||
<form action="{{ route('admin.vip.destroy', $level->id) }}" method="POST"
|
||
onsubmit="return confirm('确定删除等级 [{{ $level->name }}] 吗?关联用户会变为普通用户。')">
|
||
@csrf @method('DELETE')
|
||
<button type="submit"
|
||
class="text-xs bg-red-50 text-red-600 font-bold px-3 py-1.5 rounded hover:bg-red-600 hover:text-white transition">
|
||
删除
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
|
||
@if ($levels->isEmpty())
|
||
<div class="text-center py-16 text-gray-400">
|
||
<p class="text-lg">暂无会员等级,点击右上角"新增等级"创建</p>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- 新增/编辑弹窗 --}}
|
||
<div x-show="showForm" style="display: none;"
|
||
class="fixed inset-0 z-50 bg-black/60 flex items-center justify-center p-4">
|
||
<div @click.away="showForm = false"
|
||
class="bg-white rounded-xl shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto" x-transition>
|
||
<div class="bg-indigo-900 px-6 py-4 flex justify-between items-center rounded-t-xl text-white">
|
||
<h3 class="font-bold text-lg" x-text="editing ? '编辑等级:' + editing.name : '新增会员等级'"></h3>
|
||
<button @click="showForm = false" class="text-gray-400 hover:text-white text-xl">×</button>
|
||
</div>
|
||
|
||
<div class="p-6">
|
||
<form :action="editing ? editing.requestUrl : '{{ route('admin.vip.store') }}'" method="POST">
|
||
@csrf
|
||
<template x-if="editing"><input type="hidden" name="_method" value="PUT"></template>
|
||
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">等级名称</label>
|
||
<input type="text" name="name" x-model="form.name" required maxlength="50"
|
||
class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">图标 (Emoji)</label>
|
||
<input type="text" name="icon" x-model="form.icon" required maxlength="20"
|
||
class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">颜色</label>
|
||
<div class="flex items-center space-x-2">
|
||
<input type="color" name="color" x-model="form.color"
|
||
class="w-10 h-8 border rounded cursor-pointer">
|
||
<input type="text" x-model="form.color" maxlength="10"
|
||
class="flex-1 border rounded-md p-2 text-sm font-mono">
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">排序 (越大越高级)</label>
|
||
<input type="number" name="sort_order" x-model="form.sort_order" required min="0"
|
||
class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">经验倍率</label>
|
||
<input type="number" name="exp_multiplier" x-model="form.exp_multiplier" required
|
||
min="1" step="0.1" class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">金币倍率</label>
|
||
<input type="number" name="jjb_multiplier" x-model="form.jjb_multiplier" required
|
||
min="1" step="0.1" class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">赞助金额 (元)</label>
|
||
<input type="number" name="price" x-model="form.price" required min="0"
|
||
class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">有效天数 (0=永久)</label>
|
||
<input type="number" name="duration_days" x-model="form.duration_days" required
|
||
min="0" class="w-full border rounded-md p-2 text-sm">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 专属模板 --}}
|
||
<div class="mt-4">
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">进入欢迎语模板
|
||
<span class="font-normal text-gray-400">(每行一条,用 {username} 代替用户名)</span></label>
|
||
<textarea name="join_templates" x-model="form.join_templates" rows="3" placeholder="例:贵宾{username}驾到!全场起立!"
|
||
class="w-full border rounded-md p-2 text-sm"></textarea>
|
||
</div>
|
||
<div class="mt-3">
|
||
<label class="block text-xs font-bold text-gray-600 mb-1">离开提示语模板
|
||
<span class="font-normal text-gray-400">(每行一条)</span></label>
|
||
<textarea name="leave_templates" x-model="form.leave_templates" rows="3" placeholder="例:贵宾{username}潇洒离去..."
|
||
class="w-full border rounded-md p-2 text-sm"></textarea>
|
||
</div>
|
||
|
||
<div class="flex justify-end space-x-3 pt-4 mt-4 border-t">
|
||
<button type="button" @click="showForm = false"
|
||
class="px-4 py-2 border rounded font-medium text-gray-600 hover:bg-gray-50">取消</button>
|
||
<button type="submit"
|
||
class="px-4 py-2 bg-indigo-600 text-white rounded font-bold hover:bg-indigo-700 shadow-sm"
|
||
x-text="editing ? '保存修改' : '创建等级'"></button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endsection
|