user(); $allowedVenueIds = $user->isSuperAdmin() ? Venue::query()->pluck('id') : $user->venues()->pluck('venues.id'); $selectedVenueId = $request->filled('venue_id') ? (int) $request->input('venue_id') : null; $venueIds = $allowedVenueIds; if ($selectedVenueId) { $venueIds = $venueIds->filter(fn ($id) => (int) $id === $selectedVenueId)->values(); } $activityId = $request->filled('activity_id') ? (int) $request->input('activity_id') : null; if ($activityId) { $allowed = Activity::query() ->whereKey($activityId) ->whereNull('deleted_at') ->whereIn('venue_id', $venueIds) ->exists(); if (! $allowed) { return response()->json(['message' => '活动不存在或无权查看'], 422); } } /** 顶部指标:账号可见场馆范围内的全量累计(不受「筛选场馆」影响) */ $scopeVenueIds = $allowedVenueIds; $userCount = (int) DB::table('reservations') ->whereIn('venue_id', $scopeVenueIds) ->whereNotNull('wechat_user_id') ->selectRaw('COUNT(DISTINCT wechat_user_id) as c') ->value('c'); $activitySessions = Activity::query() ->whereIn('venue_id', $scopeVenueIds) ->whereNull('deleted_at') ->count(); $ticketGrabSessions = TicketGrabEvent::query() ->whereHas('venues', fn ($vq) => $vq->whereIn('venues.id', $scopeVenueIds)) ->count(); $blacklistedUniqueQuery = Blacklist::query() ->active() ->whereIn('venue_id', $scopeVenueIds) ->whereNotNull('visitor_phone') ->whereRaw("TRIM(visitor_phone) <> ''") ->whereExists(function ($q) use ($scopeVenueIds, $user) { $q->selectRaw('1') ->from('reservations') ->whereColumn('reservations.visitor_phone', 'blacklists.visitor_phone') ->whereIn('reservations.venue_id', $scopeVenueIds); if ($user->isSuperAdmin() && Schema::hasTable('wechat_users')) { $q->whereNotNull('reservations.wechat_user_id') ->whereExists(function ($wq) { $wq->selectRaw('1') ->from('wechat_users') ->whereColumn('wechat_users.id', 'reservations.wechat_user_id'); }); } }); $blacklistedUnique = $blacklistedUniqueQuery ->distinct('visitor_phone') ->count('visitor_phone'); $baseActivityQuery = Activity::query() ->whereIn('venue_id', $venueIds) ->whereNull('deleted_at'); if ($activityId !== null) { $baseActivityQuery->whereKey($activityId); } $totalViews = (int) (clone $baseActivityQuery)->sum('view_count'); $page = max(1, (int) $request->input('activity_stats_page', 1)); $pageSize = max(1, min(2000, (int) $request->input('activity_stats_page_size', 500))); $totalActivities = (clone $baseActivityQuery)->count(); $activityRows = (clone $baseActivityQuery) ->orderByDesc('view_count') ->orderByDesc('id') ->forPage($page, $pageSize) ->get(['id', 'title', 'venue_id', 'start_at', 'end_at', 'view_count']); $venueIdsForNames = $activityRows->pluck('venue_id')->unique()->filter()->values()->all(); $venueNameMap = $venueIdsForNames === [] ? collect() : Venue::query()->whereIn('id', $venueIdsForNames)->pluck('name', 'id'); $activityStatsActivities = $activityRows->map(function ($a) use ($venueNameMap) { $vid = (int) $a->venue_id; return [ 'id' => (int) $a->id, 'title' => (string) $a->title, 'venue_id' => $vid, 'venue_name' => (string) ($venueNameMap[$vid] ?? ('#'.$vid)), 'view_count' => (int) ($a->view_count ?? 0), 'start_at' => $a->start_at, 'end_at' => $a->end_at, ]; })->values()->all(); return response()->json([ 'scope' => [ 'role' => $user->role, 'venue_id' => $selectedVenueId, 'activity_id' => $activityId, ], 'summary' => [ 'activity_sessions' => (int) $activitySessions, 'ticket_grab_sessions' => (int) $ticketGrabSessions, 'user_count' => (int) $userCount, 'blacklisted_unique' => (int) $blacklistedUnique, ], 'activity_stats' => [ 'total_view_count' => $totalViews, ], 'activity_stats_activities' => [ 'data' => $activityStatsActivities, 'total' => $totalActivities, 'page' => $page, 'page_size' => $pageSize, ], ]); } public function ticketGrabStats(Request $request, DashboardTicketGrabStatsService $ticketGrabStats): JsonResponse { $validated = $request->validate([ 'ticket_grab_event_id' => ['required', 'integer', 'exists:ticket_grab_events,id'], 'date' => ['required', 'date_format:Y-m-d'], ]); $user = $request->user(); $allowedVenueIds = $user->isSuperAdmin() ? Venue::query()->pluck('id') : $user->venues()->pluck('venues.id'); $eventId = (int) $validated['ticket_grab_event_id']; $date = $validated['date']; $pivotVenues = TicketGrabEventVenue::query() ->where('ticket_grab_event_id', $eventId) ->pluck('venue_id'); if ($pivotVenues->isNotEmpty() && ! $user->isSuperAdmin()) { $allow = $allowedVenueIds->map(fn ($id) => (int) $id); $ok = false; foreach ($pivotVenues as $vid) { if ($allow->contains((int) $vid)) { $ok = true; break; } } if (! $ok) { return response()->json(['message' => '无权查看该抢票活动统计'], 403); } } $scoped = DashboardTicketGrabStatsService::scopedVenueIdsForEvent($eventId, $allowedVenueIds); if ($scoped->isEmpty()) { return response()->json(['message' => '当前账号下无可统计的场馆或未配置参与场馆'], 403); } $payload = $ticketGrabStats->build($eventId, $date, $scoped); if (isset($payload['error'])) { return response()->json(['message' => $payload['error']], 404); } $payload['data_updated_at'] = $date; return response()->json($payload); } }