Feat: 商店功能完整实现(单次特效卡888/周卡8888/改名卡5000,含购买、周卡覆盖、改名黑名单)
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:创建商店商品表(shop_items)
|
||||
* 存储商店内所有可购买的商品定义
|
||||
*
|
||||
* @package Database\Migrations
|
||||
*/
|
||||
|
||||
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('shop_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 50)->comment('商品名称');
|
||||
$table->string('slug', 50)->unique()->comment('商品唯一标识');
|
||||
$table->string('description', 255)->nullable()->comment('商品描述');
|
||||
$table->string('icon', 20)->default('🛍')->comment('商品图标 emoji');
|
||||
$table->unsignedInteger('price')->comment('价格(金币)');
|
||||
// type: instant=单次立即执行, duration=有时效, one_time=一次性道具
|
||||
$table->enum('type', ['instant', 'duration', 'one_time'])->comment('商品类型');
|
||||
$table->unsignedTinyInteger('duration_days')->nullable()->comment('有效天数(duration 类型用)');
|
||||
$table->unsignedTinyInteger('sort_order')->default(0)->comment('排序');
|
||||
$table->boolean('is_active')->default(true)->comment('是否上架');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 回滚迁移:删除商品表
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('shop_items');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:创建用户购买记录表(user_purchases)
|
||||
* 记录每个用户购买商店商品的流水与状态
|
||||
*
|
||||
* @package Database\Migrations
|
||||
*/
|
||||
|
||||
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('user_purchases', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id')->comment('购买用户 ID');
|
||||
$table->unsignedBigInteger('shop_item_id')->comment('商品 ID');
|
||||
// status:
|
||||
// active = 有效中(周卡 / 改名卡未使用)
|
||||
// expired = 已过期(周卡到期)
|
||||
// used = 已使用(单次卡已播 / 改名卡已用)
|
||||
// cancelled = 被新购买的周卡覆盖作废(金币不退)
|
||||
$table->enum('status', ['active', 'expired', 'used', 'cancelled'])->default('active');
|
||||
$table->unsignedInteger('price_paid')->comment('购买时实际扣除金币');
|
||||
$table->timestamp('expires_at')->nullable()->comment('到期时间(duration 类型使用)');
|
||||
$table->timestamp('used_at')->nullable()->comment('使用时间(one_time/instant 使用)');
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->foreign('shop_item_id')->references('id')->on('shop_items')->onDelete('cascade');
|
||||
$table->index(['user_id', 'status']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 回滚迁移:删除购买记录表
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_purchases');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:创建用户名黑名单表(username_blacklist)
|
||||
* 用户使用改名卡后,旧名称写入此表保留30天,防止他人立即抢注
|
||||
*
|
||||
* @package Database\Migrations
|
||||
*/
|
||||
|
||||
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('username_blacklist', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('username', 20)->unique()->comment('被保留的旧用户名');
|
||||
$table->timestamp('reserved_until')->comment('保留到期时间(默认30天)');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 回滚迁移:删除黑名单表
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('username_blacklist');
|
||||
}
|
||||
};
|
||||
61
database/seeders/ShopItemSeeder.php
Normal file
61
database/seeders/ShopItemSeeder.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:商店初始商品数据填充器
|
||||
* 初始化9种商品:4种单次特效卡 + 4种周卡 + 改名卡
|
||||
*
|
||||
* @package Database\Seeders
|
||||
*/
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ShopItem;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ShopItemSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* 填充商店商品初始数据
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$items = [
|
||||
// ── 单次特效卡(立即播放一次,888金币)────────────────
|
||||
['name' => '烟花单次卡', 'slug' => 'once_fireworks', 'icon' => '🎆',
|
||||
'description' => '购买即刻在聊天室绽放一场烟花(仅自己可见),喜庆氛围拉满!',
|
||||
'price' => 888, 'type' => 'instant', 'duration_days' => null, 'sort_order' => 1],
|
||||
['name' => '下雨单次卡', 'slug' => 'once_rain', 'icon' => '🌧',
|
||||
'description' => '立刻召唤一场滂沱大雨,感受诗意雨天(仅自己可见)。',
|
||||
'price' => 888, 'type' => 'instant', 'duration_days' => null, 'sort_order' => 2],
|
||||
['name' => '雷电单次卡', 'slug' => 'once_lightning', 'icon' => '⚡',
|
||||
'description' => '电闪雷鸣,瞬间震撼全场!立即触发雷电特效(仅自己可见)。',
|
||||
'price' => 888, 'type' => 'instant', 'duration_days' => null, 'sort_order' => 3],
|
||||
['name' => '下雪单次卡', 'slug' => 'once_snow', 'icon' => '❄️',
|
||||
'description' => '银装素裹,漫天飞雪!立即触发下雪特效(仅自己可见)。',
|
||||
'price' => 888, 'type' => 'instant', 'duration_days' => null, 'sort_order' => 4],
|
||||
|
||||
// ── 周卡(登录自动播放7天,8888金币)──────────────────
|
||||
['name' => '烟花周卡', 'slug' => 'week_fireworks', 'icon' => '🎆',
|
||||
'description' => '连续7天,每次进入聊天室自动绽放烟花!同时只能激活一种周卡。',
|
||||
'price' => 8888, 'type' => 'duration', 'duration_days' => 7, 'sort_order' => 11],
|
||||
['name' => '下雨周卡', 'slug' => 'week_rain', 'icon' => '🌧',
|
||||
'description' => '连续7天,每次进入聊天室自动下雨。同时只能激活一种周卡。',
|
||||
'price' => 8888, 'type' => 'duration', 'duration_days' => 7, 'sort_order' => 12],
|
||||
['name' => '雷电周卡', 'slug' => 'week_lightning', 'icon' => '⚡',
|
||||
'description' => '连续7天,每次进入聊天室自动触发雷电特效。同时只能激活一种周卡。',
|
||||
'price' => 8888, 'type' => 'duration', 'duration_days' => 7, 'sort_order' => 13],
|
||||
['name' => '下雪周卡', 'slug' => 'week_snow', 'icon' => '❄️',
|
||||
'description' => '连续7天,每次进入聊天室自动下雪。同时只能激活一种周卡。',
|
||||
'price' => 8888, 'type' => 'duration', 'duration_days' => 7, 'sort_order' => 14],
|
||||
|
||||
// ── 改名卡(一次性,5000金币)────────────────────────
|
||||
['name' => '改名卡', 'slug' => 'rename_card', 'icon' => '🎭',
|
||||
'description' => '使用后可修改一次昵称(旧名保留30天黑名单,不可被他人注册)。注意:历史聊天记录中的旧名不会更改。',
|
||||
'price' => 5000, 'type' => 'one_time', 'duration_days' => null, 'sort_order' => 20],
|
||||
];
|
||||
|
||||
foreach ($items as $item) {
|
||||
ShopItem::firstOrCreate(['slug' => $item['slug']], $item + ['is_active' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user