From 85d495e3b034c2a16cd5d3d8acce2fd24751798d Mon Sep 17 00:00:00 2001 From: kang Date: Mon, 1 Jun 2026 10:03:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E5=BC=80=E5=A5=96?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 AdminDrawIndexController 中新增 aggregateListStats 方法,聚合每个开奖的投注和派彩金额,计算盈亏情况。 - 更新 row 方法,使用聚合统计数据替代原有的直接查询,提升性能与可读性。 - 通过优化数据处理逻辑,确保在获取开奖列表时能够同时返回相关的统计信息。 --- .../Admin/Draw/AdminDrawIndexController.php | 70 ++++++++++++++++--- ...1_100000_add_query_performance_indexes.php | 53 ++++++++++++++ 2 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 database/migrations/2026_05_31_100000_add_query_performance_indexes.php diff --git a/app/Http/Controllers/Api/V1/Admin/Draw/AdminDrawIndexController.php b/app/Http/Controllers/Api/V1/Admin/Draw/AdminDrawIndexController.php index 999811b..6f7b09a 100644 --- a/app/Http/Controllers/Api/V1/Admin/Draw/AdminDrawIndexController.php +++ b/app/Http/Controllers/Api/V1/Admin/Draw/AdminDrawIndexController.php @@ -37,7 +37,11 @@ final class AdminDrawIndexController extends Controller /** @var LengthAwarePaginator $paginator */ $paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']); - return AdminApiList::jsonWith($paginator, fn (Draw $row) => $this->row($row), [ + $statsByDrawId = $this->aggregateListStats( + $paginator->getCollection()->pluck('id')->map(fn ($id) => (int) $id)->all(), + ); + + return AdminApiList::jsonWith($paginator, fn (Draw $row) => $this->row($row, $statsByDrawId), [ 'schedule' => [ 'timezone' => LotterySettings::drawTimezone(), 'interval_minutes' => LotterySettings::drawIntervalMinutes(), @@ -47,9 +51,58 @@ final class AdminDrawIndexController extends Controller ]); } - /** @return array */ - private function row(Draw $draw): array + /** + * @param list $drawIds + * @return array + */ + private function aggregateListStats(array $drawIds): array { + if ($drawIds === []) { + return []; + } + + $betByDraw = TicketOrder::query() + ->whereIn('draw_id', $drawIds) + ->groupBy('draw_id') + ->selectRaw('draw_id, COALESCE(SUM(total_actual_deduct), 0) AS total_bet') + ->pluck('total_bet', 'draw_id'); + + $payoutRows = TicketItem::query() + ->whereIn('draw_id', $drawIds) + ->groupBy('draw_id') + ->selectRaw( + 'draw_id, COALESCE(SUM(win_amount), 0) AS win, COALESCE(SUM(jackpot_win_amount), 0) AS jackpot', + ) + ->get() + ->keyBy('draw_id'); + + $stats = []; + foreach ($drawIds as $drawId) { + $bet = (int) ($betByDraw[$drawId] ?? $betByDraw[(string) $drawId] ?? 0); + $payoutRow = $payoutRows->get($drawId) ?? $payoutRows->get((string) $drawId); + $payout = (int) ($payoutRow->win ?? 0) + (int) ($payoutRow->jackpot ?? 0); + $stats[$drawId] = [ + 'total_bet_minor' => $bet, + 'total_payout_minor' => $payout, + 'profit_loss_minor' => $bet - $payout, + ]; + } + + return $stats; + } + + /** + * @param array $statsByDrawId + * @return array + */ + private function row(Draw $draw, array $statsByDrawId): array + { + $stats = $statsByDrawId[(int) $draw->id] ?? [ + 'total_bet_minor' => 0, + 'total_payout_minor' => 0, + 'profit_loss_minor' => 0, + ]; + return [ 'id' => (int) $draw->id, 'draw_no' => $draw->draw_no, @@ -66,14 +119,9 @@ final class AdminDrawIndexController extends Controller 'current_result_version' => (int) $draw->current_result_version, 'settle_version' => (int) $draw->settle_version, 'is_reopened' => (bool) $draw->is_reopened, - 'total_bet_minor' => (int) TicketOrder::query()->where('draw_id', $draw->id)->sum('total_actual_deduct'), - 'total_payout_minor' => (int) TicketItem::query()->where('draw_id', $draw->id)->sum('win_amount') - + (int) TicketItem::query()->where('draw_id', $draw->id)->sum('jackpot_win_amount'), - 'profit_loss_minor' => (int) TicketOrder::query()->where('draw_id', $draw->id)->sum('total_actual_deduct') - - ( - (int) TicketItem::query()->where('draw_id', $draw->id)->sum('win_amount') - + (int) TicketItem::query()->where('draw_id', $draw->id)->sum('jackpot_win_amount') - ), + 'total_bet_minor' => $stats['total_bet_minor'], + 'total_payout_minor' => $stats['total_payout_minor'], + 'profit_loss_minor' => $stats['profit_loss_minor'], 'updated_at' => $draw->updated_at?->toIso8601String(), ]; } diff --git a/database/migrations/2026_05_31_100000_add_query_performance_indexes.php b/database/migrations/2026_05_31_100000_add_query_performance_indexes.php new file mode 100644 index 0000000..09635c1 --- /dev/null +++ b/database/migrations/2026_05_31_100000_add_query_performance_indexes.php @@ -0,0 +1,53 @@ +index('draw_id', 'idx_ticket_orders_draw_id'); + }); + + Schema::table('wallet_txns', function (Blueprint $table): void { + $table->index(['player_id', 'id'], 'idx_wallet_txns_player_id'); + }); + + Schema::table('ticket_items', function (Blueprint $table): void { + $table->index(['player_id', 'id'], 'idx_ticket_items_player_id'); + }); + + Schema::table('draws', function (Blueprint $table): void { + $table->index(['business_date', 'draw_time'], 'idx_draws_business_date_draw_time'); + }); + } + + public function down(): void + { + Schema::table('draws', function (Blueprint $table): void { + $table->dropIndex('idx_draws_business_date_draw_time'); + }); + + Schema::table('ticket_items', function (Blueprint $table): void { + $table->dropIndex('idx_ticket_items_player_id'); + }); + + Schema::table('wallet_txns', function (Blueprint $table): void { + $table->dropIndex('idx_wallet_txns_player_id'); + }); + + Schema::table('ticket_orders', function (Blueprint $table): void { + $table->dropIndex('idx_ticket_orders_draw_id'); + }); + } +};