93 lines
3.1 KiB
Vue
93 lines
3.1 KiB
Vue
<script setup>
|
|
import { useAuthStore } from "../../Stores/auth.js"
|
|
import { NFlex, NDropdown, NButton, NIcon, NText, NAvatar, NEl } from 'naive-ui'
|
|
import { TbChevronDown, TbCheck } from 'vue-icons-plus/tb'
|
|
import { computed, h } from "vue"
|
|
import { useForm } from "@inertiajs/vue3"
|
|
import { useThemeVars } from "naive-ui"
|
|
|
|
const authStore = useAuthStore()
|
|
const themeVars = useThemeVars()
|
|
|
|
const initials = computed(() => {
|
|
const parts = (authStore.user?.name ?? '').trim().split(/\s+/)
|
|
return parts.slice(0, 2).map(p => p[0]?.toUpperCase() ?? '').join('')
|
|
})
|
|
|
|
// Если активная роль не задана — берём дефолтную из списка
|
|
const effectiveRole = computed(() => {
|
|
if (authStore.user?.role.role_id) return authStore.user.role
|
|
return authStore.availableRoles?.find(r => r.is_default) ?? authStore.availableRoles?.[0] ?? null
|
|
})
|
|
|
|
const currentRoleId = computed(() => effectiveRole.value?.role_id ?? null)
|
|
const currentRoleName = computed(() => effectiveRole.value?.name ?? '')
|
|
const hasMultipleRoles = computed(() => (authStore.availableRoles?.length ?? 0) > 1)
|
|
|
|
const roleOptions = computed(() =>
|
|
authStore.availableRoles?.map(r => ({
|
|
label: r.name,
|
|
key: r.role_id,
|
|
icon: () => h(NIcon, {
|
|
size: 14,
|
|
style: r.role_id === currentRoleId.value ? '' : 'opacity: 0; pointer-events: none;',
|
|
}, () => h(TbCheck)),
|
|
})) ?? []
|
|
)
|
|
|
|
const formRole = useForm({ role_id: null })
|
|
|
|
const onSelectRole = (roleId) => {
|
|
if (roleId === currentRoleId.value) return
|
|
formRole.role_id = roleId
|
|
formRole.post('/user/role/change')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<NFlex align="center" :size="12" :wrap="false">
|
|
|
|
<!-- Переключатель роли -->
|
|
<NDropdown
|
|
v-if="hasMultipleRoles"
|
|
:options="roleOptions"
|
|
placement="bottom-end"
|
|
@select="onSelectRole"
|
|
>
|
|
<NButton
|
|
text
|
|
size="small"
|
|
icon-placement="right"
|
|
:loading="formRole.processing"
|
|
>
|
|
{{ currentRoleName }}
|
|
<template #icon>
|
|
<NIcon size="12"><TbChevronDown /></NIcon>
|
|
</template>
|
|
</NButton>
|
|
</NDropdown>
|
|
|
|
<NText v-else-if="currentRoleName" style="font-size: 13px;">
|
|
{{ currentRoleName }}
|
|
</NText>
|
|
|
|
<!-- Разделитель -->
|
|
<NEl :style="`width: 1px; height: 18px; background: ${themeVars.dividerColor};`" />
|
|
|
|
<!-- Аватар + имя -->
|
|
<NFlex align="center" :size="8" :wrap="false">
|
|
<NAvatar
|
|
round :size="28"
|
|
style="
|
|
color: var(--primary-color);
|
|
font-size: 11px; font-weight: 700; flex-shrink: 0;
|
|
"
|
|
>{{ initials }}</NAvatar>
|
|
<NText style="white-space: nowrap; max-width: 180px; overflow: hidden; text-overflow: ellipsis;">
|
|
{{ authStore.user?.name }}
|
|
</NText>
|
|
</NFlex>
|
|
|
|
</NFlex>
|
|
</template>
|