功能:站长礼包系统(金币/经验双类型)+ 后台用户编辑权限收紧(仅 id=1 超管)

新增功能:
- 礼包系统:superlevel 站长可发 888 数量 10 份礼包,支持金币/经验双类型
- 发包前三按钮选择(金币礼包 / 经验礼包 / 取消),使用 chatBanner 弹窗
- 聊天室系统公告含「立即抢包」按钮,金币红色/经验紫色配色区分
- WebSocket 实时推送红包弹窗卡片至所有在线用户
- Redis LPOP 原子分发 + 数据库 unique 约束防重领,并发安全
- 弹窗打开自动拉取服务端最新状态(剩余数量/已领/过期实时刷新)
- 新增 GET /red-packet/{id}/status 状态查询接口
- 新增 CurrencySource::RED_PACKET_RECV / RED_PACKET_RECV_EXP 枚举
安全加固:
- 后台用户编辑/强杀按钮仅 id=1 超管可见(前端隐藏 + 后端 403 双重拦截)
This commit is contained in:
2026-03-01 22:20:54 +08:00
parent ed195bb5f4
commit 6fa42b90d5
13 changed files with 1414 additions and 27 deletions

View File

@@ -0,0 +1,66 @@
<?php
/**
* 文件功能:创建聊天室礼包(红包)相关数据表
*
* red_packet_envelopes红包主表superlevel 用户发出的 888 金币红包)
* red_packet_claims红包领取记录先到先得每人只能领一次
*
* @author ChatRoom Laravel
* @version 1.0.0
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* 创建红包主表与领取记录表。
*/
public function up(): void
{
// 红包主表
Schema::create('red_packet_envelopes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('sender_id')->comment('发包用户 ID');
$table->string('sender_username', 20)->comment('发包用户名(快照)');
$table->unsignedInteger('room_id')->comment('发出所在房间 ID');
$table->unsignedInteger('total_amount')->comment('红包总金额(金币)');
$table->unsignedInteger('total_count')->comment('红包总份数');
$table->unsignedInteger('claimed_count')->default(0)->comment('已被领取份数');
$table->unsignedInteger('claimed_amount')->default(0)->comment('已被领取总金额');
$table->string('status', 10)->default('active')->comment('状态active / completed / expired');
$table->timestamp('expires_at')->comment('过期时间(超时未领完则关闭)');
$table->timestamps();
$table->index(['room_id', 'status']);
$table->index('sender_id');
});
// 领取记录表
Schema::create('red_packet_claims', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('envelope_id')->comment('关联红包 ID');
$table->unsignedBigInteger('user_id')->comment('领取用户 ID');
$table->string('username', 20)->comment('领取用户名(快照)');
$table->unsignedInteger('amount')->comment('本次领取金额');
$table->timestamp('claimed_at')->useCurrent()->comment('领取时间');
// 每人每个红包只能领一次
$table->unique(['envelope_id', 'user_id']);
$table->index('envelope_id');
$table->foreign('envelope_id')->references('id')->on('red_packet_envelopes')->cascadeOnDelete();
});
}
/**
* 回滚:删除红包相关表。
*/
public function down(): void
{
Schema::dropIfExists('red_packet_claims');
Schema::dropIfExists('red_packet_envelopes');
}
};

View File

@@ -0,0 +1,39 @@
<?php
/**
* 文件功能:为礼包红包主表新增货币类型字段
*
* type 字段区分本次红包发放的是金币gold还是经验exp
* 默认 gold兼容已有记录。
*
* @author ChatRoom Laravel
* @version 1.0.0
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* 新增 type 字段到 red_packet_envelopes 表。
*/
public function up(): void
{
Schema::table('red_packet_envelopes', function (Blueprint $table) {
// 货币类型gold = 金币exp = 经验值
$table->string('type', 10)->default('gold')->after('room_id')->comment('货币类型gold / exp');
});
}
/**
* 回滚:删除 type 字段。
*/
public function down(): void
{
Schema::table('red_packet_envelopes', function (Blueprint $table) {
$table->dropColumn('type');
});
}
};