Files
web/app/components/TopMenu.vue
2026-04-15 09:43:11 +07:00

237 lines
8.1 KiB
Vue

<template>
<nav class="navbar has-shadow sticky px-3" style="top: 0" role="navigation">
<div class="navbar-brand mr-5">
<span class="navbar-item is-gap-1">
<div style="width: 16px; height: 16px" class="has-background-primary rounded-full"></div>
<span class="fs-17 font-semibold has-text-primary">{{ $dayjs().format('DD/MM') }}</span>
</span>
<a
class="navbar-item p-0 has-text-primary"
@click="changeTab(leftmenu[0])"
>
<svg
style="max-height: none; width: 44px"
width="80"
height="80"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M40.5 9C57.3447 9 71 22.6553 71 39.5C71 56.3447 57.3447 70 40.5 70C23.6553 70 10 56.3447 10 39.5C10 22.6553 23.6553 9 40.5 9ZM16 31V47.4404H19.4756V40.6494H26.5322V47.4404H30V31H26.5322V37.7832H19.4756V31H16ZM32.6396 47.4404H36.1162V41.6123H38.6533L41.7676 47.4404H45.6045L42.1143 41.0498C42.1644 41.028 42.2156 41.0094 42.2646 40.9863C43.1583 40.5689 43.8416 39.9698 44.3125 39.1885C44.7835 38.4018 45.0186 37.4619 45.0186 36.3701C45.0185 35.284 44.7857 34.3397 44.3203 33.5371C43.8601 32.7291 43.1886 32.1049 42.3057 31.666C41.428 31.2218 40.3676 31 39.126 31H32.6396V47.4404ZM47.249 47.4404H50.6201V36.6992H50.7568L55.0117 47.3604H57.3076L61.5625 36.7393H61.6982V47.4404H65.0703V31H60.7832L56.2559 42.0459H56.0635L51.5352 31H47.249V47.4404ZM38.46 33.8418C39.1289 33.8418 39.6832 33.9407 40.1221 34.1387C40.5661 34.3313 40.8953 34.6148 41.1094 34.9893C41.3288 35.3638 41.4384 35.8244 41.4385 36.3701C41.4385 36.9106 41.3288 37.3636 41.1094 37.7275C40.8953 38.0913 40.5686 38.364 40.1299 38.5459C39.6911 38.7278 39.14 38.8193 38.4766 38.8193H36.1162V33.8418H38.46Z" fill="currentColor"/>
</svg>
</a>
<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 is-gap-1 is-align-items-center" >
<template v-for="(v, i) in leftmenu" :key="i" :id="v.code">
<a class="navbar-item rounded-lg is-clipped p-0" v-if="!v.submenu" @click="changeTab(v)">
<span :class="[
'px-3 py-2 fs-14 font-medium',
currentTab.code === v.code ? 'has-text-primary-50 has-background-primary-95' : 'has-text-grey-30'
]">
{{ 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="[
'px-3 py-1 font-medium',
currentTab.code === v.code ? 'has-text-primary-bold has-background-primary-soft' : 'has-text-grey-30'
]">
<span>{{ 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 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 class="navbar-end">
<a class="navbar-item">
<div>
<p class="fs-13">Xin chào,</p>
<p class="fs-14 font-bold">Quản </p>
</div>
<Avatarbox text="Q" type="findata" size="two" />
</a>
</div>
</div>
</nav>
</template>
<script setup>
import Avatarbox from '@/components/common/Avatarbox.vue';
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);
// var menu = $filter($store.common, { category: "topmenu" });
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: 'orders',
vi: 'Đơn hàng',
link: null,
detail: {
base: 'Orders',
component: 'OrdersMaster',
},
index: 0,
},
{
id: 1,
category: 'topmenu',
classify: 'left',
code: 'inventory',
vi: 'Tồn kho',
link: null,
detail: {
base: 'Inventory',
component: 'InventoryMaster',
},
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
// })
var leftmenu = $filter(menu, {category: 'topmenu', classify: 'left'})
var currentTab = ref(leftmenu.length>0? leftmenu[0] : undefined)
var subTab = ref();
var tabConfig = $find(menu, { code: "configuration" });
var avatar = ref();
var 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>