From 3f0bdda4e1c02febc85487ea49dd01065e0ced9a Mon Sep 17 00:00:00 2001 From: kang Date: Fri, 8 May 2026 11:12:09 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=BF=81=E7=A7=BB=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 29 ++++++++++-- ...6_05_08_100000_create_currencies_table.php | 26 +++++++++++ ...2026_05_08_100001_create_players_table.php | 31 +++++++++++++ ..._05_08_100002_create_admin_users_table.php | 28 ++++++++++++ ...ate_admin_roles_and_permissions_tables.php | 45 +++++++++++++++++++ ..._08_100004_create_player_wallets_table.php | 30 +++++++++++++ ..._05_08_100005_create_wallet_txns_table.php | 38 ++++++++++++++++ ...08_100006_create_transfer_orders_table.php | 35 +++++++++++++++ .../2026_05_08_100007_create_draws_table.php | 35 +++++++++++++++ ...00008_create_draw_result_batches_table.php | 32 +++++++++++++ ..._100009_create_draw_result_items_table.php | 33 ++++++++++++++ 11 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 database/migrations/2026_05_08_100000_create_currencies_table.php create mode 100644 database/migrations/2026_05_08_100001_create_players_table.php create mode 100644 database/migrations/2026_05_08_100002_create_admin_users_table.php create mode 100644 database/migrations/2026_05_08_100003_create_admin_roles_and_permissions_tables.php create mode 100644 database/migrations/2026_05_08_100004_create_player_wallets_table.php create mode 100644 database/migrations/2026_05_08_100005_create_wallet_txns_table.php create mode 100644 database/migrations/2026_05_08_100006_create_transfer_orders_table.php create mode 100644 database/migrations/2026_05_08_100007_create_draws_table.php create mode 100644 database/migrations/2026_05_08_100008_create_draw_result_batches_table.php create mode 100644 database/migrations/2026_05_08_100009_create_draw_result_items_table.php diff --git a/.env.example b/.env.example index aa9793b..26664e0 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_NAME=Laravel +APP_NAME=Llottery APP_ENV=local APP_KEY= APP_DEBUG=true @@ -24,8 +24,8 @@ DB_CONNECTION=pgsql DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=llotterlaravel -DB_USERNAME=root -DB_PASSWORD= +DB_USERNAME=kang +DB_PASSWORD=123456 SESSION_DRIVER=database SESSION_LIFETIME=120 @@ -35,8 +35,10 @@ SESSION_DOMAIN=null BROADCAST_CONNECTION=log FILESYSTEM_DISK=local +# 本地可用 database;上线建议 redis(与产品文档:赔付池 Lua / 队列) QUEUE_CONNECTION=database +# 本地可用 database;实现赔付池与热点缓存后改为 redis CACHE_STORE=database # CACHE_PREFIX= @@ -63,3 +65,24 @@ AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" + +# --------------------------------------------------------------------------- +# 彩票业务(按对接填写;勿把真实密钥提交到 Git,只在本地 .env 写) +# --------------------------------------------------------------------------- + +# 默认结算币种(PRD:NPR) +LOTTERY_DEFAULT_CURRENCY=NPR + +# 主站 SSO / 钱包(名称可按实际接口调整) +# MAIN_SITE_BASE_URL= +# MAIN_SITE_SSO_JWT_SECRET= +# MAIN_SITE_WALLET_API_URL= +# MAIN_SITE_WALLET_API_KEY= +# MAIN_SITE_WALLET_TIMEOUT=10 + +# Sanctum:H5 / Next 管理端与 API 不同端口时需配置可识别的前端域名 +# SANCTUM_STATEFUL_DOMAINS=localhost,localhost:3000,127.0.0.1 + +# Redis 库划分(可选,与 CACHE / SESSION 分开时用) +# REDIS_DB=0 +# REDIS_CACHE_DB=1 diff --git a/database/migrations/2026_05_08_100000_create_currencies_table.php b/database/migrations/2026_05_08_100000_create_currencies_table.php new file mode 100644 index 0000000..7a3662d --- /dev/null +++ b/database/migrations/2026_05_08_100000_create_currencies_table.php @@ -0,0 +1,26 @@ +id(); + $table->string('code', 16)->unique(); + $table->string('name', 64); + $table->unsignedTinyInteger('decimal_places')->default(2); + $table->boolean('is_enabled')->default(true); + $table->boolean('is_bettable')->default(false); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('currencies'); + } +}; diff --git a/database/migrations/2026_05_08_100001_create_players_table.php b/database/migrations/2026_05_08_100001_create_players_table.php new file mode 100644 index 0000000..ecf432b --- /dev/null +++ b/database/migrations/2026_05_08_100001_create_players_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('site_code', 64); + $table->string('site_player_id', 128); + $table->string('username', 128)->nullable(); + $table->string('nickname', 128)->nullable(); + $table->string('default_currency', 16)->default('NPR'); + $table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=frozen,2=blocked'); + $table->timestamp('last_login_at')->nullable(); + $table->timestamps(); + + $table->unique(['site_code', 'site_player_id'], 'uk_players_site_player'); + $table->index('status', 'idx_players_status'); + }); + } + + public function down(): void + { + Schema::dropIfExists('players'); + } +}; diff --git a/database/migrations/2026_05_08_100002_create_admin_users_table.php b/database/migrations/2026_05_08_100002_create_admin_users_table.php new file mode 100644 index 0000000..e2d5298 --- /dev/null +++ b/database/migrations/2026_05_08_100002_create_admin_users_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name', 128); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=disabled'); + $table->timestamp('last_login_at')->nullable(); + $table->rememberToken(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('admin_users'); + } +}; diff --git a/database/migrations/2026_05_08_100003_create_admin_roles_and_permissions_tables.php b/database/migrations/2026_05_08_100003_create_admin_roles_and_permissions_tables.php new file mode 100644 index 0000000..da15840 --- /dev/null +++ b/database/migrations/2026_05_08_100003_create_admin_roles_and_permissions_tables.php @@ -0,0 +1,45 @@ +id(); + $table->string('slug', 64)->unique(); + $table->string('name', 128); + $table->timestamps(); + }); + + Schema::create('admin_permissions', function (Blueprint $table) { + $table->id(); + $table->string('slug', 128)->unique(); + $table->string('name', 128); + $table->timestamps(); + }); + + Schema::create('admin_role_permissions', function (Blueprint $table) { + $table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete(); + $table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete(); + $table->primary(['role_id', 'permission_id']); + }); + + Schema::create('admin_user_roles', function (Blueprint $table) { + $table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete(); + $table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete(); + $table->primary(['admin_user_id', 'role_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('admin_user_roles'); + Schema::dropIfExists('admin_role_permissions'); + Schema::dropIfExists('admin_permissions'); + Schema::dropIfExists('admin_roles'); + } +}; diff --git a/database/migrations/2026_05_08_100004_create_player_wallets_table.php b/database/migrations/2026_05_08_100004_create_player_wallets_table.php new file mode 100644 index 0000000..73a0d85 --- /dev/null +++ b/database/migrations/2026_05_08_100004_create_player_wallets_table.php @@ -0,0 +1,30 @@ +id(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->string('wallet_type', 32)->default('lottery'); + $table->string('currency_code', 16); + $table->bigInteger('balance')->default(0); + $table->bigInteger('frozen_balance')->default(0); + $table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=frozen'); + $table->unsignedBigInteger('version')->default(0); + $table->timestamps(); + + $table->unique(['player_id', 'wallet_type', 'currency_code'], 'uk_player_wallets_player_type_currency'); + }); + } + + public function down(): void + { + Schema::dropIfExists('player_wallets'); + } +}; diff --git a/database/migrations/2026_05_08_100005_create_wallet_txns_table.php b/database/migrations/2026_05_08_100005_create_wallet_txns_table.php new file mode 100644 index 0000000..8a52c26 --- /dev/null +++ b/database/migrations/2026_05_08_100005_create_wallet_txns_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('txn_no', 64)->unique(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->foreignId('wallet_id')->constrained('player_wallets')->cascadeOnDelete(); + $table->string('biz_type', 32); + $table->string('biz_no', 64)->nullable(); + $table->unsignedTinyInteger('direction')->comment('1=in,2=out'); + $table->bigInteger('amount'); + $table->bigInteger('balance_before'); + $table->bigInteger('balance_after'); + $table->string('status', 32); + $table->string('external_ref_no', 64)->nullable(); + $table->string('idempotent_key', 64)->nullable(); + $table->string('remark', 255)->nullable(); + $table->timestamps(); + + $table->index(['player_id', 'created_at'], 'idx_wallet_txns_player_time'); + $table->index(['biz_type', 'biz_no'], 'idx_wallet_txns_biz'); + $table->unique(['idempotent_key', 'biz_type'], 'uk_wallet_txns_idempotent_biz'); + }); + } + + public function down(): void + { + Schema::dropIfExists('wallet_txns'); + } +}; diff --git a/database/migrations/2026_05_08_100006_create_transfer_orders_table.php b/database/migrations/2026_05_08_100006_create_transfer_orders_table.php new file mode 100644 index 0000000..59146e0 --- /dev/null +++ b/database/migrations/2026_05_08_100006_create_transfer_orders_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('transfer_no', 64)->unique(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->string('direction', 16); + $table->string('currency_code', 16); + $table->bigInteger('amount'); + $table->string('idempotent_key', 64)->unique(); + $table->string('status', 32); + $table->json('external_request_payload')->nullable(); + $table->json('external_response_payload')->nullable(); + $table->string('external_ref_no', 64)->nullable(); + $table->string('fail_reason', 255)->nullable(); + $table->timestamp('finished_at')->nullable(); + $table->timestamps(); + + $table->index(['player_id', 'created_at']); + }); + } + + public function down(): void + { + Schema::dropIfExists('transfer_orders'); + } +}; diff --git a/database/migrations/2026_05_08_100007_create_draws_table.php b/database/migrations/2026_05_08_100007_create_draws_table.php new file mode 100644 index 0000000..715cda6 --- /dev/null +++ b/database/migrations/2026_05_08_100007_create_draws_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('draw_no', 32)->unique(); + $table->date('business_date'); + $table->unsignedInteger('sequence_no'); + $table->string('status', 32); + $table->timestamp('start_time')->nullable(); + $table->timestamp('close_time')->nullable(); + $table->timestamp('draw_time')->nullable(); + $table->timestamp('cooling_end_time')->nullable(); + $table->string('result_source', 16)->nullable()->comment('rng|manual'); + $table->unsignedInteger('current_result_version')->default(0); + $table->unsignedInteger('settle_version')->default(0); + $table->boolean('is_reopened')->default(false); + $table->timestamps(); + + $table->index(['status', 'draw_time'], 'idx_draws_status_draw_time'); + }); + } + + public function down(): void + { + Schema::dropIfExists('draws'); + } +}; diff --git a/database/migrations/2026_05_08_100008_create_draw_result_batches_table.php b/database/migrations/2026_05_08_100008_create_draw_result_batches_table.php new file mode 100644 index 0000000..bc05712 --- /dev/null +++ b/database/migrations/2026_05_08_100008_create_draw_result_batches_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->unsignedInteger('result_version'); + $table->string('source_type', 16)->comment('rng|manual'); + $table->string('rng_seed_hash', 128)->nullable(); + $table->text('raw_seed_encrypted')->nullable(); + $table->string('status', 32); + $table->foreignId('created_by')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->foreignId('confirmed_by')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->timestamp('confirmed_at')->nullable(); + $table->timestamps(); + + $table->unique(['draw_id', 'result_version'], 'uk_draw_result_batches_draw_version'); + }); + } + + public function down(): void + { + Schema::dropIfExists('draw_result_batches'); + } +}; diff --git a/database/migrations/2026_05_08_100009_create_draw_result_items_table.php b/database/migrations/2026_05_08_100009_create_draw_result_items_table.php new file mode 100644 index 0000000..4bd3072 --- /dev/null +++ b/database/migrations/2026_05_08_100009_create_draw_result_items_table.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->foreignId('result_batch_id')->constrained('draw_result_batches')->cascadeOnDelete(); + $table->string('prize_type', 32); + $table->unsignedInteger('prize_index')->default(0); + $table->char('number_4d', 4); + $table->char('suffix_3d', 3)->nullable(); + $table->char('suffix_2d', 2)->nullable(); + $table->unsignedTinyInteger('head_digit')->nullable(); + $table->unsignedTinyInteger('tail_digit')->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->index(['draw_id', 'prize_type', 'prize_index'], 'idx_draw_result_items_draw_prize'); + $table->index(['draw_id', 'number_4d'], 'idx_draw_result_items_draw_number'); + }); + } + + public function down(): void + { + Schema::dropIfExists('draw_result_items'); + } +};