Files
2026-04-12 16:16:23 +08:00

322 lines
18 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{--
文件功能:后台 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: '',
join_effect: 'none',
leave_effect: 'none',
join_banner_style: 'aurora',
leave_banner_style: 'farewell',
allow_custom_messages: true,
},
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: '',
join_effect: 'none',
leave_effect: 'none',
join_banner_style: 'aurora',
leave_banner_style: 'farewell',
allow_custom_messages: true,
};
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,
join_effect: level.join_effect,
leave_effect: level.leave_effect,
join_banner_style: level.join_banner_style,
leave_banner_style: level.leave_banner_style,
allow_custom_messages: level.allow_custom_messages,
};
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 class="flex justify-between">
<span class="text-gray-500">进场特效</span>
<span class="font-bold text-sky-600">{{ $effectOptions[$level->joinEffectKey()] ?? '无特效' }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">离场特效</span>
<span class="font-bold text-violet-600">{{ $effectOptions[$level->leaveEffectKey()] ?? '无特效' }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">允许自定义</span>
<span class="font-bold {{ $level->allow_custom_messages ? 'text-emerald-600' : 'text-gray-400' }}">{{ $level->allow_custom_messages ? '允许' : '关闭' }}</span>
</div>
</div>
</div>
<div class="border-t bg-gray-50 px-5 py-3 flex justify-end space-x-2">
<a href="{{ route('admin.vip.members', $level->id) }}"
class="text-xs bg-emerald-50 text-emerald-600 font-bold px-3 py-1.5 rounded hover:bg-emerald-600 hover:text-white transition">
查看会员
</a>
<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_effect: '{{ $level->joinEffectKey() }}',
leave_effect: '{{ $level->leaveEffectKey() }}',
join_banner_style: '{{ $level->joinBannerStyleKey() }}',
leave_banner_style: '{{ $level->leaveBannerStyleKey() }}',
allow_custom_messages: {{ $level->allow_custom_messages ? 'true' : 'false' }},
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">&times;</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="mt-4 grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">入场特效</label>
<select name="join_effect" x-model="form.join_effect" class="w-full border rounded-md p-2 text-sm">
@foreach ($effectOptions as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">离场特效</label>
<select name="leave_effect" x-model="form.leave_effect" class="w-full border rounded-md p-2 text-sm">
@foreach ($effectOptions as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">入场横幅风格</label>
<select name="join_banner_style" x-model="form.join_banner_style" class="w-full border rounded-md p-2 text-sm">
@foreach ($bannerStyleOptions as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">离场横幅风格</label>
<select name="leave_banner_style" x-model="form.leave_banner_style" class="w-full border rounded-md p-2 text-sm">
@foreach ($bannerStyleOptions as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</div>
</div>
<label class="mt-4 flex items-center gap-3 rounded-xl border border-amber-100 bg-amber-50 px-4 py-3 text-sm text-amber-900">
<input type="checkbox" name="allow_custom_messages" value="1" x-model="form.allow_custom_messages"
class="rounded border-amber-300 text-amber-600 focus:ring-amber-400">
允许该会员等级用户在会员中心自定义欢迎语和离开语
</label>
<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