153 lines
9.7 KiB
PHP
153 lines
9.7 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="ru" class="h-full">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{ $title ?? 'Computer Service' }}</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@if(request()->routeIs('dashboard', 'reports.general'))
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js" defer></script>
|
|
@endif
|
|
|
|
@fluxAppearance
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
@livewireStyles
|
|
</head>
|
|
<body class="h-full bg-slate-100 text-slate-900">
|
|
<div x-data="{ sidebarOpen: false }" class="h-full">
|
|
<div class="fixed inset-y-0 left-0 z-40 w-72 transform bg-slate-900 text-slate-100 shadow-xl transition-transform duration-200 lg:translate-x-0"
|
|
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'">
|
|
<div class="h-full flex flex-col">
|
|
<div class="px-5 py-5 border-b border-slate-800">
|
|
<div class="text-lg font-semibold tracking-tight">{{ config('app.name', 'Computer Service') }}</div>
|
|
<div class="text-xs text-slate-400 mt-1">IT Helpdesk & Service Desk</div>
|
|
</div>
|
|
|
|
<nav class="flex-1 overflow-y-auto p-3 space-y-1 text-sm">
|
|
@php
|
|
$user = auth()->user();
|
|
$isAdmin = $user?->isAdmin();
|
|
$isManager = $user?->isManager();
|
|
$isTechnician = $user?->isTechnician();
|
|
$isClient = $user?->isClient();
|
|
@endphp
|
|
|
|
<p class="px-3 py-1 text-xs uppercase text-slate-400">Главная</p>
|
|
@if($isAdmin || $isManager)
|
|
<a href="{{ route('dashboard') }}" class="nav-link {{ request()->routeIs('dashboard') ? 'nav-link-active' : '' }}">Дашборд</a>
|
|
@endif
|
|
|
|
<p class="px-3 pt-4 pb-1 text-xs uppercase text-slate-400">Заявки</p>
|
|
@if($isAdmin || $isManager)
|
|
<a href="{{ route('requests.index') }}" class="nav-link {{ request()->routeIs('requests.index') ? 'nav-link-active' : '' }}">Все заявки</a>
|
|
<a href="{{ route('requests.create') }}" class="nav-link {{ request()->routeIs('requests.create') ? 'nav-link-active' : '' }}">Создать заявку</a>
|
|
@endif
|
|
@if($isTechnician)
|
|
<a href="{{ route('my-tasks') }}" class="nav-link {{ request()->routeIs('my-tasks') ? 'nav-link-active' : '' }}">Мои задачи</a>
|
|
@endif
|
|
@if($isClient)
|
|
<a href="{{ route('my-requests.index') }}" class="nav-link {{ request()->routeIs('my-requests.*') ? 'nav-link-active' : '' }}">Мои заявки</a>
|
|
@endif
|
|
|
|
@if($isAdmin)
|
|
<p class="px-3 pt-4 pb-1 text-xs uppercase text-slate-400">Справочники</p>
|
|
<a href="{{ route('directories.departments') }}" class="nav-link {{ request()->routeIs('directories.departments') ? 'nav-link-active' : '' }}">Отделы</a>
|
|
<a href="{{ route('directories.equipment-categories') }}" class="nav-link {{ request()->routeIs('directories.equipment-categories') ? 'nav-link-active' : '' }}">Категории оборудования</a>
|
|
<a href="{{ route('directories.request-types') }}" class="nav-link {{ request()->routeIs('directories.request-types') ? 'nav-link-active' : '' }}">Типы заявок</a>
|
|
<a href="{{ route('directories.equipment') }}" class="nav-link {{ request()->routeIs('directories.equipment') ? 'nav-link-active' : '' }}">Оборудование</a>
|
|
@endif
|
|
|
|
@if($isAdmin || $isManager)
|
|
<p class="px-3 pt-4 pb-1 text-xs uppercase text-slate-400">Отчеты</p>
|
|
<a href="{{ route('reports.general') }}" class="nav-link {{ request()->routeIs('reports.general') ? 'nav-link-active' : '' }}">Общий</a>
|
|
<a href="{{ route('reports.technicians') }}" class="nav-link {{ request()->routeIs('reports.technicians') ? 'nav-link-active' : '' }}">Техники</a>
|
|
<a href="{{ route('reports.sla') }}" class="nav-link {{ request()->routeIs('reports.sla') ? 'nav-link-active' : '' }}">SLA</a>
|
|
<a href="{{ route('reports.equipment') }}" class="nav-link {{ request()->routeIs('reports.equipment') ? 'nav-link-active' : '' }}">Оборудование</a>
|
|
@endif
|
|
|
|
@if($isAdmin)
|
|
<p class="px-3 pt-4 pb-1 text-xs uppercase text-slate-400">Система</p>
|
|
<a href="{{ route('users.index') }}" class="nav-link {{ request()->routeIs('users.*') ? 'nav-link-active' : '' }}">Пользователи</a>
|
|
<a href="{{ route('activity-log') }}" class="nav-link {{ request()->routeIs('activity-log') ? 'nav-link-active' : '' }}">Журнал действий</a>
|
|
<a href="{{ route('settings') }}" class="nav-link {{ request()->routeIs('settings') ? 'nav-link-active' : '' }}">Настройки</a>
|
|
@endif
|
|
</nav>
|
|
|
|
<div class="border-t border-slate-800 p-4">
|
|
<div class="flex items-center gap-3 mb-3">
|
|
<div class="h-10 w-10 rounded-full bg-slate-700 flex items-center justify-center text-xs font-semibold">
|
|
{{ mb_substr(auth()->user()->name, 0, 1) }}
|
|
</div>
|
|
<div class="min-w-0">
|
|
<p class="text-sm font-medium truncate">{{ auth()->user()->name }}</p>
|
|
<p class="text-xs text-slate-400">{{ auth()->user()->role->label() }}</p>
|
|
</div>
|
|
</div>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<button type="submit" class="w-full rounded-lg bg-slate-800 hover:bg-slate-700 px-3 py-2 text-sm transition">Выйти</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="lg:pl-72 min-h-full">
|
|
<header class="sticky top-0 z-30 border-b border-slate-200 bg-white/95 backdrop-blur">
|
|
<div class="flex items-center justify-between px-4 py-3 lg:px-8">
|
|
<button @click="sidebarOpen = !sidebarOpen" class="lg:hidden rounded-md border border-slate-300 px-3 py-2 text-sm">Меню</button>
|
|
<div class="text-sm text-slate-500">
|
|
{{ $breadcrumb ?? 'Рабочая область' }}
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<div x-data="{ open: false }" class="relative">
|
|
<button @click="open = !open" class="relative rounded-lg border border-slate-200 px-3 py-2 text-sm hover:bg-slate-50">
|
|
Уведомления
|
|
@if(auth()->user()->unreadNotifications()->count() > 0)
|
|
<span class="absolute -top-2 -right-2 bg-rose-500 text-white text-[10px] rounded-full min-w-[18px] h-[18px] px-1 flex items-center justify-center">
|
|
{{ auth()->user()->unreadNotifications()->count() }}
|
|
</span>
|
|
@endif
|
|
</button>
|
|
<div x-cloak x-show="open" @click.outside="open = false" class="absolute right-0 mt-2 w-96 rounded-xl border border-slate-200 bg-white shadow-xl p-3">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<p class="text-sm font-semibold">Последние уведомления</p>
|
|
<a href="{{ route('notifications.index') }}" class="text-xs text-slate-600">Все</a>
|
|
</div>
|
|
<div class="space-y-2 max-h-80 overflow-y-auto">
|
|
@forelse(auth()->user()->notifications()->latest()->limit(10)->get() as $notification)
|
|
<a href="{{ $notification->data['url'] ?? route('notifications.index') }}" class="block rounded-lg border border-slate-100 px-3 py-2 hover:bg-slate-50">
|
|
<p class="text-sm font-medium">{{ $notification->data['title'] ?? 'Уведомление' }}</p>
|
|
<p class="text-xs text-slate-500 mt-1">{{ $notification->data['message'] ?? '' }}</p>
|
|
</a>
|
|
@empty
|
|
<p class="text-sm text-slate-500">Новых уведомлений нет.</p>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<a href="{{ route('profile') }}" class="rounded-lg border border-slate-200 px-3 py-2 text-sm hover:bg-slate-50">Профиль</a>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="p-4 lg:p-8 space-y-4">
|
|
@if(session()->has('success'))
|
|
<div class="rounded-lg border border-emerald-200 bg-emerald-50 text-emerald-700 px-4 py-3 text-sm">{{ session('success') }}</div>
|
|
@endif
|
|
@if(session()->has('error'))
|
|
<div class="rounded-lg border border-rose-200 bg-rose-50 text-rose-700 px-4 py-3 text-sm">{{ session('error') }}</div>
|
|
@endif
|
|
|
|
{{ $slot }}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
@livewireScripts
|
|
@fluxScripts
|
|
@stack('scripts')
|
|
</body>
|
|
</html>
|