DashboardController.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. namespace App\Http\Controllers\Admin;
  3. /*
  4. * DashboardController — главная страница административной панели.
  5. * Собирает метрики: заявки, посетители, состояние системы, последние события.
  6. */
  7. use App\Http\Controllers\Controller;
  8. use App\Models\Car;
  9. use App\Models\Lead;
  10. use App\Models\Review;
  11. use App\Models\Service;
  12. use Illuminate\Support\Carbon;
  13. use Illuminate\Support\Facades\Cache;
  14. use Illuminate\Support\Facades\DB;
  15. use Illuminate\View\View;
  16. class DashboardController extends Controller
  17. {
  18. public function index(): View
  19. {
  20. $today = now()->toDateString();
  21. $yesterday = now()->subDay()->toDateString();
  22. // ── Заявки ────────────────────────────────────────────────────────
  23. $leadsToday = Lead::whereDate('created_at', $today)->count();
  24. $leadsYesterday = Lead::whereDate('created_at', $yesterday)->count();
  25. $leadsTotal = Lead::count();
  26. $leadsUnread = Lead::whereNull('read_at')->count();
  27. // График заявок за 14 дней
  28. $leadsChart = $this->chartData(
  29. Lead::class,
  30. 'created_at',
  31. 14,
  32. 'Заявки'
  33. );
  34. // Последние 6 заявок
  35. $recentLeads = Lead::latest()->limit(6)->get();
  36. // ── Посетители ────────────────────────────────────────────────────
  37. $visitRow = DB::table('page_visits')->where('date', $today)->first();
  38. $visitYesterday = DB::table('page_visits')->where('date', $yesterday)->first();
  39. $visitsToday = $visitRow?->views ?? 0;
  40. $uniqueToday = $visitRow?->unique_ips ?? 0;
  41. // График посетителей за 14 дней
  42. $visitsChart = $this->visitsChartData(14);
  43. // ── Контент ───────────────────────────────────────────────────────
  44. $carsTotal = Car::count();
  45. $servicesTotal = Service::count();
  46. $reviewsTotal = Review::count();
  47. // ── Скорость / система ────────────────────────────────────────────
  48. $systemInfo = $this->systemInfo();
  49. // ── Средняя скорость ответа (самозамер) ───────────────────────────
  50. $responseTime = $this->measureSelfResponseTime();
  51. return view('admin.dashboard', compact(
  52. 'leadsToday', 'leadsYesterday', 'leadsTotal', 'leadsUnread',
  53. 'leadsChart', 'recentLeads',
  54. 'visitsToday', 'uniqueToday', 'visitYesterday',
  55. 'visitsChart',
  56. 'carsTotal', 'servicesTotal', 'reviewsTotal',
  57. 'systemInfo', 'responseTime'
  58. ));
  59. }
  60. // ── Приватные хелперы ─────────────────────────────────────────────────
  61. private function chartData(string $model, string $column, int $days, string $label): array
  62. {
  63. $start = now()->subDays($days - 1)->startOfDay();
  64. $rows = DB::table((new $model)->getTable())
  65. ->selectRaw("DATE($column) as d, COUNT(*) as cnt")
  66. ->where($column, '>=', $start)
  67. ->groupBy('d')
  68. ->pluck('cnt', 'd');
  69. $labels = [];
  70. $data = [];
  71. for ($i = $days - 1; $i >= 0; $i--) {
  72. $date = now()->subDays($i)->toDateString();
  73. $labels[] = now()->subDays($i)->format('d.m');
  74. $data[] = (int) ($rows[$date] ?? 0);
  75. }
  76. return compact('labels', 'data', 'label');
  77. }
  78. private function visitsChartData(int $days): array
  79. {
  80. $start = now()->subDays($days - 1)->toDateString();
  81. $rows = DB::table('page_visits')
  82. ->where('date', '>=', $start)
  83. ->orderBy('date')
  84. ->pluck('views', 'date');
  85. $labels = [];
  86. $data = [];
  87. for ($i = $days - 1; $i >= 0; $i--) {
  88. $date = now()->subDays($i)->toDateString();
  89. $labels[] = now()->subDays($i)->format('d.m');
  90. $data[] = (int) ($rows[$date] ?? 0);
  91. }
  92. return ['labels' => $labels, 'data' => $data, 'label' => 'Просмотры'];
  93. }
  94. private function systemInfo(): array
  95. {
  96. $cacheDriver = config('cache.default', 'file');
  97. $opcache = function_exists('opcache_get_status') ? opcache_get_status(false) : null;
  98. return [
  99. 'php' => PHP_VERSION,
  100. 'laravel' => app()->version(),
  101. 'cache_driver' => $cacheDriver,
  102. 'opcache' => $opcache && ($opcache['opcache_enabled'] ?? false),
  103. 'opcache_hits' => $opcache ? ($opcache['opcache_statistics']['hits'] ?? 0) : 0,
  104. 'opcache_misses'=> $opcache ? ($opcache['opcache_statistics']['misses'] ?? 0) : 0,
  105. 'disk_free' => $this->humanBytes(disk_free_space(base_path())),
  106. 'disk_total' => $this->humanBytes(disk_total_space(base_path())),
  107. 'disk_pct' => round((1 - disk_free_space(base_path()) / disk_total_space(base_path())) * 100),
  108. 'memory_limit' => ini_get('memory_limit'),
  109. 'max_upload' => ini_get('upload_max_filesize'),
  110. ];
  111. }
  112. private function measureSelfResponseTime(): ?int
  113. {
  114. // Берём время старта текущего запроса как proxy метрики
  115. if (defined('LARAVEL_START')) {
  116. return (int) ((microtime(true) - LARAVEL_START) * 1000);
  117. }
  118. return null;
  119. }
  120. private function humanBytes(float $bytes): string
  121. {
  122. foreach (['Б', 'КБ', 'МБ', 'ГБ', 'ТБ'] as $unit) {
  123. if ($bytes < 1024) {
  124. return round($bytes, 1) . ' ' . $unit;
  125. }
  126. $bytes /= 1024;
  127. }
  128. return round($bytes, 1) . ' ПБ';
  129. }
  130. }