From c101ece5392ef7934b9486d69319651c3755292f Mon Sep 17 00:00:00 2001 From: kang Date: Mon, 1 Jun 2026 16:01:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=BE=85=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E5=BC=80=E5=A5=96=E6=89=B9=E6=AC=A1=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=87=B3=E7=AE=A1=E7=90=86=E5=91=98=E4=BB=AA?= =?UTF-8?q?=E8=A1=A8=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 AdminDashboardSnapshotBuilder 中新增 resultBatchQueue 方法,统计全站待审核的开奖批次信息。 - 更新仪表板数据结构,包含待审核开奖批次的总数、待开奖次数及首个待审核开奖的 ID。 - 在 AdminDashboardApiTest 中新增测试用例,验证仪表板返回的待审核开奖批次统计数据的准确性。 --- .../Admin/AdminDashboardSnapshotBuilder.php | 31 +++++++++ tests/Feature/AdminDashboardApiTest.php | 67 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/app/Services/Admin/AdminDashboardSnapshotBuilder.php b/app/Services/Admin/AdminDashboardSnapshotBuilder.php index 6889e1d..2094654 100644 --- a/app/Services/Admin/AdminDashboardSnapshotBuilder.php +++ b/app/Services/Admin/AdminDashboardSnapshotBuilder.php @@ -10,6 +10,7 @@ use App\Models\TicketItem; use App\Models\TicketOrder; use App\Models\TransferOrder; use App\Models\SettlementBatch; +use App\Models\DrawResultBatch; use App\Lottery\DrawResultBatchStatus; use App\Services\Draw\DrawHallSnapshotBuilder; @@ -40,6 +41,7 @@ final class AdminDashboardSnapshotBuilder 'finance' => null, 'draw' => null, 'risk' => null, + 'result_batch_queue' => null, 'abnormal_transfer_total' => null, 'warnings' => [], 'capabilities' => [ @@ -75,6 +77,7 @@ final class AdminDashboardSnapshotBuilder $out['finance'] = $this->financeSummary($draw); $out['draw'] = $this->drawPanel($draw); $out['risk'] = $this->riskPanel($draw); + $out['result_batch_queue'] = $this->resultBatchQueue(); } if ($canWallet) { @@ -189,6 +192,34 @@ final class AdminDashboardSnapshotBuilder ]; } + /** + * 全站待审核开奖批次(首页「待审核开奖」卡片用,不限于大厅当前期)。 + * + * @return array{pending_review_total: int, pending_draw_count: int, first_pending_draw_id: int|null, first_pending_batch_id: int|null} + */ + private function resultBatchQueue(): array + { + $pendingQuery = DrawResultBatch::query() + ->where('status', DrawResultBatchStatus::PendingReview->value); + + $pendingTotal = (int) (clone $pendingQuery)->count(); + + $pendingDrawCount = $pendingTotal > 0 + ? (int) (clone $pendingQuery)->distinct('draw_id')->count('draw_id') + : 0; + + $firstPending = $pendingTotal > 0 + ? (clone $pendingQuery)->orderBy('id')->first(['id', 'draw_id']) + : null; + + return [ + 'pending_review_total' => $pendingTotal, + 'pending_draw_count' => $pendingDrawCount, + 'first_pending_draw_id' => $firstPending !== null ? (int) $firstPending->draw_id : null, + 'first_pending_batch_id' => $firstPending !== null ? (int) $firstPending->id : null, + ]; + } + /** @return array */ private function drawPanel(Draw $draw): array { diff --git a/tests/Feature/AdminDashboardApiTest.php b/tests/Feature/AdminDashboardApiTest.php index f4d3649..9b31d32 100644 --- a/tests/Feature/AdminDashboardApiTest.php +++ b/tests/Feature/AdminDashboardApiTest.php @@ -3,6 +3,10 @@ use App\Models\Draw; use App\Models\RiskPool; use App\Models\AdminUser; +use App\Models\DrawResultBatch; +use App\Lottery\DrawStatus; +use App\Lottery\DrawResultBatchStatus; +use App\Lottery\DrawResultSourceType; use Illuminate\Support\Facades\Hash; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -70,6 +74,69 @@ test('admin dashboard aggregates hall finance and risk for super admin', functio ->assertJsonPath('data.risk.sold_out_buckets.d4', 1); }); +test('admin dashboard counts pending result batches site wide not only current draw', function (): void { + $hallDraw = Draw::query()->create([ + 'draw_no' => '20260512-020', + 'business_date' => '2026-05-12', + 'sequence_no' => 20, + 'status' => 'open', + 'start_time' => now()->subHour(), + 'close_time' => now()->addHour(), + 'draw_time' => now()->addHours(2), + 'cooling_end_time' => null, + 'result_source' => null, + 'current_result_version' => 0, + 'settle_version' => 0, + 'is_reopened' => false, + ]); + + $reviewDraw = Draw::query()->create([ + 'draw_no' => '20260512-019', + 'business_date' => '2026-05-12', + 'sequence_no' => 19, + 'status' => DrawStatus::Review->value, + 'start_time' => now()->subHours(3), + 'close_time' => now()->subHour(), + 'draw_time' => now()->subMinutes(30), + 'cooling_end_time' => null, + 'result_source' => DrawResultSourceType::Manual->value, + 'current_result_version' => 0, + 'settle_version' => 0, + 'is_reopened' => false, + ]); + + DrawResultBatch::query()->create([ + 'draw_id' => $reviewDraw->id, + 'result_version' => 1, + 'source_type' => DrawResultSourceType::Manual->value, + 'rng_seed_hash' => null, + 'raw_seed_encrypted' => null, + 'status' => DrawResultBatchStatus::PendingReview->value, + 'created_by' => null, + 'confirmed_by' => null, + 'confirmed_at' => null, + ]); + + $admin = AdminUser::query()->create([ + 'username' => 'dash_queue_admin', + 'name' => 'Dash Queue QA', + 'email' => null, + 'password' => Hash::make('secret-strong'), + 'status' => 0, + ]); + grantSuperAdminRole($admin); + $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken; + + $this->withHeader('Authorization', 'Bearer '.$token) + ->getJson('/api/v1/admin/dashboard') + ->assertOk() + ->assertJsonPath('data.resolved_draw.id', $hallDraw->id) + ->assertJsonPath('data.draw.result_batch_counts.pending_review', 0) + ->assertJsonPath('data.result_batch_queue.pending_review_total', 1) + ->assertJsonPath('data.result_batch_queue.pending_draw_count', 1) + ->assertJsonPath('data.result_batch_queue.first_pending_draw_id', $reviewDraw->id); +}); + test('admin dashboard returns 401 without token', function (): void { $this->getJson('/api/v1/admin/dashboard')->assertStatus(401); });