generated from VLADIMIR/template_frontend
271 lines
6.0 KiB
Vue
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>
|