This commit is contained in:
Dede Fuji Abdul
2023-10-24 15:24:21 +07:00
parent 6931e06952
commit 96d8550cfe
9 changed files with 199 additions and 215 deletions

View File

@ -2,12 +2,9 @@
import { RouterView } from 'vue-router'
import { NotificationProvider } from '@/components/Notification'
import { useDialogStore } from '@/stores/dialog'
import ActionDialog from '@/components/Dialogs/ActionDialog.vue';
import CommandPalettes from '@/components/CommandPalettes.vue';
import { useCommandPalattesStore } from '@/stores/command';
import ActionDialog from '@/components/Dialogs/ActionDialog.vue'
import CommandPalettes from '@/components/CommandPalettes.vue'
const dialog = useDialogStore()
const command = useCommandPalattesStore()
</script>
<template>
@ -16,9 +13,7 @@ const command = useCommandPalattesStore()
:open="dialog.open" :title="dialog.title" :message="dialog.content" :confirm-text="dialog.confirmText"
:cancel-text="dialog.cancelText" @on-close="dialog.open = false" @on-confirm="dialog.onConfirm"
@on-cancel="dialog.onCancel" :type="dialog.type" />
<CommandPalettes :open="command.open" @onClose="command.handleOnDismissCommandPalettes" />
<CommandPalettes />
<RouterView />
</NotificationProvider>
</template>
<style scoped></style>
</template>

View File

