Files
coruna-lab/app/Http/Controllers/Admin/PageVisitController.php
T
2026-08-14 02:59:21 +08:00

193 lines
6.6 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\PortalAware;
use App\Http\Controllers\Controller;
use App\Models\PageVisit;
use App\Models\User;
use App\Support\AgentScope;
use Carbon\Carbon;
use Illuminate\Http\Request;
class PageVisitController extends Controller
{
use PortalAware;
public function index()
{
$agents = $this->isAgentPortal()
? collect()
: User::query()->orderBy('username')->get(['id', 'username']);
return view('admin.visits.index', [
'portal' => $this->portal(),
'agents' => $agents,
]);
}
public function data(Request $request)
{
$q = $this->scopedQuery($request);
$limit = min(100, max(1, (int) $request->query('limit', 20)));
$page = max(1, (int) $request->query('page', 1));
$total = (clone $q)->count();
$rows = (clone $q)
->orderByDesc('id')
->forPage($page, $limit)
->get([
'id', 'channel_id', 'client_uid', 'os', 'os_version',
'browser', 'browser_version', 'user_agent', 'ip', 'domain', 'referer', 'created_at',
]);
return response()->json([
'code' => 0,
'msg' => '',
'count' => $total,
'data' => $rows->map(static fn (PageVisit $v) => [
'id' => $v->id,
'channel_id' => $v->channel_id,
'client_uid' => $v->client_uid,
'os' => $v->os ?: '',
'os_version' => $v->os_version ?: '',
'browser' => $v->browser ?: '',
'browser_version' => $v->browser_version ?: '',
'user_agent' => $v->user_agent ?: '',
'ip' => $v->ip ?: '',
'domain' => $v->domain ?: '',
'referer' => $v->referer ?: '',
'created_at' => optional($v->created_at)?->toDateTimeString(),
])->values(),
]);
}
public function groups(Request $request)
{
$group = (string) $request->query('group', 'os');
$base = $this->scopedQuery($request);
$builder = match ($group) {
'os_version' => $base
->select('os', 'os_version')
->selectRaw('COUNT(*) as pv')
->selectRaw('COUNT(DISTINCT client_uid) as uv')
->groupBy('os', 'os_version'),
'domain' => $base
->select('domain')
->selectRaw('COUNT(*) as pv')
->selectRaw('COUNT(DISTINCT client_uid) as uv')
->groupBy('domain'),
'browser' => $base
->select('browser')
->selectRaw('COUNT(*) as pv')
->selectRaw('COUNT(DISTINCT client_uid) as uv')
->groupBy('browser'),
'browser_version' => $base
->select('browser', 'browser_version')
->selectRaw('COUNT(*) as pv')
->selectRaw('COUNT(DISTINCT client_uid) as uv')
->groupBy('browser', 'browser_version'),
default => $base
->select('os')
->selectRaw('COUNT(*) as pv')
->selectRaw('COUNT(DISTINCT client_uid) as uv')
->groupBy('os'),
};
$rows = $builder
->orderByDesc('pv')
->limit(50)
->get()
->map(static function ($row) use ($group) {
$label = match ($group) {
'os_version' => trim(((string) ($row->os ?? '')).' '.((string) ($row->os_version ?? ''))),
'domain' => (string) ($row->domain ?? ''),
'browser' => (string) ($row->browser ?? ''),
'browser_version' => trim(((string) ($row->browser ?? '')).' '.((string) ($row->browser_version ?? ''))),
default => (string) ($row->os ?? ''),
};
return [
'label' => $label !== '' ? $label : 'Unknown',
'pv' => (int) $row->pv,
'uv' => (int) $row->uv,
];
})
->values();
return response()->json([
'code' => 0,
'msg' => '',
'data' => [
'group' => $group,
'rows' => $rows,
],
]);
}
private function scopedQuery(Request $request)
{
$q = PageVisit::query();
AgentScope::applyChannelIdScope($q, $this->agent());
if (! $this->isAgentPortal()) {
AgentScope::applyChannelIdAgentUserFilter(
$q,
AgentScope::parseAgentUserIdFilter($request->query('agent_user_id'))
);
}
$channelId = trim((string) $request->query('channel_id', ''));
if ($channelId !== '') {
$q->where('channel_id', 'like', '%'.$channelId.'%');
}
$os = trim((string) $request->query('os', ''));
if ($os !== '') {
$q->where('os', $os);
}
$osVersion = trim((string) $request->query('os_version', ''));
if ($osVersion !== '') {
$q->where('os_version', $osVersion);
}
$browser = trim((string) $request->query('browser', ''));
if ($browser !== '') {
$q->where('browser', $browser);
}
$browserVersion = trim((string) $request->query('browser_version', ''));
if ($browserVersion !== '') {
$q->where('browser_version', $browserVersion);
}
$domain = trim((string) $request->query('domain', ''));
if ($domain !== '') {
$q->where('domain', 'like', '%'.$domain.'%');
}
$referer = trim((string) $request->query('referer', ''));
if ($referer !== '') {
$q->where('referer', 'like', '%'.$referer.'%');
}
[$from, $to] = $this->rangeBounds((string) $request->query('range', '30d'));
$q->whereBetween('created_at', [$from, $to]);
return $q;
}
/**
* @return array{0: Carbon, 1: Carbon}
*/
private function rangeBounds(string $range): array
{
$now = Carbon::now();
return match ($range) {
'today' => [$now->copy()->startOfDay(), $now->copy()->endOfDay()],
'yesterday' => [
$now->copy()->subDay()->startOfDay(),
$now->copy()->subDay()->endOfDay(),
],
'7d' => [$now->copy()->subDays(6)->startOfDay(), $now->copy()->endOfDay()],
default => [$now->copy()->subDays(29)->startOfDay(), $now->copy()->endOfDay()],
};
}
}