From 2d79e38de3f1ef7783ca131ecee92553c4a540fe Mon Sep 17 00:00:00 2001 From: kang Date: Fri, 8 May 2026 11:58:05 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E6=96=87=E4=BB=B6=E5=92=8C=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E4=BB=A3=E7=A0=81=E5=8F=AF=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...6_05_08_130000_create_play_types_table.php | 32 +++++++ ..._play_config_versions_and_items_tables.php | 44 ++++++++++ ..._create_odds_versions_and_items_tables.php | 46 ++++++++++ ...ate_risk_cap_versions_and_items_tables.php | 39 ++++++++ ...5_08_130004_create_ticket_orders_table.php | 34 +++++++ ...05_08_130005_create_ticket_items_table.php | 51 +++++++++++ ...30006_create_ticket_combinations_table.php | 29 ++++++ ...create_risk_pools_and_lock_logs_tables.php | 45 ++++++++++ ...8_create_settlement_and_jackpot_tables.php | 88 +++++++++++++++++++ ...9_create_report_audit_reconcile_tables.php | 87 ++++++++++++++++++ 10 files changed, 495 insertions(+) create mode 100644 database/migrations/2026_05_08_130000_create_play_types_table.php create mode 100644 database/migrations/2026_05_08_130001_create_play_config_versions_and_items_tables.php create mode 100644 database/migrations/2026_05_08_130002_create_odds_versions_and_items_tables.php create mode 100644 database/migrations/2026_05_08_130003_create_risk_cap_versions_and_items_tables.php create mode 100644 database/migrations/2026_05_08_130004_create_ticket_orders_table.php create mode 100644 database/migrations/2026_05_08_130005_create_ticket_items_table.php create mode 100644 database/migrations/2026_05_08_130006_create_ticket_combinations_table.php create mode 100644 database/migrations/2026_05_08_130007_create_risk_pools_and_lock_logs_tables.php create mode 100644 database/migrations/2026_05_08_130008_create_settlement_and_jackpot_tables.php create mode 100644 database/migrations/2026_05_08_130009_create_report_audit_reconcile_tables.php diff --git a/database/migrations/2026_05_08_130000_create_play_types_table.php b/database/migrations/2026_05_08_130000_create_play_types_table.php new file mode 100644 index 0000000..9b83f79 --- /dev/null +++ b/database/migrations/2026_05_08_130000_create_play_types_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('play_code', 32)->unique(); + $table->string('category', 16); + $table->unsignedTinyInteger('dimension')->nullable()->comment('2/3/4'); + $table->string('bet_mode', 32)->nullable(); + $table->string('display_name_zh', 64)->nullable(); + $table->string('display_name_en', 64)->nullable(); + $table->string('display_name_ne', 64)->nullable(); + $table->boolean('is_enabled')->default(true); + $table->integer('sort_order')->default(0); + $table->boolean('supports_multi_number')->default(false); + $table->json('reserved_rule_json')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('play_types'); + } +}; diff --git a/database/migrations/2026_05_08_130001_create_play_config_versions_and_items_tables.php b/database/migrations/2026_05_08_130001_create_play_config_versions_and_items_tables.php new file mode 100644 index 0000000..1f0d503 --- /dev/null +++ b/database/migrations/2026_05_08_130001_create_play_config_versions_and_items_tables.php @@ -0,0 +1,44 @@ +id(); + $table->unsignedInteger('version_no'); + $table->string('status', 16); + $table->timestamp('effective_at')->nullable(); + $table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->string('reason', 255)->nullable(); + $table->timestamps(); + }); + + Schema::create('play_config_items', function (Blueprint $table) { + $table->id(); + $table->foreignId('version_id')->constrained('play_config_versions')->cascadeOnDelete(); + $table->string('play_code', 32); + $table->boolean('is_enabled')->default(true); + $table->bigInteger('min_bet_amount')->default(0); + $table->bigInteger('max_bet_amount')->default(0); + $table->integer('display_order')->default(0); + $table->text('rule_text_zh')->nullable(); + $table->text('rule_text_en')->nullable(); + $table->text('rule_text_ne')->nullable(); + $table->json('extra_config_json')->nullable(); + $table->timestamps(); + + $table->unique(['version_id', 'play_code'], 'uk_play_config_items_version_play'); + }); + } + + public function down(): void + { + Schema::dropIfExists('play_config_items'); + Schema::dropIfExists('play_config_versions'); + } +}; diff --git a/database/migrations/2026_05_08_130002_create_odds_versions_and_items_tables.php b/database/migrations/2026_05_08_130002_create_odds_versions_and_items_tables.php new file mode 100644 index 0000000..d01696e --- /dev/null +++ b/database/migrations/2026_05_08_130002_create_odds_versions_and_items_tables.php @@ -0,0 +1,46 @@ +id(); + $table->unsignedInteger('version_no'); + $table->string('status', 16); + $table->timestamp('effective_at')->nullable(); + $table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->string('reason', 255)->nullable(); + $table->timestamps(); + }); + + Schema::create('odds_items', function (Blueprint $table) { + $table->id(); + $table->foreignId('version_id')->constrained('odds_versions')->cascadeOnDelete(); + $table->string('play_code', 32); + $table->string('prize_scope', 32); + $table->bigInteger('odds_value')->default(0); + $table->decimal('rebate_rate', 8, 4)->default(0); + $table->decimal('commission_rate', 8, 4)->default(0); + $table->string('currency_code', 16); + $table->json('extra_config_json')->nullable(); + $table->timestamps(); + + $table->index(['version_id', 'play_code'], 'idx_odds_items_version_play'); + $table->unique( + ['version_id', 'play_code', 'prize_scope', 'currency_code'], + 'uk_odds_items_version_play_prize_currency' + ); + }); + } + + public function down(): void + { + Schema::dropIfExists('odds_items'); + Schema::dropIfExists('odds_versions'); + } +}; diff --git a/database/migrations/2026_05_08_130003_create_risk_cap_versions_and_items_tables.php b/database/migrations/2026_05_08_130003_create_risk_cap_versions_and_items_tables.php new file mode 100644 index 0000000..07c7b91 --- /dev/null +++ b/database/migrations/2026_05_08_130003_create_risk_cap_versions_and_items_tables.php @@ -0,0 +1,39 @@ +id(); + $table->unsignedInteger('version_no'); + $table->string('status', 16); + $table->timestamp('effective_at')->nullable(); + $table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->string('reason', 255)->nullable(); + $table->timestamps(); + }); + + Schema::create('risk_cap_items', function (Blueprint $table) { + $table->id(); + $table->foreignId('version_id')->constrained('risk_cap_versions')->cascadeOnDelete(); + $table->foreignId('draw_id')->nullable()->constrained('draws')->nullOnDelete(); + $table->char('normalized_number', 4); + $table->bigInteger('cap_amount'); + $table->string('cap_type', 16); + $table->timestamps(); + + $table->index(['version_id', 'draw_id', 'normalized_number'], 'idx_risk_cap_items_lookup'); + }); + } + + public function down(): void + { + Schema::dropIfExists('risk_cap_items'); + Schema::dropIfExists('risk_cap_versions'); + } +}; diff --git a/database/migrations/2026_05_08_130004_create_ticket_orders_table.php b/database/migrations/2026_05_08_130004_create_ticket_orders_table.php new file mode 100644 index 0000000..3cc7dda --- /dev/null +++ b/database/migrations/2026_05_08_130004_create_ticket_orders_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('order_no', 64)->unique(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->string('currency_code', 16); + $table->bigInteger('total_bet_amount')->default(0); + $table->bigInteger('total_rebate_amount')->default(0); + $table->bigInteger('total_actual_deduct')->default(0); + $table->bigInteger('total_estimated_payout')->default(0); + $table->string('status', 32); + $table->string('submit_source', 16)->default('h5'); + $table->string('client_trace_id', 64)->nullable(); + $table->timestamps(); + + $table->index(['player_id', 'draw_id'], 'idx_ticket_orders_player_draw'); + }); + } + + public function down(): void + { + Schema::dropIfExists('ticket_orders'); + } +}; diff --git a/database/migrations/2026_05_08_130005_create_ticket_items_table.php b/database/migrations/2026_05_08_130005_create_ticket_items_table.php new file mode 100644 index 0000000..bec7927 --- /dev/null +++ b/database/migrations/2026_05_08_130005_create_ticket_items_table.php @@ -0,0 +1,51 @@ +id(); + $table->string('ticket_no', 64)->unique(); + $table->foreignId('order_id')->constrained('ticket_orders')->cascadeOnDelete(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->string('original_number', 32)->nullable(); + $table->char('normalized_number', 4); + $table->string('play_code', 32); + $table->unsignedTinyInteger('dimension')->nullable()->comment('2/3/4'); + $table->unsignedTinyInteger('digit_slot')->nullable()->comment('千百十个位,领域字典'); + $table->string('bet_mode', 32)->nullable(); + $table->bigInteger('unit_bet_amount')->default(0); + $table->bigInteger('total_bet_amount')->default(0); + $table->decimal('rebate_rate_snapshot', 8, 4)->default(0); + $table->decimal('commission_rate_snapshot', 8, 4)->default(0); + $table->bigInteger('actual_deduct_amount')->default(0); + $table->json('odds_snapshot_json')->nullable(); + $table->json('rule_snapshot_json')->nullable(); + $table->unsignedInteger('combination_count')->default(1); + $table->bigInteger('estimated_max_payout')->default(0); + $table->bigInteger('risk_locked_amount')->default(0); + $table->string('status', 32); + $table->string('fail_reason_code', 32)->nullable(); + $table->string('fail_reason_text', 255)->nullable(); + $table->bigInteger('win_amount')->default(0); + $table->bigInteger('jackpot_win_amount')->default(0); + $table->timestamp('settled_at')->nullable(); + $table->timestamps(); + + $table->index(['player_id', 'draw_id'], 'idx_ticket_items_player_draw'); + $table->index(['draw_id', 'status'], 'idx_ticket_items_draw_status'); + $table->index(['draw_id', 'normalized_number'], 'idx_ticket_items_draw_number'); + }); + } + + public function down(): void + { + Schema::dropIfExists('ticket_items'); + } +}; diff --git a/database/migrations/2026_05_08_130006_create_ticket_combinations_table.php b/database/migrations/2026_05_08_130006_create_ticket_combinations_table.php new file mode 100644 index 0000000..c3a9fbc --- /dev/null +++ b/database/migrations/2026_05_08_130006_create_ticket_combinations_table.php @@ -0,0 +1,29 @@ +id(); + $table->foreignId('ticket_item_id')->constrained('ticket_items')->cascadeOnDelete(); + $table->unsignedInteger('combination_no')->default(0); + $table->char('number_4d', 4); + $table->bigInteger('bet_amount')->default(0); + $table->bigInteger('estimated_payout')->default(0); + $table->timestamp('created_at')->useCurrent(); + + $table->index('ticket_item_id', 'idx_ticket_combinations_item'); + $table->index('number_4d', 'idx_ticket_combinations_number'); + }); + } + + public function down(): void + { + Schema::dropIfExists('ticket_combinations'); + } +}; diff --git a/database/migrations/2026_05_08_130007_create_risk_pools_and_lock_logs_tables.php b/database/migrations/2026_05_08_130007_create_risk_pools_and_lock_logs_tables.php new file mode 100644 index 0000000..2aec7c7 --- /dev/null +++ b/database/migrations/2026_05_08_130007_create_risk_pools_and_lock_logs_tables.php @@ -0,0 +1,45 @@ +id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->char('normalized_number', 4); + $table->bigInteger('total_cap_amount')->default(0); + $table->bigInteger('locked_amount')->default(0); + $table->bigInteger('remaining_amount')->default(0); + $table->unsignedTinyInteger('sold_out_status')->default(0); + $table->unsignedBigInteger('version')->default(0); + $table->timestamps(); + + $table->unique(['draw_id', 'normalized_number'], 'uk_risk_pools_draw_number'); + $table->index(['draw_id', 'sold_out_status'], 'idx_risk_pools_draw_soldout'); + }); + + Schema::create('risk_pool_lock_logs', function (Blueprint $table) { + $table->id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->char('normalized_number', 4); + $table->foreignId('ticket_item_id')->nullable()->constrained('ticket_items')->nullOnDelete(); + $table->string('action_type', 16); + $table->bigInteger('amount')->default(0); + $table->string('source_reason', 32)->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->index(['draw_id', 'normalized_number'], 'idx_risk_lock_logs_draw_number'); + }); + } + + public function down(): void + { + Schema::dropIfExists('risk_pool_lock_logs'); + Schema::dropIfExists('risk_pools'); + } +}; diff --git a/database/migrations/2026_05_08_130008_create_settlement_and_jackpot_tables.php b/database/migrations/2026_05_08_130008_create_settlement_and_jackpot_tables.php new file mode 100644 index 0000000..e5cdf4b --- /dev/null +++ b/database/migrations/2026_05_08_130008_create_settlement_and_jackpot_tables.php @@ -0,0 +1,88 @@ +id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->foreignId('result_batch_id')->constrained('draw_result_batches')->cascadeOnDelete(); + $table->unsignedInteger('settle_version')->default(1); + $table->string('status', 32); + $table->unsignedInteger('total_ticket_count')->default(0); + $table->unsignedInteger('total_win_count')->default(0); + $table->bigInteger('total_payout_amount')->default(0); + $table->bigInteger('total_jackpot_payout_amount')->default(0); + $table->timestamp('started_at')->nullable(); + $table->timestamp('finished_at')->nullable(); + $table->timestamps(); + + $table->index(['draw_id', 'settle_version'], 'idx_settlement_batches_draw_version'); + }); + + Schema::create('ticket_settlement_details', function (Blueprint $table) { + $table->id(); + $table->foreignId('settlement_batch_id')->constrained('settlement_batches')->cascadeOnDelete(); + $table->foreignId('ticket_item_id')->constrained('ticket_items')->cascadeOnDelete(); + $table->string('matched_prize_tier', 32)->nullable(); + $table->bigInteger('win_amount')->default(0); + $table->bigInteger('jackpot_allocation_amount')->default(0); + $table->json('match_detail_json')->nullable(); + $table->timestamps(); + + $table->unique(['settlement_batch_id', 'ticket_item_id'], 'uk_ticket_settlement_batch_ticket'); + }); + + Schema::create('jackpot_pools', function (Blueprint $table) { + $table->id(); + $table->string('currency_code', 16)->unique(); + $table->bigInteger('current_amount')->default(0); + $table->decimal('contribution_rate', 8, 4)->default(0); + $table->bigInteger('trigger_threshold')->default(0); + $table->decimal('payout_rate', 8, 4)->default(0); + $table->unsignedInteger('force_trigger_draw_gap')->default(0); + $table->bigInteger('min_bet_amount')->default(0); + $table->unsignedTinyInteger('status')->default(0)->comment('0=off,1=on'); + $table->foreignId('last_trigger_draw_id')->nullable()->constrained('draws')->nullOnDelete(); + $table->timestamps(); + }); + + Schema::create('jackpot_contributions', function (Blueprint $table) { + $table->id(); + $table->foreignId('jackpot_pool_id')->constrained('jackpot_pools')->cascadeOnDelete(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->foreignId('player_id')->constrained('players')->cascadeOnDelete(); + $table->foreignId('ticket_item_id')->nullable()->constrained('ticket_items')->nullOnDelete(); + $table->bigInteger('contribution_amount')->default(0); + $table->string('currency_code', 16); + $table->timestamps(); + + $table->index(['draw_id', 'player_id'], 'idx_jackpot_contrib_draw_player'); + }); + + Schema::create('jackpot_payout_logs', function (Blueprint $table) { + $table->id(); + $table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete(); + $table->foreignId('jackpot_pool_id')->constrained('jackpot_pools')->cascadeOnDelete(); + $table->string('trigger_type', 32); + $table->bigInteger('total_payout_amount')->default(0); + $table->unsignedInteger('winner_count')->default(0); + $table->json('trigger_snapshot_json')->nullable(); + $table->timestamp('created_at')->useCurrent(); + }); + } + + public function down(): void + { + Schema::dropIfExists('jackpot_payout_logs'); + Schema::dropIfExists('jackpot_contributions'); + Schema::dropIfExists('jackpot_pools'); + Schema::dropIfExists('ticket_settlement_details'); + Schema::dropIfExists('settlement_batches'); + } +}; diff --git a/database/migrations/2026_05_08_130009_create_report_audit_reconcile_tables.php b/database/migrations/2026_05_08_130009_create_report_audit_reconcile_tables.php new file mode 100644 index 0000000..675fa9a --- /dev/null +++ b/database/migrations/2026_05_08_130009_create_report_audit_reconcile_tables.php @@ -0,0 +1,87 @@ +id(); + $table->string('job_no', 64)->unique(); + $table->foreignId('admin_user_id')->nullable()->constrained('admin_users')->nullOnDelete(); + $table->string('report_type', 64); + $table->string('export_format', 16)->default('csv'); + $table->json('filter_json')->nullable(); + $table->string('status', 32); + $table->string('output_path', 512)->nullable(); + $table->text('error_message')->nullable(); + $table->timestamp('finished_at')->nullable(); + $table->timestamps(); + }); + + Schema::create('audit_logs', function (Blueprint $table) { + $table->id(); + $table->string('operator_type', 16); + $table->unsignedBigInteger('operator_id')->default(0); + $table->string('module_code', 32)->nullable(); + $table->string('action_code', 32)->nullable(); + $table->string('target_type', 32)->nullable(); + $table->string('target_id', 64)->nullable(); + $table->json('before_json')->nullable(); + $table->json('after_json')->nullable(); + $table->string('ip', 64)->nullable(); + $table->string('user_agent', 255)->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->index(['operator_type', 'operator_id', 'created_at'], 'idx_audit_logs_operator_time'); + $table->index(['module_code', 'action_code'], 'idx_audit_logs_module_action'); + }); + + Schema::create('system_jobs', function (Blueprint $table) { + $table->id(); + $table->string('job_key', 128)->unique(); + $table->string('name', 128); + $table->string('schedule_cron', 64)->nullable(); + $table->boolean('is_enabled')->default(true); + $table->timestamp('last_started_at')->nullable(); + $table->timestamp('last_finished_at')->nullable(); + $table->string('last_status', 32)->nullable(); + $table->timestamps(); + }); + + Schema::create('reconcile_jobs', function (Blueprint $table) { + $table->id(); + $table->string('job_no', 64)->unique(); + $table->string('reconcile_type', 32); + $table->string('status', 32); + $table->timestamp('period_start')->nullable(); + $table->timestamp('period_end')->nullable(); + $table->json('summary_json')->nullable(); + $table->timestamp('finished_at')->nullable(); + $table->timestamps(); + }); + + Schema::create('reconcile_items', function (Blueprint $table) { + $table->id(); + $table->foreignId('reconcile_job_id')->constrained('reconcile_jobs')->cascadeOnDelete(); + $table->string('side_a_ref', 128)->nullable(); + $table->string('side_b_ref', 128)->nullable(); + $table->bigInteger('difference_amount')->default(0); + $table->string('status', 32); + $table->timestamp('resolved_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('reconcile_items'); + Schema::dropIfExists('reconcile_jobs'); + Schema::dropIfExists('system_jobs'); + Schema::dropIfExists('audit_logs'); + Schema::dropIfExists('report_jobs'); + } +};