@ -1,5 +1,5 @@
<template>
<TransitionRoot :show="open" as="template" @after-leave="onQueryChange('')" appear>
<TransitionRoot :show="command.open" as="template" @after-leave="onQueryChange('')" appear>
<Dialog as="div" class="relative z-10" @close="onClose">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100"
leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
@ -27,13 +27,14 @@
<li class="p-2" v-if="filteredMenus.length > 0 || recent.length > 0">
<h2 v-if="query === '' && recent.length > 0"
class="px-3 mt-4 mb-2 text-xs font-semibold text-gray-900">
Pencarian terakhir</h2>
Terakhir Diakses
</h2>
<ul class="text-sm text-gray-700">
<ComboboxOption as="template" v-for="menu in query === '' ? recent : filteredMenus"
:key="menu.href" v-slot="{ active }">
:key="menu.path" v-slot="{ active }">
<li @click="openMenu(menu)"
:class="['flex cursor-pointer select-none items-center rounded-md px-3 py-2', active && 'bg-gray-900 bg-opacity-5 text-gray-900']">
<component :is="menu.icon"
<DocumentTextIcon
:class="['h-6 w-6 flex-none text-gray-900 text-opacity-40', active && 'text-opacity-100']"
aria-hidden="true" />
<span class="flex-auto ml-3 truncate">
@ -69,7 +70,7 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { MagnifyingGlassIcon } from '@heroicons/vue/20/solid'
import { FolderIcon } from '@heroicons/vue/24/outline'
import { DocumentTextIcon } from '@heroicons/vue/24/outline'
import {
Combobox,
ComboboxInput,
@ -80,80 +81,28 @@ import {
TransitionChild,
TransitionRoot,
} from '@headlessui/vue'
import { useMenuStore } from '@/stores/menu';
import { useRouter } from 'vue-router';
import { useRouter, type RouteRecordRaw } from 'vue-router'
import { routes, extractLeafRoutes } from '@/router'
import { useCommandPalattesStore } from '@/stores/command'
// const menus = [
// { id: 1, name: 'Workflow Inc. / Website Redesign', url: '#' },
// ]
const nav = useMenuStore()
const menus = nav.navigation
// var recent = computed(() => readRecentMenu())
const props = defineProps({
open: Boolean
})
const emit = defineEmits(['onClose'])
function searchMenus(query: string) {
const result: typeof menus = []
menus.forEach((menu) => {
if (menu.children.length > 0) {
menu.children.forEach((child) => {
if (child.children.length > 0) {
child.children.forEach((grandChild) => {
if (grandChild.name.toLowerCase().includes(query.toLowerCase())) {
result.push(grandChild)
}
})
} else {
if (child.name.toLowerCase().includes(query.toLowerCase())) {
result.push(child)
}
}
})
} else {
if (menu.name.toLowerCase().includes(query.toLowerCase())) {
result.push(menu)
}
}
})
return result;
const command = useCommandPalattesStore()
const searchRoutesByName = (routes: RouteRecordRaw[], query: string): RouteRecordRaw[] => {
const matchingRoutes = extractLeafRoutes(routes, '').filter((item: RouteRecordRaw) => item.path.includes('home/') && item.name?.toString().toLocaleLowerCase().includes(query.toLocaleLowerCase()))
return matchingRoutes
}
const route = useRouter()
const recent = computed(() => query.value === '' ? readRecentMenu() : [])
const open = ref(props.open)
const recent = computed(() => query.value === '' ? command.readRecent() : [])
const query = ref('')
const filteredMenus = computed(() =>
query.value === ''
? []
: searchMenus(query.value)
: searchRoutesByName(routes, query.value)
)
const onClose = () => command.open = false
function onClose() {
open.value = false
emit('onClose')
}
function addMenuToRecent(menu: any) {
const lastRecent = readRecentMenu()
const index = lastRecent.findIndex((item: any) => item.href === menu.href)
if (index > -1) {
lastRecent.splice(index, 1)
}
lastRecent.unshift(menu)
if (lastRecent.length > 5) {
lastRecent.pop()
}
localStorage.setItem('recentmenu', JSON.stringify(lastRecent))
}
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
function onQueryChange(value: string) {
const onQueryChange = (value: string) => {
if (debounceTimeout) {
clearTimeout(debounceTimeout);
}
@ -164,25 +113,15 @@ function onQueryChange(value: string) {
return
}
query.value = value
const data = extractLeafRoutes(routes, '').filter((item: RouteRecordRaw) => item.path.includes('home/') && item.name?.toString().includes(value))
console.log(data)
}, 300);
}
function readRecentMenu() {
const recent = localStorage.getItem('recentmenu')
if (recent) {
return JSON.parse(recent)
}
return []
}
function openMenu(menu: typeof menus[0]) {
addMenuToRecent(menu)
const openMenu = (menu: RouteRecordRaw) => {
command.addRecent(menu)
route.push(menu.path)
onClose()
}
watch(() => props.open, (value) => {
open.value = value;
});
</script>

View File

@ -6,9 +6,9 @@ import LoginView from '@/views/LoginView.vue'
import NotFoundView from '@/views/NotFoundView.vue'
import EmptyPage from '@/components/Pages/HomeEmpty.vue'
import TestPage from '@/components/Pages/TestPage.vue'
import { hasMoreThanTwoSlashes, removeExtraSlashes } from '@/utils/route'
import qs from 'qs'
const routes: RouteRecordRaw[] = [
export const routes: RouteRecordRaw[] = [
{
path: '/home',
name: 'Home',
@ -24,7 +24,7 @@ const routes: RouteRecordRaw[] = [
name: 'Gangguan',
children: [
{
path: 'a',
path: 'daftar',
name: 'Daftar',
children: [
{
@ -65,7 +65,7 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: 'b',
path: 'rekapitulasi',
name: 'Rekapitulasi',
children: [
{
@ -147,7 +147,7 @@ const routes: RouteRecordRaw[] = [
name: 'Keluhan',
children: [
{
path: 'a',
path: 'daftar',
name: 'Daftar',
children: [
{
@ -188,7 +188,7 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: 'b',
path: 'rekapitulasi',
name: 'Rekapitulasi',
children: [
{
@ -240,11 +240,11 @@ const routes: RouteRecordRaw[] = [
name: 'Monalisa',
children: [
{
path: 'a',
path: 'gangguan',
name: 'Gangguan',
children: [
{
path: 'a',
path: 'rekapitulasi',
name: 'Rekapitulasi',
children: [
{
@ -254,31 +254,41 @@ const routes: RouteRecordRaw[] = [
},
{
path: '2',
name: 'Recovery Time (RCT) Gangguan',
name: 'Dispacthing Time (DT) Gangguan',
component: TestPage,
},
{
path: '3',
name: 'Response Time (RPT) Gangguan',
name: 'Recovery Time (RCT) Gangguan',
component: TestPage,
},
{
path: '4',
name: 'Rekapitulasi Gangguan Per Jenis Gangguan',
name: 'Response Time (RPT) Gangguan',
component: TestPage,
},
{
path: '5',
name: 'Rekapitulasi Lapor Ulang Gangguan',
name: 'Jumlah dan Durasi RPT RCT Gangguan',
component: TestPage,
},
{
path: '6',
name: 'Rekapitulasi ENS Gangguan',
name: 'Rekapitulasi Gangguan Per Jenis Gangguan',
component: TestPage,
},
{
path: '7',
name: 'Rekapitulasi Lapor Ulang Gangguan',
component: TestPage,
},
{
path: '8',
name: 'Rekapitulasi ENS Gangguan',
component: TestPage,
},
{
path: '9',
name: 'Rekapitulasi Gangguan Belum Selesai',
component: TestPage,
},
@ -287,11 +297,11 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: 'b',
path: 'keluhan',
name: 'Keluhan',
children: [
{
path: 'a',
path: 'rekapitulasi',
name: 'Rekapitulasi',
children: [
{
@ -311,16 +321,21 @@ const routes: RouteRecordRaw[] = [
},
{
path: '4',
name: 'Rekapitulasi Gangguan Per Jenis Keluhan',
name: 'Jumlah dan Durasi RPT RCT Keluhan',
component: TestPage,
},
{
path: '5',
name: 'Rekapitulasi Lapor Ulang Keluhan',
name: 'Rekapitulasi Gangguan Per Jenis Keluhan',
component: TestPage,
},
{
path: '6',
name: 'Rekapitulasi Lapor Ulang Keluhan',
component: TestPage,
},
{
path: '7',
name: 'Rekapitulasi Keluhan Belum Selesai',
component: TestPage,
},
@ -329,11 +344,11 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: 'c',
path: 'kpi',
name: 'Laporan KPI',
children: [
{
path: 'a',
path: 'bulanan',
name: 'Bulanan',
children: [
{
@ -359,7 +374,7 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: '2',
path: 'kumulatif',
name: 'Kumulatif',
children: [
{
@ -393,7 +408,7 @@ const routes: RouteRecordRaw[] = [
name: 'Check In OutCheck In Dan Check Out',
children: [
{
path: 'a',
path: 'laporan',
name: 'Laporan Check In /Check Out (CICO)',
children: [
{
@ -410,7 +425,7 @@ const routes: RouteRecordRaw[] = [
name: 'Anomali Penangan Pengaduan',
children: [
{
path: 'a',
path: 'gangguan',
name: 'Gangguan',
children: [
{
@ -426,7 +441,7 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: 'b',
path: 'keluhan',
name: 'Keluhan',
children: [
{
@ -463,50 +478,50 @@ const routes: RouteRecordRaw[] = [
},
]
// const createRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => {
// var newRoute: RouteRecordRaw[] = []
export const mergeChildrenRoutes = (routes: RouteRecordRaw[]): RouteRecordRaw[] => {
const mergedRoutes: RouteRecordRaw[] = [];
// const getRoute = (route: RouteRecordRaw[], parent: string = '') => {
// route.forEach((r) => {
// if (r.children) {
// if (r.component) {
// var fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}`
// fullPath = hasMoreThanTwoSlashes(fullPath) ? removeExtraSlashes(fullPath) : fullPath
// newRoute.push({
// path: fullPath,
// name: r.name,
// component: r.component
// } as RouteRecordRaw)
// }
// getRoute(r.children, `${parent}/${r.path}`)
// } else {
// var fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}`
// if (newRoute.find((nr) => nr.path !== '/' && nr.path === '/home' && fullPath.includes(nr.path))) {
// const index = newRoute.findIndex((nr) => nr.path !== '/' && fullPath.includes(nr.path))
// newRoute[index] = {
// ...newRoute[index], children: [...newRoute[index].children ?? [], {
// path: fullPath === '/home/' ? '' : fullPath.includes('/home/') ? fullPath.replace('/home/', '').split('/').join('-') : fullPath.split('/').join('-'),
// name: r.name,
// component: r.component
// } as RouteRecordRaw]
// }
// } else {
// newRoute.push({
// path: fullPath,
// name: r.name,
// component: r.component
// } as RouteRecordRaw)
// }
// }
// })
// }
// getRoute(route)
// console.log(newRoute);
for (const route of routes) {
if (route.children && route.children.length > 0) {
// Buat salinan route tanpa children
const topLevelRoute: RouteRecordRaw = { ...route, children: [] };
// return newRoute
// }
// Salin setiap route children ke children route paling atas
for (const childRoute of route.children) {
const fullPath = `${route.path}/${childRoute.path}`.replace(/\/+/g, '/');
const mergedChildRoute: RouteRecordRaw = { ...childRoute, path: fullPath };
topLevelRoute.children?.push(mergedChildRoute);
}
const createRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => {
mergedRoutes.push(topLevelRoute);
} else {
// Jika route tidak memiliki children, tambahkan as is
mergedRoutes.push(route);
}
}
return mergedRoutes;
}
export const extractLeafRoutes = (routes: RouteRecordRaw[], parentPath = ''): RouteRecordRaw[] => {
const leafRoutes: RouteRecordRaw[] = [];
for (const route of routes) {
const fullPath = `${parentPath}/${route.path}`.replace(/\/+/g, '/');
if (route.children && route.children.length > 0) {
leafRoutes.push(...extractLeafRoutes(route.children, fullPath));
} else {
const leafRoute = { ...route, path: fullPath };
leafRoutes.push(leafRoute);
}
}
return leafRoutes;
}
export const fixRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => {
var newRoute: RouteRecordRaw[] = []
const getRoute = (route: RouteRecordRaw[], parent: string = '') => {
@ -550,13 +565,13 @@ const createRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => {
return uniqueRoute
}
const router = createRouter({
history: createWebHistory(),
linkActiveClass: 'active',
routes: createRoute(routes)
stringifyQuery: qs.stringify,
routes: fixRoute(routes)
})
console.log(router.getRoutes());
router.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
@ -594,6 +609,3 @@ router.beforeEach((to, from, next) => {
})
export default router
export {
routes
}

View File

@ -1,7 +1,7 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { dispatchNotification } from '@/components/Notification'
import { readData, removeData, writeData } from './storage'
import { readData, removeData, writeData } from '@/utils/storage'
import router from '@/router'
export const useAuthStore = defineStore('auth', () => {

View File

@ -1,21 +1,23 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import type { RouteRecordRaw } from 'vue-router'
import { readDataJson, writeDataJson } from '@/utils/storage'
export const useCommandPalattesStore = defineStore('command_palettes', () => {
const open = ref(false);
const open = ref(false)
const controlStatus = ref(false)
const keyFStatus = ref(false)
function showCommandPalettes() {
const showCommandPalettes = () => {
open.value = true;
}
function handleOnDismissCommandPalettes() {
const handleOnDismissCommandPalettes = () => {
open.value = false;
}
function onKeyPressed(event: KeyboardEvent) {
const onKeyPressed = (event: KeyboardEvent) => {
if (event.key === 'Control') {
console.log('control pressed');
controlStatus.value = true
@ -31,7 +33,7 @@ export const useCommandPalattesStore = defineStore('command_palettes', () => {
}
}
function onKeyUp(event: KeyboardEvent) {
const onKeyUp = (event: KeyboardEvent) => {
if (event.key === 'Control') {
console.log('control released');
controlStatus.value = false
@ -43,5 +45,39 @@ export const useCommandPalattesStore = defineStore('command_palettes', () => {
}
}
return { open, showCommandPalettes, handleOnDismissCommandPalettes, onKeyPressed, onKeyUp }
const readRecent = (): RouteRecordRaw[] => {
const recent = readDataJson('recentmenu')
if (recent) {
try {
JSON.parse(recent)
} catch (error) {
return recent as RouteRecordRaw[]
}
}
return [] as RouteRecordRaw[]
}
const addRecent = (menu: RouteRecordRaw) => {
const lastRecent = readRecent()
const index = lastRecent.findIndex((item: RouteRecordRaw) => item.path === menu.path)
if (index > -1) {
lastRecent.splice(index, 1)
}
lastRecent.unshift(menu)
if (lastRecent.length > 5) {
lastRecent.pop()
}
writeDataJson('recentmenu', lastRecent)
}
return {
open,
showCommandPalettes,
handleOnDismissCommandPalettes,
onKeyPressed,
onKeyUp,
addRecent,
readRecent
}
})

View File

@ -30,26 +30,6 @@ const convertToDashedString = (input: string): string => {
return `/${parts.join('-')}`;
}
// export const convertRouteToMenu = (data: RouteRecordRaw[], basePath: string = '/home', iconIndex: number = 0): MenuItemModel[] => {
// return data.filter((i) => i.path !== '').map((item) => {
// const convertedItem: MenuItemModel = {
// name: item.name?.toString() || '',
// path: convertToDashedString(`${basePath}/${item.path}`).replace('/home-', '/home/'),
// expanded: false,
// icon: undefined,
// children: [],
// };
// if (item.children) {
// convertedItem.icon = navigationIcon[iconIndex];
// iconIndex = (iconIndex + 1) % navigationIcon.length;
// convertedItem.children = convertRouteToMenu(item.children, `${basePath}/${item.path}`, iconIndex);
// }
// return convertedItem
// })
// }
export const convertRouteToMenu = (data: RouteRecordRaw[], basePath: string = '/home', iconIndex: number = 0): MenuItemModel[] => {
return data.filter((i) => i.path !== '').map((item) => {
const convertedItem: MenuItemModel = {