Files
hrm/app/components/TopMenu.vue
2026-04-06 15:53:14 +07:00

271 lines
7.1 KiB
Vue

<template>
<nav class="navbar is-fixed-top has-shadow px-3" role="navigation">
<div class="navbar-brand mr-5">
<span class="navbar-item">
<SvgIcon v-bind="{ name: 'dot.svg', size: 18, type: 'primary' }" />
<span class="fsb-20 has-text-primary">HRM</span>
</span>
<a
role="button"
class="navbar-burger"
id="burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
@click="handleClick()"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" id="navMenu">
<div class="navbar-start" style="min-width: 650px">
<template v-for="(v, i) in leftmenu" :key="i" :id="v.code">
<a class="navbar-item px-2" v-if="!v.submenu" @click="changeTab(v)">
<span
:class="`fs-15 ${currentTab.code === v.code ? 'activetab' : ''}`"
style="font-weight: 600; padding: 3px 4px"
>
{{ v[lang] }}
</span>
</a>
<div class="navbar-item has-dropdown is-hoverable" v-else>
<a class="navbar-item px-2" @click="changeTab(v)">
<span
:class="`icon-text ${currentTab.code === v.code ? 'activetab' : ''}`"
style="padding: 3px 4px"
>
<span class="fsb-16">{{ v[lang] }}</span>
<SvgIcon
style="padding-top: 5px"
v-bind="{
name: 'down2.svg',
type: currentTab.code === v.code ? 'white' : 'dark',
size: 15,
}"
>
</SvgIcon>
</span>
</a>
<div class="navbar-dropdown has-background-light">
<a
class="navbar-item has-background-light fs-15 has-text-black py-1 border-bottom"
v-for="x in v.submenu"
@click="changeTab(v, x)"
>
{{ x[lang] }}
</a>
</div>
</div>
</template>
</div>
<div class="navbar-end">
<a class="navbar-item" @click="changeTab(tabConfig)" v-if="tabConfig">
<SvgIcon
v-bind="{ name: 'configuration.svg', type: 'findata', size: 24 }"
></SvgIcon>
</a>
<a class="navbar-item" @click="openProfile()" v-if="avatar">
<Avatarbox v-bind="avatar"></Avatarbox>
</a>
</div>
</div>
</nav>
</template>
<script setup>
import { watch } from 'vue';
const router = useRouter();
const route = useRoute();
const emit = defineEmits(['changetab', 'langChanged']);
const { $find, $filter, $findIndex, $store } = useNuxtApp();
const lang = ref($store.lang);
// let menu = $filter($store.common, { category: 'topmenu' });
// console.log('menu', menu);
const menu = [
{
id: 1,
category: 'topmenu',
classify: 'left',
code: 'dashboard',
vi: 'Dashboard',
link: null,
detail: {
base: 'Dashboard',
component: 'DashboardMaster',
},
index: 0,
},
{
id: 2,
category: 'topmenu',
classify: 'left',
code: 'hrm',
vi: 'Quản lý nhân sự',
link: null,
detail: {
base: 'HRM',
component: 'HRMMaster',
},
index: 0,
},
{
id: 3,
category: 'topmenu',
classify: 'left',
code: 'rollcall',
vi: 'Chấm công',
link: null,
detail: {
base: 'Rollcall',
component: 'RollcallMaster',
},
index: 0,
},
{
id: 4,
category: 'topmenu',
classify: 'left',
code: 'salary',
vi: 'Tính lương',
link: null,
detail: {
base: 'Salary',
component: 'SalaryMaster',
},
index: 0,
},
{
id: 5,
category: 'topmenu',
classify: 'left',
code: 'kpi_efficiency',
vi: 'KPI & Hiệu suất',
link: null,
detail: {
base: 'Kpi',
component: 'KpiMaster',
},
index: 0,
},
{
id: 6,
category: 'topmenu',
classify: 'left',
code: 'employee',
vi: 'Cổng nhân viên',
link: null,
detail: {
base: 'Employee',
component: 'EmployeeMaster',
},
index: 0,
},
];
if ($store.rights.length > 0) {
menu = menu.filter((v) => $findIndex($store.rights, { setting: v.id }) >= 0);
}
if (menu.length === 0) {
$snackbar(
$store.lang === 'vi'
? 'Bạn không có quyền truy cập'
: 'You do not have permission to access.',
);
}
menu.map((v) => {
let arr = $filter($store.common, { category: 'submenu', classify: v.code });
if ($store.rights.length > 0) {
arr = arr.filter((x) => $findIndex($store.rights, { setting: x.id }) >= 0);
}
v.submenu = arr.length > 0 ? arr : null;
});
const leftmenu = $filter(menu, { category: 'topmenu', classify: 'left' });
let currentTab = ref(leftmenu.length > 0 ? leftmenu[0] : undefined);
const subTab = ref();
const tabConfig = $find(menu, { code: 'configuration' });
const avatar = ref();
const isAdmin = ref();
const handleClick = function () {
const target = document.getElementById('burger');
target.classList.toggle('is-active');
const target1 = document.getElementById('navMenu');
target1.classList.toggle('is-active');
};
const closeMenu = function () {
if (!document) return;
const target = document.getElementById('burger');
const target1 = document.getElementById('navMenu');
if (!target) return;
if (target.classList.contains('is-active')) {
target.classList.remove('is-active');
target1.classList.remove('is-active');
}
};
function changeTab(tab, subtab) {
if (tab.submenu && tab.submenu.length > 0 && !subtab && !tab.detail) {
subtab = tab.submenu[0];
}
currentTab.value = tab;
subTab.value = subtab;
emit('changetab', tab, subtab);
closeMenu();
let query = subtab
? { tab: tab.code, subtab: subtab.code }
: { tab: tab.code };
router.push({ query: query });
}
function openProfile() {
let modal = {
component: 'user/Profile',
width: '1100px',
height: '360px',
title: $store.lang === 'vi' ? 'Thông tin cá nhân' : '"User profile"',
};
$store.commit('showmodal', modal);
}
let found = route.query.tab
? $find(menu, { code: route.query.tab })
: undefined;
if (found || currentTab.value) changeTab(found || currentTab.value);
onMounted(() => {
if (!$store.login) return;
avatar.value = {
image: null,
text: $store.login.fullname.substring(0, 1).toUpperCase(),
size: 'two',
type: 'findata',
};
isAdmin.value = $store.login.type__code === 'admin';
});
watch(
() => $store.login,
(newVal, oldVal) => {
if (!newVal) return;
avatar.value = {
image: null,
text: $store.login.fullname.substring(0, 1).toUpperCase(),
size: 'two',
type: 'findata',
};
isAdmin.value = $store.login.type__code === 'admin';
lang.value = $store.lang;
},
);
</script>
<style scoped>
.navbar-dropdown {
padding-block: 0.375rem;
overflow: hidden;
}
.navbar-dropdown > .navbar-item {
&:hover {
background-color: hsl(30, 48%, 82%) !important;
}
&:last-child {
border-bottom: none;
}
}
</style>