132 lines
4.3 KiB
PHP
132 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Concerns\PortalAware;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Device;
|
|
use App\Models\PageVisit;
|
|
use App\Models\User;
|
|
use App\Support\AgentScope;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
|
|
class DashboardController extends Controller
|
|
{
|
|
use PortalAware;
|
|
|
|
public function index()
|
|
{
|
|
$agents = $this->isAgentPortal()
|
|
? collect()
|
|
: User::query()->orderBy('username')->get(['id', 'username']);
|
|
|
|
return view('admin.dashboard.index', [
|
|
'portal' => $this->portal(),
|
|
'agents' => $agents,
|
|
]);
|
|
}
|
|
|
|
public function data(Request $request)
|
|
{
|
|
$range = (string) $request->query('range', '30d');
|
|
[$from, $to] = $this->rangeBounds($range);
|
|
|
|
$channelId = trim((string) $request->query('channel_id', ''));
|
|
$agentUserId = $this->isAgentPortal()
|
|
? (int) ($this->agent()?->id ?? 0)
|
|
: (int) $request->query('agent_user_id', 0);
|
|
|
|
$base = Device::query();
|
|
AgentScope::applyDeviceChannelScope($base, $this->agent());
|
|
if (! $this->isAgentPortal() && $agentUserId > 0) {
|
|
AgentScope::applyAgentUserFilter($base, $agentUserId);
|
|
}
|
|
if ($channelId !== '') {
|
|
$base->where('channel_id', 'like', '%'.$channelId.'%');
|
|
}
|
|
|
|
$total = (clone $base)->count();
|
|
$newCount = (clone $base)->whereBetween('created_at', [$from, $to])->count();
|
|
$activeCount = (clone $base)->whereBetween('updated_at', [$from, $to])->count();
|
|
|
|
$visits = PageVisit::query();
|
|
AgentScope::applyChannelIdScope($visits, $this->agent());
|
|
if (! $this->isAgentPortal() && $agentUserId > 0) {
|
|
AgentScope::applyChannelIdAgentUserFilter($visits, $agentUserId);
|
|
}
|
|
if ($channelId !== '') {
|
|
$visits->where('channel_id', 'like', '%'.$channelId.'%');
|
|
}
|
|
$visits->whereBetween('created_at', [$from, $to]);
|
|
|
|
$pv = (clone $visits)->count();
|
|
$uv = (int) (clone $visits)->selectRaw('COUNT(DISTINCT client_uid) as aggregate')->value('aggregate');
|
|
|
|
$byOs = (clone $visits)
|
|
->select('os')
|
|
->selectRaw('COUNT(*) as pv')
|
|
->selectRaw('COUNT(DISTINCT client_uid) as uv')
|
|
->groupBy('os')
|
|
->orderByDesc('pv')
|
|
->limit(10)
|
|
->get()
|
|
->map(static fn ($r) => [
|
|
'label' => ((string) ($r->os ?? '')) !== '' ? (string) $r->os : 'Unknown',
|
|
'pv' => (int) $r->pv,
|
|
'uv' => (int) $r->uv,
|
|
])
|
|
->values();
|
|
|
|
$byBrowser = (clone $visits)
|
|
->select('browser')
|
|
->selectRaw('COUNT(*) as pv')
|
|
->selectRaw('COUNT(DISTINCT client_uid) as uv')
|
|
->groupBy('browser')
|
|
->orderByDesc('pv')
|
|
->limit(10)
|
|
->get()
|
|
->map(static fn ($r) => [
|
|
'label' => ((string) ($r->browser ?? '')) !== '' ? (string) $r->browser : 'Unknown',
|
|
'pv' => (int) $r->pv,
|
|
'uv' => (int) $r->uv,
|
|
])
|
|
->values();
|
|
|
|
return response()->json([
|
|
'code' => 0,
|
|
'msg' => '',
|
|
'data' => [
|
|
'total' => $total,
|
|
'new_count' => $newCount,
|
|
'active_count' => $activeCount,
|
|
'pv' => $pv,
|
|
'uv' => $uv,
|
|
'by_os' => $byOs,
|
|
'by_browser' => $byBrowser,
|
|
'range' => $range,
|
|
'from' => $from->toDateTimeString(),
|
|
'to' => $to->toDateTimeString(),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @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()],
|
|
};
|
|
}
|
|
}
|