/
Codename-Nik
/
WebApp
Обзор
Документация
Войти
/
Codename-Nik
/
WebApp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
frontend/src/components/layout/AppLayout.vue
203 строки
6 KB
Nikolay Pokhodnya
first commit
03 ноя 2025, 19:47
03 ноя 2025, 19:47
a9fbdee
Код
Авторство
О чём код?
<template> <v-app> <v-layout> <v-navigation-drawer v-model="drawer" :rail="rail" permanent @click="rail = false" color="primary" :width="280" > <v-list density="comfortable" nav class="py-0"> <v-list-item class="px-4 py-6 bg-primary-darken-1"> <template v-slot:prepend> <v-icon icon="mdi-checkbox-marked-circle-outline" color="white" size="32"></v-icon> </template> <v-list-item-title class="text-h6 font-weight-bold text-white"> TaskFlow </v-list-item-title> </v-list-item> <v-list-item v-for="item in navItems" :key="item.value" :prepend-icon="item.icon" :title="item.title" :value="item.value" :to="item.to" active-class="primary-lighten-1" variant="flat" rounded="lg" class="mx-3 my-1" > <template v-slot:append v-if="item.value === 'team' && pendingInvitationsCount > 0"> <v-badge color="error" :content="pendingInvitationsCount" inline ></v-badge> </template> </v-list-item> </v-list> <template v-slot:append> <div class="pa-4"> <v-list density="compact" nav class="bg-transparent"> <v-list-item prepend-icon="mdi-cog" title="Настройки" value="settings" :to="{ name: 'settings' }" variant="text" rounded="lg" ></v-list-item> </v-list> </div> </template> </v-navigation-drawer> <v-app-bar color="surface" elevation="1" density="comfortable" > <template v-slot:prepend> <v-app-bar-nav-icon @click.stop="rail = !rail" variant="text" ></v-app-bar-nav-icon> </template> <v-app-bar-title class="text-h6 font-weight-medium"> {{ pageTitle }} </v-app-bar-title> <template v-slot:append> <v-btn icon variant="text" class="mr-2"> <v-icon>mdi-bell-outline</v-icon> <v-badge v-if="unreadCount > 0" color="error" :content="unreadCount" inline ></v-badge> </v-btn> <v-menu location="bottom end"> <template v-slot:activator="{ props }"> <v-btn variant="text" v-bind="props" class="px-2"> <v-avatar size="36" class="mr-2"> <v-img v-if="auth.user?.avatar" :src="auth.user.avatar" alt="Avatar" ></v-img> <v-icon v-else size="24">mdi-account-circle</v-icon> </v-avatar> <span class="text-body-1 font-weight-medium d-none d-sm-flex"> {{ getUserDisplayName }} </span> <v-icon class="ml-1">mdi-chevron-down</v-icon> </v-btn> </template> <v-list density="compact"> <v-list-item> <v-list-item-title class="font-weight-medium"> {{ auth.user?.first_name }} {{ auth.user?.last_name }} </v-list-item-title> <v-list-item-subtitle> @{{ auth.user?.username }} </v-list-item-subtitle> </v-list-item> <v-divider></v-divider> <v-list-item @click="goToProfile"> <template v-slot:prepend> <v-icon>mdi-account</v-icon> </template> <v-list-item-title>Профиль</v-list-item-title> </v-list-item> <v-list-item @click="logout"> <template v-slot:prepend> <v-icon>mdi-logout</v-icon> </template> <v-list-item-title>Выйти</v-list-item-title> </v-list-item> </v-list> </v-menu> </template> </v-app-bar> <v-main class="bg-grey-lighten-3"> <v-container fluid class="fill-height pa-6"> <slot></slot> </v-container> </v-main> </v-layout> <AppNotifications /> </v-app> </template> <script setup lang="ts"> import { ref, computed, onMounted } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useAuthStore } from '@/stores/auth' import AppNotifications from '@/components/AppNotifications.vue' const route = useRoute() const router = useRouter() const auth = useAuthStore() const drawer = ref(true) const rail = ref(false) const unreadCount = ref(0) const pendingInvitationsCount = ref(0) const navItems = [ { icon: 'mdi-view-dashboard', title: 'Дашборд', value: 'dashboard', to: { name: 'dashboard' } }, { icon: 'mdi-format-list-checks', title: 'Задачи', value: 'tasks', to: { name: 'tasks' } }, { icon: 'mdi-folder', title: 'Проекты', value: 'projects', to: { name: 'projects' } }, { icon: 'mdi-account-group', title: 'Команда', value: 'team', to: { name: 'team' } }, ] const pageTitle = computed(() => { const titles: { [key: string]: string } = { dashboard: 'Обзор', tasks: 'Задачи', projects: 'Проекты', team: 'Команда', settings: 'Настройки', profile: 'Профиль' } return titles[route.name as string] || 'TaskFlow' }) const getUserDisplayName = computed(() => { if (auth.user?.first_name) { return auth.user.first_name } return auth.user?.username || 'Пользователь' }) const goToProfile = () => { router.push({ name: 'profile' }) } const logout = () => { auth.logout() router.push({ name: 'login' }) } onMounted(() => { console.log('AppLayout mounted') }) </script> <style scoped> :deep(.v-list-item--active) { border-left: 3px solid rgb(var(--v-theme-primary)); } </style>