2022-03-28 07:06:36 +00:00
|
|
|
<script setup>
|
2022-11-29 13:45:48 +00:00
|
|
|
import axios from 'axios';
|
2024-02-27 13:55:45 +00:00
|
|
|
import { onMounted, ref, reactive } from 'vue';
|
2022-03-15 09:33:28 +00:00
|
|
|
import { useI18n } from 'vue-i18n';
|
2023-04-11 11:31:03 +00:00
|
|
|
import { QSeparator, useQuasar } from 'quasar';
|
2022-11-24 06:21:45 +00:00
|
|
|
import { useRoute } from 'vue-router';
|
2022-11-29 06:10:04 +00:00
|
|
|
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
2022-11-29 13:45:48 +00:00
|
|
|
import { toLowerCamel } from 'src/filters';
|
2022-11-21 16:33:21 +00:00
|
|
|
import routes from 'src/router/modules';
|
2022-11-29 13:45:48 +00:00
|
|
|
import LeftMenuItem from './LeftMenuItem.vue';
|
|
|
|
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
|
2022-03-15 09:33:28 +00:00
|
|
|
|
|
|
|
const { t } = useI18n();
|
2022-11-24 06:21:45 +00:00
|
|
|
const route = useRoute();
|
2022-11-24 13:54:38 +00:00
|
|
|
const quasar = useQuasar();
|
2022-11-29 06:10:04 +00:00
|
|
|
const navigation = useNavigationStore();
|
2022-03-15 09:33:28 +00:00
|
|
|
|
2022-11-24 06:21:45 +00:00
|
|
|
const props = defineProps({
|
2022-11-21 16:33:21 +00:00
|
|
|
source: {
|
|
|
|
type: String,
|
|
|
|
default: 'main',
|
|
|
|
},
|
|
|
|
});
|
2022-03-15 09:33:28 +00:00
|
|
|
|
2024-02-27 13:55:45 +00:00
|
|
|
const expansionItemElements = reactive({});
|
|
|
|
|
2022-12-19 13:32:55 +00:00
|
|
|
onMounted(async () => {
|
|
|
|
await navigation.fetchPinned();
|
|
|
|
getRoutes();
|
2022-11-29 13:45:48 +00:00
|
|
|
});
|
2022-11-24 06:21:45 +00:00
|
|
|
|
|
|
|
function findMatches(search, item) {
|
|
|
|
const matches = [];
|
|
|
|
function findRoute(search, item) {
|
|
|
|
for (const child of item.children) {
|
2023-08-14 11:52:25 +00:00
|
|
|
if (search?.indexOf(child.name) > -1) {
|
2022-11-24 06:21:45 +00:00
|
|
|
matches.push(child);
|
|
|
|
} else if (child.children) {
|
|
|
|
findRoute(search, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
findRoute(search, item);
|
|
|
|
|
|
|
|
return matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addChildren(module, route, parent) {
|
|
|
|
if (route.menus) {
|
|
|
|
const mainMenus = route.menus[props.source];
|
|
|
|
const matches = findMatches(mainMenus, route);
|
2022-12-13 11:21:12 +00:00
|
|
|
|
2022-11-24 06:21:45 +00:00
|
|
|
for (const child of matches) {
|
2022-11-29 13:45:48 +00:00
|
|
|
navigation.addMenuItem(module, child, parent);
|
2022-11-24 06:21:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-13 11:21:12 +00:00
|
|
|
|
2022-11-24 06:21:45 +00:00
|
|
|
const items = ref([]);
|
2022-11-29 13:45:48 +00:00
|
|
|
function getRoutes() {
|
|
|
|
if (props.source === 'main') {
|
|
|
|
const modules = Object.assign([], navigation.getModules().value);
|
2022-12-13 11:21:12 +00:00
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
for (const item of modules) {
|
2023-04-11 11:31:03 +00:00
|
|
|
const moduleDef = routes.find(
|
|
|
|
(route) => toLowerCamel(route.name) === item.module
|
|
|
|
);
|
2022-11-29 13:45:48 +00:00
|
|
|
item.children = [];
|
2022-11-29 06:10:04 +00:00
|
|
|
|
2022-12-13 11:21:12 +00:00
|
|
|
if (!moduleDef) continue;
|
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
addChildren(item.module, moduleDef, item.children);
|
|
|
|
}
|
2022-11-24 06:21:45 +00:00
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
items.value = modules;
|
2022-11-21 16:33:21 +00:00
|
|
|
}
|
2022-11-24 06:21:45 +00:00
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
if (props.source === 'card') {
|
|
|
|
const currentRoute = route.matched[1];
|
|
|
|
const currentModule = toLowerCamel(currentRoute.name);
|
2023-04-11 11:31:03 +00:00
|
|
|
const moduleDef = routes.find(
|
|
|
|
(route) => toLowerCamel(route.name) === currentModule
|
|
|
|
);
|
2022-11-21 16:33:21 +00:00
|
|
|
|
2022-12-13 11:21:12 +00:00
|
|
|
if (!moduleDef) return;
|
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
addChildren(currentModule, moduleDef, items.value);
|
|
|
|
}
|
2022-03-15 09:33:28 +00:00
|
|
|
}
|
2022-11-24 06:21:45 +00:00
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
async function togglePinned(item, event) {
|
2022-11-29 06:10:04 +00:00
|
|
|
if (event.defaultPrevented) return;
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
|
2022-11-29 13:45:48 +00:00
|
|
|
const data = { moduleName: item.module };
|
|
|
|
const response = await axios.post('StarredModules/toggleStarredModule', data);
|
|
|
|
|
|
|
|
item.isPinned = false;
|
|
|
|
|
|
|
|
if (response.data && response.data.id) {
|
|
|
|
item.isPinned = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
navigation.togglePinned(item.module);
|
2022-11-21 16:33:21 +00:00
|
|
|
|
2022-11-24 13:54:38 +00:00
|
|
|
quasar.notify({
|
|
|
|
message: t('globals.dataSaved'),
|
|
|
|
type: 'positive',
|
|
|
|
});
|
2023-08-10 08:52:34 +00:00
|
|
|
}
|
2024-02-27 13:55:45 +00:00
|
|
|
|
|
|
|
const handleItemExpansion = (itemName) => {
|
|
|
|
expansionItemElements[itemName].scrollToLastElement();
|
|
|
|
};
|
2022-03-15 09:33:28 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2023-08-09 08:09:37 +00:00
|
|
|
<QList padding class="column-max-width">
|
2022-11-29 13:45:48 +00:00
|
|
|
<template v-if="$props.source === 'main'">
|
2023-08-18 12:13:49 +00:00
|
|
|
<template v-if="$route?.matched[1]?.name === 'Dashboard'">
|
2023-08-09 11:29:00 +00:00
|
|
|
<QItem class="header">
|
|
|
|
<QItemSection avatar>
|
|
|
|
<QIcon name="view_module" />
|
|
|
|
</QItemSection>
|
|
|
|
<QItemSection> {{ t('globals.modules') }}</QItemSection>
|
|
|
|
</QItem>
|
2023-08-09 07:43:24 +00:00
|
|
|
<QSeparator />
|
2023-08-09 11:29:00 +00:00
|
|
|
<template v-for="item in items" :key="item.name">
|
|
|
|
<template v-if="item.children">
|
|
|
|
<LeftMenuItem :item="item" group="modules">
|
|
|
|
<template #side>
|
|
|
|
<QBtn
|
|
|
|
v-if="item.isPinned === true"
|
|
|
|
@click="togglePinned(item, $event)"
|
|
|
|
icon="remove_circle"
|
|
|
|
size="xs"
|
|
|
|
flat
|
|
|
|
round
|
|
|
|
>
|
|
|
|
<QTooltip>
|
|
|
|
{{ t('components.leftMenu.removeFromPinned') }}
|
|
|
|
</QTooltip>
|
|
|
|
</QBtn>
|
|
|
|
<QBtn
|
|
|
|
v-if="item.isPinned === false"
|
|
|
|
@click="togglePinned(item, $event)"
|
|
|
|
icon="push_pin"
|
|
|
|
size="xs"
|
|
|
|
flat
|
|
|
|
round
|
|
|
|
>
|
|
|
|
<QTooltip>
|
|
|
|
{{ t('components.leftMenu.addToPinned') }}
|
|
|
|
</QTooltip>
|
|
|
|
</QBtn>
|
|
|
|
</template>
|
|
|
|
</LeftMenuItem>
|
|
|
|
</template>
|
2022-11-29 13:45:48 +00:00
|
|
|
</template>
|
2022-11-24 06:21:45 +00:00
|
|
|
</template>
|
2023-08-09 11:29:00 +00:00
|
|
|
|
2023-08-09 07:43:24 +00:00
|
|
|
<template v-for="item in items" :key="item.name">
|
2023-08-18 12:13:49 +00:00
|
|
|
<template v-if="item.name === $route?.matched[1]?.name">
|
2023-08-09 11:29:00 +00:00
|
|
|
<QItem class="header">
|
|
|
|
<QItemSection avatar v-if="item.icon">
|
|
|
|
<QIcon :name="item.icon" />
|
|
|
|
</QItemSection>
|
|
|
|
<QItemSection avatar v-if="!item.icon">
|
|
|
|
<QIcon name="disabled_by_default" />
|
|
|
|
</QItemSection>
|
|
|
|
<QItemSection>{{ t(item.title) }}</QItemSection>
|
|
|
|
<QItemSection side>
|
|
|
|
<slot name="side" :item="item" />
|
|
|
|
</QItemSection>
|
|
|
|
</QItem>
|
|
|
|
<QSeparator />
|
2022-11-24 13:54:38 +00:00
|
|
|
<template v-if="item.children">
|
2023-04-11 11:31:03 +00:00
|
|
|
<LeftMenuItemGroup :item="item" group="modules">
|
2022-11-29 13:45:48 +00:00
|
|
|
<template #side>
|
2023-04-11 11:31:03 +00:00
|
|
|
<QBtn
|
2022-11-29 13:45:48 +00:00
|
|
|
v-if="item.isPinned === true"
|
|
|
|
@click="togglePinned(item, $event)"
|
2023-05-09 12:05:36 +00:00
|
|
|
icon="remove_circle"
|
2022-11-29 13:45:48 +00:00
|
|
|
size="xs"
|
|
|
|
flat
|
|
|
|
round
|
|
|
|
>
|
2023-04-11 11:31:03 +00:00
|
|
|
<QTooltip>
|
|
|
|
{{ t('components.leftMenu.removeFromPinned') }}
|
|
|
|
</QTooltip>
|
|
|
|
</QBtn>
|
|
|
|
<QBtn
|
2022-11-29 13:45:48 +00:00
|
|
|
v-if="item.isPinned === false"
|
|
|
|
@click="togglePinned(item, $event)"
|
2023-05-09 12:05:36 +00:00
|
|
|
icon="push_pin"
|
2022-11-29 13:45:48 +00:00
|
|
|
size="xs"
|
|
|
|
flat
|
|
|
|
round
|
|
|
|
>
|
2023-04-11 11:31:03 +00:00
|
|
|
<QTooltip>
|
|
|
|
{{ t('components.leftMenu.addToPinned') }}
|
|
|
|
</QTooltip>
|
|
|
|
</QBtn>
|
2022-11-24 13:54:38 +00:00
|
|
|
</template>
|
2023-04-11 11:31:03 +00:00
|
|
|
</LeftMenuItemGroup>
|
2022-11-24 13:54:38 +00:00
|
|
|
</template>
|
|
|
|
</template>
|
2023-08-09 07:43:24 +00:00
|
|
|
</template>
|
2022-11-29 13:45:48 +00:00
|
|
|
</template>
|
|
|
|
<template v-if="$props.source === 'card'">
|
|
|
|
<template v-for="item in items" :key="item.name">
|
2023-04-11 11:31:03 +00:00
|
|
|
<LeftMenuItem v-if="!item.children" :item="item" />
|
2024-01-27 15:08:56 +00:00
|
|
|
<QList v-else>
|
|
|
|
<QExpansionItem
|
|
|
|
v-ripple
|
|
|
|
clickable
|
|
|
|
:icon="item.icon"
|
|
|
|
:label="t(item.title)"
|
2024-01-27 15:14:50 +00:00
|
|
|
:content-inset-level="0.5"
|
2024-02-27 13:55:45 +00:00
|
|
|
@after-show="handleItemExpansion(item.name)"
|
2024-01-27 15:08:56 +00:00
|
|
|
>
|
2024-02-27 13:55:45 +00:00
|
|
|
<LeftMenuItemGroup
|
|
|
|
:ref="(el) => (expansionItemElements[item.name] = el)"
|
|
|
|
:item="item"
|
|
|
|
/>
|
2024-01-27 15:08:56 +00:00
|
|
|
</QExpansionItem>
|
|
|
|
</QList>
|
2022-11-29 13:45:48 +00:00
|
|
|
</template>
|
|
|
|
</template>
|
2023-04-11 11:31:03 +00:00
|
|
|
</QList>
|
2022-05-17 12:58:01 +00:00
|
|
|
</template>
|
2022-06-08 12:53:10 +00:00
|
|
|
|
2023-08-10 08:52:34 +00:00
|
|
|
<style scoped>
|
2023-05-11 06:54:51 +00:00
|
|
|
.pinned .q-btn {
|
2022-11-29 13:45:48 +00:00
|
|
|
visibility: hidden;
|
|
|
|
}
|
|
|
|
|
2023-05-11 06:54:51 +00:00
|
|
|
.pinned:hover .q-btn {
|
2022-11-29 13:45:48 +00:00
|
|
|
visibility: visible;
|
|
|
|
}
|
2023-08-09 08:09:37 +00:00
|
|
|
.column-max-width {
|
|
|
|
max-width: 256px;
|
|
|
|
}
|
2023-08-09 11:29:00 +00:00
|
|
|
.header {
|
2024-03-19 10:15:54 +00:00
|
|
|
color: var(--vn-label-color);
|
2023-08-09 11:29:00 +00:00
|
|
|
}
|
2022-11-29 13:45:48 +00:00
|
|
|
</style>
|