hrms-admin/src/views/MainLayout.vue

831 lines
27 KiB
Vue
Raw Normal View History

2024-05-29 17:58:57 +07:00
<script setup lang="ts">
2024-07-01 09:19:17 +07:00
import { ref, onMounted, onUnmounted, watch } from "vue"
import keycloak from "@/plugins/keycloak"
import { useRoute } from "vue-router"
import { useDataStore } from "@/stores/data"
import { storeToRefs } from "pinia"
import { scroll, useQuasar } from "quasar"
import { useCounterMixin } from "@/stores/mixin"
import http from "@/plugins/http"
import config from "@/app.config"
import type { ScrollType, notiType, optionType } from "../interface/request/main/main"
import { menuList } from "../interface/request/main/main"
import checkPermission from "@/plugins/checkPermission"
2024-06-10 20:25:42 +07:00
// import { useroleUserDataStore } from "@/stores/roleUser";
2024-05-29 17:58:57 +07:00
2024-07-01 09:19:17 +07:00
const { setVerticalScrollPosition } = scroll
const store = useDataStore()
const route = useRoute()
const link = ref<string>("")
const mixin = useCounterMixin() //เรียกฟังก์ชันกลาง
const { showLoader, hideLoader, dialogRemove, success, messageError, date2Thai, dialogConfirm } = mixin
2024-06-10 20:25:42 +07:00
// const DataStore = useroleUserDataStore();
// const { fetchroleUser } = DataStore;
2024-05-29 17:58:57 +07:00
2024-07-01 09:19:17 +07:00
const id = ref<string>("")
const $q = useQuasar()
const { loader } = storeToRefs(store)
const { changeTab } = store
const miniState = ref<boolean>(false)
const drawerR = ref<boolean>(false)
const rightActive = ref<boolean>(false)
const resize = ref<number>(0)
const active = ref<number>(0)
const drawerL = ref<boolean>(false)
const fullname = ref<string>("")
const role = ref<string[]>([])
const notiTrigger = ref<boolean>(false)
const notiList = ref<notiType[]>([])
2024-05-29 17:58:57 +07:00
const options = ref<optionType[]>([
2024-07-01 09:19:17 +07:00
{
icon: "mdi-account-cog",
label: "ผู้ดูแลระบบ",
value: "op1",
color: "primary",
},
{
icon: "mdi-account-group",
label: "เจ้าหน้าที่",
value: "op2",
color: "blue",
},
{
icon: "mdi-account-circle",
label: "บุคคล",
value: "op3",
color: "indigo",
},
])
2024-05-29 17:58:57 +07:00
async function fetchmsgNoread() {
2024-07-01 09:19:17 +07:00
await http
.get(config.API.msgNoread())
.then((res) => {
totalNoti.value = res.data.result
})
.catch((err) => {
messageError($q, err)
})
2024-05-29 17:58:57 +07:00
}
2024-07-01 09:19:17 +07:00
const statusLoad = ref<boolean>(false)
2024-05-29 17:58:57 +07:00
const getDataNotification = async (index: number, type: string) => {
2024-07-01 09:19:17 +07:00
const thaiOptions: Intl.DateTimeFormatOptions = {
hour: "2-digit",
minute: "2-digit",
}
await http
.get(config.API.msgNotificate + `?page=${index}&pageSize=${10}`)
.then((res: any) => {
const response = res.data.result.data
totalInbox.value = res.data.result.total
let list: notiType[] = []
if (type === "DEL") {
notiList.value = []
}
response.map((e: any) => {
list.push({
id: e.id,
sender: e.createdFullName == "" || e.createdFullName == null ? "เจ้าหน้าที่"[0] : e.createdFullName[0],
body: e.body ?? "",
timereceive: `${date2Thai(e.receiveDate)} ${new Date(e.receiveDate).toLocaleTimeString("th-TH", thaiOptions)} น.`,
isOpen: e.isOpen,
})
})
notiList.value.push(...list)
statusLoad.value = totalInbox.value === 0 ? true : false
})
.catch((e) => {
messageError($q, e)
})
.finally(() => {})
}
2024-05-29 17:58:57 +07:00
/**
* toggleBtnRight มย ขยาย drawer ขวา
*/
const toggleBtnRight = () => {
2024-07-01 09:19:17 +07:00
drawerR.value = !drawerR.value
}
2024-05-29 17:58:57 +07:00
/**
* toggleBtnLeft มย ขยาย drawer าย เมอหนาจอ อถงขนาด 1024 px
* ปกตเปนการยอโดยใช Ministate
*/
const toggleBtnLeft = () => {
2024-07-01 09:19:17 +07:00
if (window.innerWidth < 1024) {
drawerL.value = !drawerL.value
} else {
miniState.value = !miniState.value
}
}
2024-05-29 17:58:57 +07:00
/**
* Event onScroll นำ ตำแหน top scroll
* ใช function updateScroll
*/
const onScroll = (scroll: ScrollType) => {
2024-07-01 09:19:17 +07:00
const { position } = scroll
2024-06-10 20:25:42 +07:00
2024-07-01 09:19:17 +07:00
updateScroll(position)
}
2024-05-29 17:58:57 +07:00
/**
* updateScroll เป function active แทปดานขวา
*/
const updateScroll = (position: number) => {
2024-07-01 09:19:17 +07:00
// เมื่อ position เป็น undifind ให้ position เป็น ตำแหน่ง top ที่ scroll
if (position === void 0) {
position = document.documentElement.scrollTop || document.body.scrollTop
}
let last
/**
* last ไมเทาก undifind
* ใช เซ active ใหเปนแทปส
* และใช scrollIntoView ายตำแหน activeโดยการเลอนไปหา
*/
if (last !== void 0) {
changeTab(last)
const tocEl = document.getElementById("tab--" + last)
if (tocEl) {
tocEl.scrollIntoView({ block: "nearest" })
}
}
}
2024-05-29 17:58:57 +07:00
/**
* ใหแสดง แทปดานขวา เมอเขาหน รายละเอยดทะเบยนประว และ rightActive เทาก true
*/
const activeBtn = () => {
2024-07-01 09:19:17 +07:00
return route.name == "registryDetail" && rightActive.value
}
2024-05-29 17:58:57 +07:00
/**
* เมอเรมตนโปรแกรมให event resize และ function myEventHandler
* set function myEventHandler เพราะ state งไมเซ , state เซทเม หนาจอเร ขยบหนาจอ
* เรมเขามา state rightActive เป state โชว มขวา
* งจ boolean งตอง set
*/
onMounted(async () => {
2024-07-01 09:19:17 +07:00
// if (keycloak.tokenParsed) {
// await fetchroleUser(keycloak.tokenParsed.role);
// }
await fetchmsgNoread()
// await getDataNotification(1, "NOMAL");
myEventHandler(null, false)
window.addEventListener("resize", (e: any) => {
myEventHandler(e, true)
})
})
2024-05-29 17:58:57 +07:00
/**
* เมอออกจากโปรแกรม ให ยกเลกการฟ event resize
*/
onUnmounted(() => {
2024-07-01 09:19:17 +07:00
window.removeEventListener("resize", (e: any) => {
myEventHandler(e, true)
})
})
2024-05-29 17:58:57 +07:00
/**
* @param e event ของ resize
* @param setSCroll เชความาจาก event หรอปาว
* set state resize = ความกวางหนาเว
* เมอความกวาง อยกว 1024( เทาก อยกว 1023) ให rightActive เป true แต rightActive true อยแลวไมอง set
* เมอความกวาง มากกวาหรอเทาก 1024 และเม rightActive เป true
* และ drawerR เป true ให rightActive เป true drawerR เป false ให rightActive เป false
* rightActive = true ; แสดงป drawer าน ขวา
* rightActive = false; ไมแสดงป drawer าน ขวา
*/
const myEventHandler = (e: any, setSCroll: boolean) => {
2024-07-01 09:19:17 +07:00
if (setSCroll) {
resize.value = e.target.innerWidth
} else {
resize.value = window.innerWidth
}
if (resize.value < 1024) {
if (!rightActive.value) {
rightActive.value = true
}
} else {
if (rightActive.value) {
if (drawerR.value) {
rightActive.value = true
} else {
rightActive.value = false
}
}
}
}
2024-05-29 17:58:57 +07:00
/**
* ตรวจสอบ path นๆ ายงอย path แมจะเป path child แทปกงจะ active อยเช
* ปกต path จะ active เม path นม ตรงตวมนเช /main
* แตจะไม active เม path child path /main/นๆ
* @param path string
*/
const activeMenu = (path: string) => {
2024-07-01 09:19:17 +07:00
const bool = route.name === path
2024-05-29 17:58:57 +07:00
2024-07-01 09:19:17 +07:00
return bool
}
2024-05-29 17:58:57 +07:00
/**
* logout keycloak
* confirm อนออกจากระบบ
*/
const doLogout = () => {
2024-07-01 09:19:17 +07:00
dialogConfirm(
$q,
() =>
keycloak.logout({
redirectUri: `${window.location.protocol}//${window.location.host}/`,
}),
"ยืนยันการออกจากระบบ",
"ต้องการออกจากระบบใช่หรือไม่?"
)
}
2024-05-29 17:58:57 +07:00
/**
* งชอผใชงานจาก keycloak
*/
if (keycloak.tokenParsed != null) {
2024-07-01 09:19:17 +07:00
fullname.value = keycloak.tokenParsed.name
role.value = keycloak.tokenParsed.role
2024-05-29 17:58:57 +07:00
}
const clickDelete = async (id: string, index: number) => {
2024-07-01 09:19:17 +07:00
dialogRemove($q, async () => {
showLoader()
await http
.delete(config.API.msgId(id))
.then(() => {
notiList.value.splice(index, 1)
success($q, "ลบข้อมูลสำเร็จ")
totalInbox.value--
})
.catch((e) => {
messageError($q, e)
})
.finally(async () => {
notiList.value.length === 7 && getDataNotification(1, "DEL")
hideLoader()
})
})
}
const totalInbox = ref<number>(0)
const totalNoti = ref<number>(0)
const page = ref<number>(0)
2024-05-29 17:58:57 +07:00
function onLoad(index: any, done: any) {
2024-07-01 09:19:17 +07:00
if (notiList.value.length < totalInbox.value || (notiList.value.length === 0 && totalInbox.value === 0)) {
page.value++
setTimeout(() => {
done()
getDataNotification(page.value, "NOMAL")
}, 1500)
}
}
const handleButtonClick = () => {
const currentPath = route.name
const queryParams = { role: "admin" } // Replace with your query parameters
const queryString = new URLSearchParams(queryParams).toString()
// Assuming config.generatePopupPath() returns a base URL
const popupBasePath = config.generatePopupPath(currentPath)
console.log(currentPath)
if (popupBasePath) {
const popupPath = `${popupBasePath}?${queryString}`
window.open(popupPath, "_blank") // Opens in a new tab/window
} else {
console.log("No manual available for this page:", currentPath)
}
2024-05-29 17:58:57 +07:00
}
watch(
2024-07-01 09:19:17 +07:00
() => notiTrigger.value,
() => {
if (!notiTrigger.value) {
const updatedNotifications = notiList.value.map((item) => ({
...item,
isOpen: true,
}))
notiList.value = updatedNotifications
fetchmsgNoread()
}
}
)
2024-05-29 17:58:57 +07:00
</script>
<!-- โครงเว -->
<template>
2024-07-01 09:19:17 +07:00
<!-- แบบเก design แรก -->
<!-- <q-layout view="lHh Lpr lff"> -->
<!-- ปรบใหบหน รายละเอยดทะเบยนประว -->
<q-layout view="lHh LpR lff" @scroll="onScroll">
<!-- header -->
<q-header flat class="bg-grey-2 text-dark" height-hint="7">
<q-toolbar style="padding: 0 2%">
<q-btn size="13px" class="bg-grey-3" flat dense round @click="toggleBtnLeft" aria-label="Menu">
<q-icon :name="miniState == false ? 'mdi-backburger' : 'mdi-menu-open'" size="20px" color="grey-7" />
</q-btn>
<q-space />
<!-- Search -->
<!-- <q-input dense rounded standout v-model="text" placeholder="ค้นหา">
2024-05-29 17:58:57 +07:00
<template v-slot:prepend>
<q-icon name="mdi-magnify" size="20px" color="grey-7" />
</template>
2024-07-01 09:19:17 +07:00
</q-input> -->
<!-- <q-btn class="bg-grey-3" flat dense round>
2024-05-29 17:58:57 +07:00
<q-icon name="mdi-magnify" size="20px" color="grey-7" />
</q-btn>
-->
2024-07-01 09:19:17 +07:00
<q-btn round dense flat size="13px" class="bg-grey-3" :color="totalNoti === 0 ? 'grey-6' : 'grey-8'" @click="handleButtonClick()" style="margin-right: 10px">
<q-icon name="mdi-book-open-variant" size="18px" color="grey-7" />
<q-tooltip></q-tooltip>
</q-btn>
<!-- Notification -->
2024-07-01 09:21:18 +07:00
<q-btn round dense flat size="13px" class="bg-grey-3" :color="totalNoti === 0 ? 'grey-6' : 'grey-8'">
2024-07-01 09:19:17 +07:00
<q-icon name="mdi-bell" size="18px" color="grey-7" />
<q-badge rounded color="negative" text-color="white" floating v-if="totalNoti !== 0">{{ totalNoti }}</q-badge>
<q-menu v-model="notiTrigger" :offset="[0, 8]" style="width: 480px">
<div class="q-px-md q-py-sm row col-12 items-center">
<div class="text-subtitle1 text-weight-medium">การแจงเตอน</div>
<q-space />
<div class="text-grey-5" style="font-size: 12px">งหมด {{ totalInbox }} อความ</div>
</div>
<q-infinite-scroll @load="onLoad" :offset="250" v-if="statusLoad === false">
<div v-for="(n, index) in notiList" :key="index" class="caption q-pa-xs">
<q-item v-ripple :class="!n.isOpen ? 'mytry q-py-xs my-menu-link' : 'mytry q-py-xs'" dense>
<q-item-section avatar top style="min-width: 40px">
<q-avatar color="primary" size="22px" text-color="white">
<span class="text-weight-medium text-uppercase">{{ n.body[0] }}</span>
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label caption class="text-black">{{ n.body }}</q-item-label>
<q-item-label caption class="row items-center text-grey-7">{{ n.timereceive }}</q-item-label>
</q-item-section>
<q-btn size="sm" unelevated dense icon="mdi-close" class="mybtn q-mx-xs" @click="clickDelete(n.id, index)"></q-btn>
</q-item>
</div>
<q-separator color="grey-2" />
<template v-slot:loading v-if="notiList.length < totalInbox || (notiList.length === 0 && totalInbox === 0)">
<div class="row justify-center q-my-md">
<q-spinner-dots color="primary" size="40px" />
</div>
</template>
</q-infinite-scroll>
<div class="q-pa-md" v-else>
<q-banner rounded class="bg-amber-1 text-center">
<div class="text-yellow-10">
<q-icon name="mdi-alert-box" class="q-mx-xs" size="sm" color="yellow-10" />
ไมมอม
</div>
</q-banner>
</div>
</q-menu>
</q-btn>
<div class="row items-center no-wrap">
<q-btn-dropdown size="md" dropdown-color="grey" flat>
<template v-slot:label>
<q-item v-close-popup class="q-pa-none">
<q-item-section :avatar="$q.screen.gt.xs">
<q-avatar color="grey-3">
<!-- <img src="https://cdn.quasar.dev/img/avatar.png" /> -->
<q-icon name="mdi-account" size="22px" color="grey-7" />
</q-avatar>
</q-item-section>
<q-item-section class="text-left gt-xs">
<q-item-label class="text-caption text-weight-medium">{{ fullname }}</q-item-label>
<!-- <q-item-label caption>เจาหนาท ..</q-item-label> -->
</q-item-section>
</q-item>
</template>
<div class="row justify-center" style="border-top: solid 3px #1bb19b !important; width: 273.797px">
<div class="column items-center col-12 q-py-md" color="grey-3">
<q-avatar size="72px" color="grey-4">
<q-icon name="mdi-account" color="grey-7" />
<!-- <img :src="require('@/assets/logo.png')" /> -->
</q-avatar>
<div class="text-subtitle2 q-mt-md q-mb-xs text-center">
{{ fullname }}
</div>
<div id="#logout"><q-btn color="primary" label="ออกจากระบบ" push size="sm" v-close-popup @click="doLogout" /><!-- --></div>
</div>
<div class="column col-12">
<q-separator />
<div class="column q-pb-md justify-center">
<div class="text-overline text-grey q-px-md q-pt-sm">เลอกโหมด</div>
<!-- <q-option-group v-model="group" :options="options" color="primary"/> -->
<q-list dense v-for="op in options" :key="op.label">
<q-item clickable>
<q-item-section avatar>
<q-avatar :color="op.color" text-color="white" :icon="op.icon" size="20px" font-size="12px" />
</q-item-section>
<q-item-section class="q-py-sm">{{ op.label }}</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div>
</q-btn-dropdown>
</div>
<q-btn size="13px" class="bg-blue-1" v-if="activeBtn()" flat dense round @click="toggleBtnRight" aria-label="Menu">
<q-icon name="mdi-menu" class="rotate-180" size="20px" color="blue" />
</q-btn>
</q-toolbar>
</q-header>
<!-- end header -->
<!-- drawer -->
<q-drawer side="left" class="text-white" style="background: #273238" v-model="drawerL" show-if-above :width="260" :breakpoint="1023" :mini="miniState">
<!-- วนของเมน mini -->
<template v-slot:mini>
<q-scroll-area class="fit mini-slot cursor-pointer">
<q-toolbar class="q-py-md">
<q-img src="@/assets/logo.png" spinner-color="white" style="height: 32px; max-width: 32px" />
</q-toolbar>
<q-separator color="grey-9" />
<!-- เมนอย ตอนย -->
<q-list padding>
<div v-for="(menuItem, index) in menuList" :key="index">
<!-- v-if="role.includes(menuItem.role)" -->
<div>
<q-item
clickable
v-ripple
:active="link === menuItem.label"
@click="link = menuItem.label"
active-class="text-primary menuActiveMini text-weight-medium"
v-if="
menuItem.key == 2 ||
menuItem.key == 0 ||
menuItem.key == 7 ||
menuItem.key == 8 ||
menuItem.key == 9 ||
menuItem.key == 10 ||
menuItem.key == 11 ||
menuItem.key == 12 ||
menuItem.key == 13 ||
menuItem.key == 14 ||
menuItem.key == 15 ||
menuItem.key == 16
"
>
<div class="row items-center no-wrap">
<q-icon :name="menuItem.icon" size="20px" class="q-ml-md" />
<q-icon name="mdi-dots-vertical" size="13px" color="grey-6" />
</div>
<q-tooltip anchor="center right" self="center left" :offset="[10, 10]">
{{ menuItem.label }}
</q-tooltip>
<q-menu anchor="top right" self="top left" :offset="[5, 0]" style="background: #273238; z-index: 9000">
<q-list class="text-white q-py-sm">
<div v-for="(subMenu, i) in menuItem.children" :key="i" :to="{ name: `${subMenu.path}` }">
<!-- เมนอย 2 -->
<div v-if="menuItem.key == 2 || menuItem.key == 7 || menuItem.key == 12 || menuItem.key == 13">
<q-item dense clickable v-if="subMenu.key !== 2.0 && subMenu.key !== 7.1 && subMenu.key !== 12.0 && subMenu.key !== 13.0">
<q-item-section>{{ subMenu.label }} </q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start" :offset="[5, 0]" style="background: #273238; z-index: 9000">
<q-list class="text-white q-py-sm">
<q-item
v-for="subMenu2 in subMenu.children"
:key="subMenu2.label"
:to="{ name: `${subMenu2.path}` }"
dense
class="q-pl-md text-body2"
active-class="text-primary active-item text-weight-medium"
clickable
>
<q-item-section>
<q-item-label>{{ subMenu2.label }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
<q-item v-else dense class="q-pl-md q-pr-xl text-body2" active-class="text-primary active-item text-weight-medium" clickable :to="{ name: `${subMenu.path}` }">
<q-item-section>
<q-item-label>{{ subMenu.label }}</q-item-label>
</q-item-section>
</q-item>
</div>
<!-- เมนอย 1 -->
<div v-else>
<q-item dense class="q-pl-md q-pr-xl text-body2" active-class="text-primary active-item text-weight-medium" clickable :to="{ name: `${subMenu.path}` }">
<q-item-section>
<q-item-label>{{ subMenu.label }}</q-item-label>
</q-item-section>
</q-item>
</div>
</div>
</q-list>
</q-menu>
</q-item>
<q-item clickable v-ripple :to="{ name: `${menuItem.path}` }" :active="link === menuItem.label" @click="link = menuItem.label" active-class="text-primary menuActiveMini" v-else>
<q-item-section avatar>
<q-avatar size="md" font-size="20px">
<q-icon :name="menuItem.icon" />
</q-avatar>
</q-item-section>
<q-tooltip anchor="center right" self="center left" :offset="[10, 10]">
{{ menuItem.label }}
</q-tooltip>
</q-item>
</div>
</div>
</q-list>
</q-scroll-area>
</template>
<!-- จบสวนของเมน mini -->
<!-- วนของเมน -->
<q-scroll-area class="fit">
<q-toolbar class="q-py-md">
<q-toolbar-title shrink class="row items-center no-wrap">
<q-img src="@/assets/logo.png" spinner-color="white" style="height: 40px; max-width: 40px" />
<div class="row q-ml-sm">
<div style="color: #ffffff; letter-spacing: 1px" class="text-body2 text-weight-bolder">ระบบ<span class="text-primary">บรหารทรพยากรบคคล</span></div>
<div class="text-caption text-white">ของกรงเทพมหานคร</div>
</div>
</q-toolbar-title>
</q-toolbar>
<q-separator inset color="grey-9" />
<q-list padding>
<div v-for="(menuItem, index) in menuList" :key="index">
<!-- เมนอย -->
<div v-if="checkPermission(menuItem.role)">
<q-expansion-item
group="somegroup"
class="menuSub"
expand-icon="mdi-chevron-down"
expanded-icon="mdi-chevron-up"
v-if="
menuItem.key == 2 ||
menuItem.key == 0 ||
menuItem.key == 7 ||
menuItem.key == 8 ||
menuItem.key == 9 ||
menuItem.key == 10 ||
menuItem.key == 11 ||
menuItem.key == 12 ||
menuItem.key == 13 ||
menuItem.key == 14 ||
menuItem.key == 15 ||
menuItem.key == 16
"
>
<template v-slot:header>
<q-item-section avatar>
<q-avatar :icon="menuItem.icon" size="md" font-size="20px" />
</q-item-section>
<q-item-section>{{ menuItem.label }}</q-item-section>
</template>
<!-- เมนอย 2 (สรรหา) -->
<div v-if="menuItem.key == 2 || menuItem.key == 7 || menuItem.key == 12 || menuItem.key == 13">
<div v-for="(subMenu, i) in menuItem.children" :key="i">
<q-expansion-item
switch-toggle-side
dense-toggle
:label="subMenu.label"
v-if="subMenu.key !== 2.0 && subMenu.key !== 7.1 && subMenu.key !== 12.0 && subMenu.key !== 13.0"
class="expan2"
dense
>
<q-item
dense
class="menuSubHover"
active-class="text-primary active-item text-weight-bold menuSubAct"
clickable
v-for="subMenu2 in subMenu.children"
:key="subMenu2.key"
:to="{ name: `${subMenu2.path}` }"
>
<q-item-section>
<q-item-label class="font-400 subLabel">{{ subMenu2.label }} </q-item-label>
</q-item-section>
</q-item>
</q-expansion-item>
<q-item v-else dense class="menuSubHover" active-class="text-primary active-item text-weight-bold menuSubAct" clickable :to="{ name: `${subMenu.path}` }">
<q-item-section>
<q-item-label>{{ subMenu.label }} </q-item-label>
</q-item-section>
</q-item>
</div>
</div>
<!-- เมนอย 1 -->
<q-item
v-else
dense
class="menuSubHover"
active-class="text-primary active-item text-weight-bold menuSubAct"
clickable
v-for="(subMenu, j) in menuItem.children"
:key="j"
:to="{ name: `${subMenu.path}` }"
>
<q-item-section>
<q-item-label class="font-400">{{ subMenu.label }}</q-item-label>
</q-item-section>
</q-item>
</q-expansion-item>
<!-- เมนปกต -->
<q-item
class="text-weight-medium menu"
:active="activeMenu(menuItem.path)"
active-class="text-primary active-item text-weight-bold menuActive"
:to="{ name: `${menuItem.path}` }"
clickable
v-ripple
dense
exact
v-else
>
<q-item-section avatar>
<q-avatar size="md" font-size="20px">
<q-icon :name="menuItem.key === active ? menuItem.activeIcon : menuItem.icon" />
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label>{{ menuItem.label }}</q-item-label>
</q-item-section>
</q-item>
</div>
</div>
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container class="bg-grey-2">
<q-page style="padding: 0 2%">
<router-view :key="$route.fullPath" />
</q-page>
</q-page-container>
<full-loader :visibility="loader" />
</q-layout>
2024-05-29 17:58:57 +07:00
</template>
<style>
.my-menu-link {
2024-07-01 09:19:17 +07:00
background: #ebf9f7 !important;
border-radius: 5px;
border: 1px solid #1bb19ab8;
color: #1bb19ab8 !important;
2024-05-29 17:58:57 +07:00
}
2024-07-01 09:19:17 +07:00
2024-05-29 17:58:57 +07:00
.menuSub .q-item__section--avatar,
.menu .q-item__section--avatar {
2024-07-01 09:19:17 +07:00
min-width: 0px;
2024-05-29 17:58:57 +07:00
}
.menu {
2024-07-01 09:19:17 +07:00
padding-bottom: 5px;
padding-top: 5px;
border-radius: 0 100px 100px 0;
margin-right: 2%;
2024-05-29 17:58:57 +07:00
}
.menuActive {
2024-07-01 09:19:17 +07:00
background: #212a2f;
border-radius: 0 100px 100px 0;
margin-right: 2%;
2024-05-29 17:58:57 +07:00
}
.menuActiveMini {
2024-07-01 09:19:17 +07:00
background: #212a2f;
2024-05-29 17:58:57 +07:00
}
.menuSub .q-item {
2024-07-01 09:19:17 +07:00
border-radius: 0 100px 100px 0;
margin-right: 2%;
font-weight: 500;
2024-05-29 17:58:57 +07:00
}
.expan2 .q-item {
2024-07-01 09:19:17 +07:00
padding-left: 10%;
2024-05-29 17:58:57 +07:00
}
.subLabel {
2024-07-01 09:19:17 +07:00
white-space: nowrap;
width: 160px;
overflow: hidden;
text-overflow: ellipsis;
2024-05-29 17:58:57 +07:00
}
.font-400 {
2024-07-01 09:19:17 +07:00
font-weight: 400;
2024-05-29 17:58:57 +07:00
}
.expan2 .menuSubHover {
2024-07-01 09:19:17 +07:00
padding-left: 30%;
border-radius: 20px;
2024-05-29 17:58:57 +07:00
}
.menuSubHover {
2024-07-01 09:19:17 +07:00
padding-left: 25%;
border-radius: 20px;
2024-05-29 17:58:57 +07:00
}
.menuSub .q-expansion-item__content {
2024-07-01 09:19:17 +07:00
background: #212a2f;
padding: 5px 0px;
margin-bottom: 5px;
2024-05-29 17:58:57 +07:00
}
.tabNative {
2024-07-01 09:19:17 +07:00
color: grey;
padding-left: 8%;
border-radius: 100px 0px 0px 100px;
2024-05-29 17:58:57 +07:00
}
.tabActive {
2024-07-01 09:19:17 +07:00
padding-left: 8%;
background: #e4f2ff;
border-radius: 100px 0px 0px 100px;
2024-05-29 17:58:57 +07:00
}
.q-card {
2024-07-01 09:19:17 +07:00
box-shadow: 3px 3px 20px -10px rgba(151, 150, 150, 0.261) !important;
2024-05-29 17:58:57 +07:00
}
.q-card--bordered {
2024-07-01 09:19:17 +07:00
border: 1px solid #ededed;
box-shadow: none !important;
2024-05-29 17:58:57 +07:00
}
.q-menu {
2024-07-01 09:19:17 +07:00
box-shadow: 3px 3px 10px 1px rgba(95, 95, 95, 0.15) !important;
2024-05-29 17:58:57 +07:00
}
.toptitle {
2024-07-01 09:19:17 +07:00
font-size: 1.2rem;
font-weight: bold;
margin-bottom: 1%;
2024-05-29 17:58:57 +07:00
}
.q-field--outlined .q-field__control {
2024-07-01 09:19:17 +07:00
border-radius: 5px;
2024-05-29 17:58:57 +07:00
}
.q-field--outlined .q-field__control:before {
2024-07-01 09:19:17 +07:00
border-color: #c8d3db;
2024-05-29 17:58:57 +07:00
}
.btnManu {
2024-07-01 09:19:17 +07:00
min-height: 48px;
border-radius: 0px 100px 100px 0px;
2024-05-29 17:58:57 +07:00
}
/* .q-field--outlined .q-icon {
color: #7474747f;
}
*/
.q-card__actions .q-btn--rectangle {
2024-07-01 09:19:17 +07:00
padding: 0 14px !important;
2024-05-29 17:58:57 +07:00
}
/* custom scrollbar */
::-webkit-scrollbar {
2024-07-01 09:19:17 +07:00
width: 12px;
height: 12px;
2024-05-29 17:58:57 +07:00
}
::-webkit-scrollbar-track {
2024-07-01 09:19:17 +07:00
background-color: transparent;
2024-05-29 17:58:57 +07:00
}
::-webkit-scrollbar-thumb {
2024-07-01 09:19:17 +07:00
background-color: #d6dee1;
border-radius: 20px;
border: 3px solid transparent;
background-clip: content-box;
2024-05-29 17:58:57 +07:00
}
::-webkit-scrollbar-thumb:hover {
2024-07-01 09:19:17 +07:00
background-color: #a8bbbf;
2024-05-29 17:58:57 +07:00
}
</style>