新增节日福利系统:①数据库表+模型 ②TriggerHolidayEventJob队列任务(在线用户筛选/金额分配/WebSocket广播) ③后台管理页面(列表/创建/手动触发) ④前台领取弹窗+WebSocket监听 ⑤定时调度每分钟扫描 ⑥CurrencySource补充HOLIDAY_BONUS
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', '创建节日福利活动')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-3xl mx-auto space-y-6">
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<a href="{{ route('admin.holiday-events.index') }}" class="text-gray-400 hover:text-gray-600">← 返回列表</a>
|
||||
<h2 class="text-lg font-bold text-gray-800">🎊 创建节日福利活动</h2>
|
||||
</div>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
|
||||
<ul class="list-disc list-inside text-sm text-red-700 space-y-1">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.holiday-events.store') }}" method="POST" x-data="holidayForm()">
|
||||
@csrf
|
||||
|
||||
{{-- 基础信息 --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-3 pb-2 border-b">📋 基础信息</h3>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">活动名称 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="text" name="name" value="{{ old('name') }}" required placeholder="例:元旦快乐🎊"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm focus:border-amber-400 focus:ring-amber-400">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">活动描述 <span
|
||||
class="text-gray-400 font-normal">(可选,公屏广播时显示)</span></label>
|
||||
<textarea name="description" rows="2" placeholder="例:新年快乐!感谢大家一直以来的陪伴,送上新年礼物!"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm focus:border-amber-400 focus:ring-amber-400">{{ old('description') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 奖励配置 --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-3 pb-2 border-b">🪙 奖励配置</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">总金币奖池 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="number" name="total_amount" value="{{ old('total_amount', 100000) }}" required
|
||||
min="1" class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">可领取人数上限 <span
|
||||
class="text-gray-400 font-normal">(0=不限)</span></label>
|
||||
<input type="number" name="max_claimants" value="{{ old('max_claimants', 0) }}" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-xs font-bold text-gray-600 mb-2">分配方式 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<div class="flex gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="distribute_type" value="random" x-model="distributeType"
|
||||
{{ old('distribute_type', 'random') === 'random' ? 'checked' : '' }}>
|
||||
<span class="text-sm font-bold">🎲 随机分配</span>
|
||||
<span class="text-xs text-gray-400">(二倍均值算法,每人金额不同)</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="distribute_type" value="fixed" x-model="distributeType"
|
||||
{{ old('distribute_type') === 'fixed' ? 'checked' : '' }}>
|
||||
<span class="text-sm font-bold">📏 定额发放</span>
|
||||
<span class="text-xs text-gray-400">(每人相同金额)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 随机模式配置 --}}
|
||||
<div x-show="distributeType === 'random'" class="col-span-2">
|
||||
<div class="grid grid-cols-2 gap-4 bg-purple-50 rounded-lg p-4">
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">最低保底金额</label>
|
||||
<input type="number" name="min_amount" value="{{ old('min_amount', 100) }}"
|
||||
min="1" class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">单人最高上限 <span
|
||||
class="text-gray-400 font-normal">(可选)</span></label>
|
||||
<input type="number" name="max_amount" value="{{ old('max_amount') }}" min="1"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm"
|
||||
placeholder="不填则自动计算">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 定额模式配置 --}}
|
||||
<div x-show="distributeType === 'fixed'" class="col-span-2">
|
||||
<div class="bg-blue-50 rounded-lg p-4">
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">每人固定金额 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="number" name="fixed_amount" value="{{ old('fixed_amount', 500) }}"
|
||||
min="1" class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
<p class="text-xs text-gray-400 mt-1">💡 总发放 = 固定金额 × 在线人数(受最大领取人数限制)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 时间配置 --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-3 pb-2 border-b">⏰ 时间配置</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">触发时间 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="datetime-local" name="send_at" value="{{ old('send_at') }}" required
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">领取有效期(分钟)</label>
|
||||
<input type="number" name="expire_minutes" value="{{ old('expire_minutes', 30) }}"
|
||||
min="1" max="1440"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">重复方式</label>
|
||||
<select name="repeat_type" class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
<option value="once" {{ old('repeat_type', 'once') === 'once' ? 'selected' : '' }}>仅一次
|
||||
</option>
|
||||
<option value="daily" {{ old('repeat_type') === 'daily' ? 'selected' : '' }}>每天(相同时间)
|
||||
</option>
|
||||
<option value="weekly" {{ old('repeat_type') === 'weekly' ? 'selected' : '' }}>每周(相同时间)
|
||||
</option>
|
||||
<option value="monthly" {{ old('repeat_type') === 'monthly' ? 'selected' : '' }}>
|
||||
每月(相同日期时间)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 目标用户 --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-3 pb-2 border-b">🎯 目标用户</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">用户范围</label>
|
||||
<select name="target_type" x-model="targetType"
|
||||
class="w-full border border-gray-300 rounded-lg p-2.5 text-sm">
|
||||
<option value="all">全部在线用户</option>
|
||||
<option value="vip">仅 VIP 用户</option>
|
||||
<option value="level">指定等级以上</option>
|
||||
</select>
|
||||
</div>
|
||||
<div x-show="targetType === 'level'">
|
||||
<label class="block text-xs font-bold text-gray-600 mb-1">最低用户等级</label>
|
||||
<input type="number" name="target_value" value="{{ old('target_value', 1) }}"
|
||||
min="1" class="w-full border border-gray-300 rounded-lg p-2.5 text-sm"
|
||||
placeholder="例:10">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 提交 --}}
|
||||
<div class="flex gap-3 pt-4 border-t">
|
||||
<button type="submit"
|
||||
class="px-8 py-2.5 bg-amber-500 text-white rounded-lg font-bold hover:bg-amber-600 transition shadow-sm">
|
||||
🎊 创建活动
|
||||
</button>
|
||||
<a href="{{ route('admin.holiday-events.index') }}"
|
||||
class="px-6 py-2.5 bg-gray-100 text-gray-600 rounded-lg font-bold hover:bg-gray-200 transition">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 节日福利创建表单 Alpine 组件
|
||||
*/
|
||||
function holidayForm() {
|
||||
return {
|
||||
distributeType: '{{ old('distribute_type', 'random') }}',
|
||||
targetType: '{{ old('target_type', 'all') }}',
|
||||
};
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user