Files
evening_detective_frontend/src/components/HeaderMenu.vue
T
2026-10-14 10:25:28 +07:00

271 lines
6.0 KiB
Vue

<script setup lang="ts">
import { MenuOutlined } from '@vicons/material'
import { Icon } from '@vicons/utils'
import { NTag, useMessage } from 'naive-ui'
import { storeToRefs } from 'pinia'
import { computed, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useUIStore } from '@/stores/ui'
const props = defineProps<{ active?: string }>()
const authStore = useAuthStore()
const router = useRouter()
const uiStore = useUIStore()
const message = useMessage()
const { permissions, environment, isLoadingEnvironment } = storeToRefs(uiStore)
const environmentLabel = computed(() => {
if (isLoadingEnvironment.value) return 'Среда: …'
if (environment.value === 'prod') return 'Сервер'
if (environment.value === 'venue') return 'Локальная сеть'
return 'Среда: ?'
})
watch(
() => authStore.user,
async () => {
try {
await uiStore.load()
} catch (err) {
message.error('Не удалось загрузить сведения сервера')
console.error('Failed to load server information:', err)
}
},
{ immediate: true },
)
function hasPermission(permission: string): boolean {
return permissions.value.includes(permission)
}
const goToLogin = () => {
router.push('/login')
}
const goToLogout = () => {
authStore.logout()
router.push('/login')
}
const openMenu = ref(false)
</script>
<template>
<div class="menu-block">
<button
type="button"
class="burger-button"
:aria-expanded="openMenu"
:aria-label="openMenu ? 'Закрыть меню' : 'Открыть меню'"
@click="openMenu = !openMenu"
>
<Icon class="burger-icon" size="28">
<MenuOutlined />
</Icon>
</button>
<div
class="left-group menu-buttons-block"
:class="!openMenu ? 'menu-buttons-block-active' : ''"
>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'main' }"
@click="router.push('/')"
>
Главная
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'office' }"
v-if="authStore.hasRole('user')"
@click="router.push('/office')"
>
Кабинет
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'games' }"
v-if="hasPermission('games_page')"
@click="router.push('/games')"
>
Игры
</button>
<button
v-if="authStore.isAuthenticated"
type="button"
class="menu-item-block"
@click="router.push('/screen')"
>
Экран
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'catalog' }"
@click="router.push('/catalog')"
>
Каталог
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'scenarios' }"
v-if="hasPermission('scenarios_page')"
@click="router.push('/scenarios')"
>
Сценарии
</button>
<button
v-if="hasPermission('tasks_page')"
type="button"
class="menu-item-block"
:class="{ active: props.active == 'tasks' }"
@click="router.push('/tasks')"
>
Задачи
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'users' }"
v-if="hasPermission('users_page')"
@click="router.push('/users')"
>
Пользователи
</button>
<button
type="button"
class="menu-item-block"
:class="{ active: props.active == 'reviews' }"
v-if="hasPermission('reviews_page')"
@click="router.push('/reviews')"
>
Отзывы
</button>
</div>
<div class="right-group">
<NTag
v-if="authStore.isAuthenticated"
size="small"
:type="environment === 'venue' ? 'warning' : 'default'"
:title="environment ? 'Среда подключённого сервера' : 'Среда сервера не определена'"
role="status"
>
{{ environmentLabel }}
</NTag>
<button
v-if="!authStore.isAuthenticated"
type="button"
class="menu-item-block right"
@click="goToLogin"
>
Войти
</button>
<button
v-if="authStore.isAuthenticated"
type="button"
class="menu-item-block right"
@click="goToLogout"
>
Выйти
</button>
</div>
</div>
</template>
<style scoped>
.menu-block {
align-items: center;
background-color: #222;
display: flex;
height: 70px;
justify-content: space-between;
left: 0;
padding: 20px;
position: fixed;
top: 0;
width: 100%;
z-index: 10;
}
.menu-item-block {
background: transparent;
border: 0;
color: inherit;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1.1em;
margin-left: 10px;
padding: 5px;
}
.menu-item-block:hover {
color: #63e2b7;
opacity: 0.8;
}
.right-group {
align-items: center;
display: flex;
flex-shrink: 0;
gap: 10px;
}
.right {
margin-left: auto;
}
.active {
color: #63e2b7;
}
.burger-button {
background: transparent;
border: 0;
color: inherit;
cursor: pointer;
padding: 0;
}
@media (width >=1024px) {
.burger-button {
display: none;
}
}
@media (width < 1024px) {
.menu-buttons-block {
background-color: #222;
display: flex;
flex-direction: column;
left: 0;
padding-bottom: 5px;
position: fixed;
top: 70px;
width: 100%;
}
.menu-buttons-block button {
padding: 15px 5px;
}
.menu-buttons-block-active {
position: relative;
top: -1000px;
}
.burger-icon {
position: relative;
top: 5px;
}
}
</style>