You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
2.0 KiB

<?php
namespace App\Services;
use App\Models\Venue;
use Illuminate\Support\Collection;
class RealtimeCrowdService
{
/**
* 第三方实时客流占位实现:
* - 目前使用可复现的模拟数;
* - 后续对接第三方接口时,只需替换本类方法。
*
* @param Collection<int, int> $venueIds
* @return array{city_total: int, top_venues: array<int, array{venue_id:int, venue_name:string, current_count:int}>}
*/
public function citySummary(Collection $venueIds): array
{
$ids = $venueIds->map(fn ($id) => (int) $id)->filter()->unique()->values();
if ($ids->isEmpty()) {
return ['city_total' => 0, 'top_venues' => []];
}
$map = $this->venueCurrentMap($ids);
$top = collect($map)
->sortByDesc('current_count')
->take(3)
->values()
->all();
$cityTotal = collect($map)->sum('current_count');
return [
'city_total' => (int) $cityTotal,
'top_venues' => $top,
];
}
/**
* @param Collection<int, int> $venueIds
* @return array<int, array{venue_id:int, venue_name:string, current_count:int}>
*/
public function venueCurrentMap(Collection $venueIds): array
{
$ids = $venueIds->map(fn ($id) => (int) $id)->filter()->unique()->values();
if ($ids->isEmpty()) {
return [];
}
$venues = Venue::query()->whereIn('id', $ids)->get(['id', 'name']);
$seed = (int) now()->format('YmdHi'); // 分钟级动态变化
return $venues->map(function (Venue $venue) use ($seed) {
$base = abs(crc32((string) ($venue->id * 131 + $seed)));
$current = 20 + ($base % 380); // 20~399
return [
'venue_id' => (int) $venue->id,
'venue_name' => (string) $venue->name,
'current_count' => (int) $current,
];
})->values()->all();
}
}