forked from verdnatura/salix-front
Pinned refactor
This commit is contained in:
parent
3fa5eb1726
commit
edf05bb7a9
|
@ -2,7 +2,7 @@
|
||||||
"editor.bracketPairColorization.enabled": true,
|
"editor.bracketPairColorization.enabled": true,
|
||||||
"editor.guides.bracketPairs": true,
|
"editor.guides.bracketPairs": true,
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.defaultFormatter": "johnsoncodehk.volar",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
||||||
"json.schemas": [
|
"json.schemas": [
|
||||||
|
@ -11,9 +11,6 @@
|
||||||
"url": "https://on.cypress.io/cypress.schema.json"
|
"url": "https://on.cypress.io/cypress.schema.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"[javascript]": {
|
|
||||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
|
||||||
},
|
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,9 @@ module.exports = configure(function (ctx) {
|
||||||
// 'line-awesome',
|
// 'line-awesome',
|
||||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||||
|
|
||||||
'roboto-font', // optional, you are not bound to it
|
'roboto-font',
|
||||||
'material-icons', // optional, you are not bound to it
|
'material-icons-outlined',
|
||||||
|
'material-symbols-outlined',
|
||||||
],
|
],
|
||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-build
|
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-build
|
||||||
|
|
|
@ -19,6 +19,11 @@ quasar.iconMapFn = (iconName) => {
|
||||||
cls: `icon-${name}`,
|
cls: `icon-${name}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cls: 'material-symbols-outlined',
|
||||||
|
content: iconName,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function responseError(error) {
|
function responseError(error) {
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<script setup>
|
|
||||||
// import { onMounted } from 'vue';
|
|
||||||
// import { useI18n } from 'vue-i18n';
|
|
||||||
// import { useNavigation } from 'src/stores/useNavigationStoreStore';
|
|
||||||
|
|
||||||
// const { t } = useI18n();
|
|
||||||
// const navigation = useNavigation();
|
|
||||||
|
|
||||||
// onMounted(() => {
|
|
||||||
// navigation.fetchPinned();
|
|
||||||
// });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
Test
|
|
||||||
<!-- {{ navigation.pinned }} -->
|
|
||||||
<!-- <q-menu-->
|
|
||||||
<!-- anchor="bottom left"-->
|
|
||||||
<!-- class="row q-pa-md q-col-gutter-lg"-->
|
|
||||||
<!-- max-width="350px"-->
|
|
||||||
<!-- max-height="400px"-->
|
|
||||||
<!-- v-if="navigation.favorites.value.length"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <div v-for="module of navigation.favorites.value" :key="module.title" class="row no-wrap q-pa-xs flex-item">-->
|
|
||||||
<!-- <q-btn-->
|
|
||||||
<!-- align="evenly"-->
|
|
||||||
<!-- padding="16px"-->
|
|
||||||
<!-- flat-->
|
|
||||||
<!-- stack-->
|
|
||||||
<!-- size="lg"-->
|
|
||||||
<!-- :icon="module.icon"-->
|
|
||||||
<!-- color="primary"-->
|
|
||||||
<!-- class="col-4 button"-->
|
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <div class="text-center text-primary button-text">-->
|
|
||||||
<!-- {{ t(`${module.name}.pageTitles.${module.title}`) }}-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-btn>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-menu>-->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!--<style lang="scss" scoped>-->
|
|
||||||
<!--.flex-item {-->
|
|
||||||
<!-- width: 100px;-->
|
|
||||||
<!--}-->
|
|
||||||
<!--.button {-->
|
|
||||||
<!-- width: 100%;-->
|
|
||||||
<!-- line-height: normal;-->
|
|
||||||
<!-- align-items: center;-->
|
|
||||||
<!--}-->
|
|
||||||
<!--.button-text {-->
|
|
||||||
<!-- font-size: 10px;-->
|
|
||||||
<!-- margin-top: 5px;-->
|
|
||||||
<!--}-->
|
|
||||||
<!--</style>-->
|
|
|
@ -1,15 +1,16 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import axios from 'axios';
|
||||||
|
import { onMounted, ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRole } from 'src/composables/useRole';
|
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
||||||
|
import { toLowerCamel } from 'src/filters';
|
||||||
import routes from 'src/router/modules';
|
import routes from 'src/router/modules';
|
||||||
import axios from 'axios';
|
import LeftMenuItem from './LeftMenuItem.vue';
|
||||||
|
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const role = useRole();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const navigation = useNavigationStore();
|
const navigation = useNavigationStore();
|
||||||
|
@ -21,9 +22,10 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function toLowerCamel(value) {
|
onMounted(async () => {
|
||||||
return value.charAt(0).toLowerCase() + value.slice(1);
|
await navigation.fetchPinned();
|
||||||
}
|
getRoutes();
|
||||||
|
});
|
||||||
|
|
||||||
function findMatches(search, item) {
|
function findMatches(search, item) {
|
||||||
const matches = [];
|
const matches = [];
|
||||||
|
@ -47,333 +49,146 @@ function addChildren(module, route, parent) {
|
||||||
const mainMenus = route.menus[props.source];
|
const mainMenus = route.menus[props.source];
|
||||||
const matches = findMatches(mainMenus, route);
|
const matches = findMatches(mainMenus, route);
|
||||||
for (const child of matches) {
|
for (const child of matches) {
|
||||||
addMenuItem(module, child, parent);
|
navigation.addMenuItem(module, child, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const pinnedItems = computed(() => {
|
||||||
function addMenuItem(module, route, parent) {
|
return items.value.filter((item) => item.isPinned);
|
||||||
const { meta } = route;
|
});
|
||||||
|
|
||||||
if (meta && meta.roles && role.hasAny(meta.roles) === false) return;
|
|
||||||
|
|
||||||
const item = {
|
|
||||||
name: route.name,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (meta) {
|
|
||||||
item.title = `${module}.pageTitles.${meta.title}`;
|
|
||||||
item.icon = meta.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.push(item);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = ref([]);
|
const items = ref([]);
|
||||||
if (props.source === 'main') {
|
function getRoutes() {
|
||||||
for (const module of navigation.modules) {
|
if (props.source === 'main') {
|
||||||
const moduleDef = routes.find((route) => toLowerCamel(route.name) === module);
|
const modules = Object.assign([], navigation.getModules().value);
|
||||||
|
for (const item of modules) {
|
||||||
const item = addMenuItem(module, moduleDef, items.value);
|
const moduleDef = routes.find((route) => toLowerCamel(route.name) === item.module);
|
||||||
const pinned = navigation.pinned.value;
|
|
||||||
if (pinned.contains(module)) {
|
|
||||||
item.isPinned = true
|
|
||||||
}
|
|
||||||
|
|
||||||
item.children = [];
|
item.children = [];
|
||||||
item.module = module;
|
|
||||||
|
|
||||||
if (!item) continue;
|
addChildren(item.module, moduleDef, item.children);
|
||||||
addChildren(module, moduleDef, item.children);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (props.source === 'card') {
|
items.value = modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.source === 'card') {
|
||||||
const currentRoute = route.matched[1];
|
const currentRoute = route.matched[1];
|
||||||
const currentModule = toLowerCamel(currentRoute.name);
|
const currentModule = toLowerCamel(currentRoute.name);
|
||||||
const moduleDef = routes.find((route) => toLowerCamel(route.name) === currentModule);
|
const moduleDef = routes.find((route) => toLowerCamel(route.name) === currentModule);
|
||||||
|
|
||||||
addChildren(currentModule, moduleDef, items.value);
|
addChildren(currentModule, moduleDef, items.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function togglePinned(moduleName, event) {
|
async function togglePinned(item, event) {
|
||||||
if (event.defaultPrevented) return;
|
if (event.defaultPrevented) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
await axios.post('StarredModules/toggleStarredModule', { moduleName });
|
const data = { moduleName: item.module };
|
||||||
navigation.togglePinned(moduleName);
|
const response = await axios.post('StarredModules/toggleStarredModule', data);
|
||||||
|
|
||||||
|
item.isPinned = false;
|
||||||
|
|
||||||
|
if (response.data && response.data.id) {
|
||||||
|
item.isPinned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigation.togglePinned(item.module);
|
||||||
|
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
message: t('globals.dataSaved'),
|
message: t('globals.dataSaved'),
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOpen(name) {
|
|
||||||
const { matched } = route;
|
|
||||||
|
|
||||||
return matched.some((item) => item.name === name);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-list padding>
|
<q-list padding>
|
||||||
<q-item-label v-if="$props.source === 'main'" header>
|
<template v-if="$props.source === 'main'">
|
||||||
{{ t('globals.favoriteModules') }}
|
<q-item-label header>
|
||||||
|
{{ t('globals.pinnedModules') }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<!-- <template v-for="item in items" :key="item.name">
|
<template v-for="item in pinnedItems" :key="item.name">
|
||||||
<template v-if="item.children">
|
<template v-if="item.children">
|
||||||
<q-expansion-item
|
<left-menu-item-group :item="item" group="pinnedModules" class="pinned">
|
||||||
group="itemGroup"
|
<template #side>
|
||||||
class="module"
|
|
||||||
active-class="text-primary"
|
|
||||||
:label="item.title"
|
|
||||||
:to="{ name: item.name }"
|
|
||||||
expand-separator
|
|
||||||
:default-opened="isOpen(item.name)"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon :name="item.icon"></q-icon>
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ t(item.title) }}</q-item-section>
|
|
||||||
<q-item-section side>
|
|
||||||
<div
|
|
||||||
@click="onToggleFavoriteModule(module.name, $event)"
|
|
||||||
class="row items-center"
|
|
||||||
v-if="module.name != 'dashboard'"
|
|
||||||
>
|
|
||||||
<q-icon name="vn:pin"></q-icon>
|
|
||||||
</div>
|
|
||||||
</q-item-section>
|
|
||||||
</template>
|
|
||||||
<template v-for="section in item.children" :key="section.name">
|
|
||||||
<q-item active-class="text-primary" :to="{ name: section.name }" clickable v-ripple>
|
|
||||||
<q-item-section avatar v-if="section.icon">
|
|
||||||
<q-icon :name="section.icon" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section avatar v-if="!item.icon">
|
|
||||||
<q-icon name="disabled_by_default" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ t(section.title) }}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-expansion-item>
|
|
||||||
</template>
|
|
||||||
<template v-if="!item.children">
|
|
||||||
<q-item active-class="text-primary" :to="{ name: item.name }" clickable v-ripple>
|
|
||||||
<q-item-section avatar v-if="item.icon">
|
|
||||||
<q-icon :name="item.icon" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section avatar v-if="!item.icon">
|
|
||||||
<q-icon name="disabled_by_default" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ t(item.title) }}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</template> -->
|
|
||||||
<q-separator />
|
|
||||||
<q-expansion-item :label="t('moduleIndex.allModules')">
|
|
||||||
<q-list padding>
|
|
||||||
<template v-for="item in items" :key="item.name">
|
|
||||||
<template v-if="item.children">
|
|
||||||
<q-expansion-item
|
|
||||||
group="itemGroup"
|
|
||||||
class="module"
|
|
||||||
active-class="text-primary"
|
|
||||||
:label="item.title"
|
|
||||||
:to="{ name: item.name }"
|
|
||||||
expand-separator
|
|
||||||
:default-opened="isOpen(item.name)"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon :name="item.icon"></q-icon>
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ t(item.title) }}</q-item-section>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-btn
|
<q-btn
|
||||||
@click="togglePinned(item.module, $event)"
|
v-if="item.isPinned === true"
|
||||||
|
@click="togglePinned(item, $event)"
|
||||||
|
icon="vn:pin_off"
|
||||||
|
size="xs"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
>
|
||||||
|
<q-tooltip>{{ t('components.leftMenu.removeFromPinned') }}</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-if="item.isPinned === false"
|
||||||
|
@click="togglePinned(item, $event)"
|
||||||
icon="vn:pin"
|
icon="vn:pin"
|
||||||
size="xs"
|
size="xs"
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
>
|
>
|
||||||
<q-tooltip>Pin this module to favorites</q-tooltip>
|
<q-tooltip>{{ t('components.leftMenu.addToPinned') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-item-section>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-for="section in item.children" :key="section.name">
|
</left-menu-item-group>
|
||||||
<q-item active-class="text-primary" :to="{ name: section.name }" clickable v-ripple>
|
|
||||||
<q-item-section avatar v-if="section.icon">
|
|
||||||
<q-icon :name="section.icon" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section avatar v-if="!item.icon">
|
|
||||||
<q-icon name="disabled_by_default" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ t(section.title) }}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
</template>
|
||||||
</q-expansion-item>
|
|
||||||
|
<left-menu-item v-if="!item.children" :item="item" />
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!item.children">
|
<q-separator />
|
||||||
<q-item active-class="text-primary" :to="{ name: item.name }" clickable v-ripple>
|
<q-expansion-item :label="t('moduleIndex.allModules')">
|
||||||
<q-item-section avatar v-if="item.icon">
|
<template v-for="item in items" :key="item.name">
|
||||||
<q-icon :name="item.icon" />
|
<template v-if="item.children">
|
||||||
</q-item-section>
|
<left-menu-item-group :item="item" group="modules">
|
||||||
<q-item-section avatar v-if="!item.icon">
|
<template #side>
|
||||||
<q-icon name="disabled_by_default" />
|
<q-btn
|
||||||
</q-item-section>
|
v-if="item.isPinned === true"
|
||||||
<q-item-section>{{ t(item.title) }}</q-item-section>
|
@click="togglePinned(item, $event)"
|
||||||
</q-item>
|
icon="vn:pin_off"
|
||||||
|
size="xs"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
>
|
||||||
|
<q-tooltip>{{ t('components.leftMenu.removeFromPinned') }}</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-if="item.isPinned === false"
|
||||||
|
@click="togglePinned(item, $event)"
|
||||||
|
icon="vn:pin"
|
||||||
|
size="xs"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
>
|
||||||
|
<q-tooltip>{{ t('components.leftMenu.addToPinned') }}</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
</left-menu-item-group>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</q-list>
|
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<!-- <template v-for="module in navigation.favorites.value" :key="module.title">-->
|
</template>
|
||||||
<!-- <div class="module" v-if="!module.children">-->
|
<template v-if="$props.source === 'card'">
|
||||||
<!-- <q-item-->
|
<template v-for="item in items" :key="item.name">
|
||||||
<!-- clickable-->
|
<left-menu-item v-if="!item.children" :item="item" />
|
||||||
<!-- v-ripple-->
|
</template>
|
||||||
<!-- active-class="text-primary"-->
|
</template>
|
||||||
<!-- :key="module.title"-->
|
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
|
||||||
<!-- v-if="!module.roles || !module.roles.length || hasAny(module.roles)"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-item-section avatar :if="module.icon">-->
|
|
||||||
<!-- <q-icon :name="module.icon" />-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${module.title}`) }}</q-item-section>-->
|
|
||||||
<!-- <q-item-section side>-->
|
|
||||||
<!-- <div @click="onToggleFavoriteModule(module.name, $event)" class="row items-center">-->
|
|
||||||
<!-- <q-icon name="vn:pin_off"></q-icon>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- </q-item>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
|
|
||||||
<!-- <template v-if="module.children">-->
|
|
||||||
<!-- <q-expansion-item-->
|
|
||||||
<!-- class="module"-->
|
|
||||||
<!-- active-class="text-primary"-->
|
|
||||||
<!-- :label="t(`${module.name}.pageTitles.${module.title}`)"-->
|
|
||||||
<!-- v-if="!module.roles || !module.roles.length || hasAny(module.roles)"-->
|
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <template #header>-->
|
|
||||||
<!-- <q-item-section avatar>-->
|
|
||||||
<!-- <q-icon :name="module.icon"></q-icon>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${module.title}`) }}</q-item-section>-->
|
|
||||||
<!-- <q-item-section side>-->
|
|
||||||
<!-- <div @click="onToggleFavoriteModule(module.name, $event)" class="row items-center">-->
|
|
||||||
<!-- <q-icon name="vn:pin_off"></q-icon>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- <template v-for="section in module.children" :key="section.title">-->
|
|
||||||
<!-- <q-item-->
|
|
||||||
<!-- clickable-->
|
|
||||||
<!-- v-ripple-->
|
|
||||||
<!-- active-class="text-primary"-->
|
|
||||||
<!-- :to="{ name: section.stateName }"-->
|
|
||||||
<!-- v-if="!section.roles || !section.roles.length || hasAny(section.roles)"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-item-section avatar :if="section.icon">-->
|
|
||||||
<!-- <q-icon :name="section.icon" />-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${section.title}`) }}</q-item-section>-->
|
|
||||||
<!-- </q-item>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </q-expansion-item>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
</q-list>
|
</q-list>
|
||||||
|
|
||||||
<!-- <q-expansion-item :label="t('moduleIndex.allModules')">-->
|
|
||||||
<!-- <q-list padding>-->
|
|
||||||
<!-- <template v-for="module in navigation.modules.value" :key="module.title">-->
|
|
||||||
<!-- <div class="module" v-if="!module.children">-->
|
|
||||||
<!-- <q-item-->
|
|
||||||
<!-- class="module"-->
|
|
||||||
<!-- clickable-->
|
|
||||||
<!-- v-ripple-->
|
|
||||||
<!-- active-class="text-primary"-->
|
|
||||||
<!-- :key="module.title"-->
|
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
|
||||||
<!-- v-if="!module.roles || !module.roles.length || hasAny(module.roles)"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-item-section avatar :if="module.icon">-->
|
|
||||||
<!-- <q-icon :name="module.icon" />-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${module.title}`) }}</q-item-section>-->
|
|
||||||
<!-- <q-item-section side>-->
|
|
||||||
<!-- <div-->
|
|
||||||
<!-- @click="onToggleFavoriteModule(module.name, $event)"-->
|
|
||||||
<!-- class="row items-center"-->
|
|
||||||
<!-- v-if="module.name != 'dashboard'"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-icon name="vn:pin"></q-icon>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- </q-item>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
|
|
||||||
<!-- <template v-if="module.children">-->
|
|
||||||
<!-- <q-expansion-item-->
|
|
||||||
<!-- class="module"-->
|
|
||||||
<!-- active-class="text-primary"-->
|
|
||||||
<!-- :label="t(`${module.name}.pageTitles.${module.title}`)"-->
|
|
||||||
<!-- v-if="!module.roles || !module.roles.length || hasAny(module.roles)"-->
|
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <template #header>-->
|
|
||||||
<!-- <q-item-section avatar>-->
|
|
||||||
<!-- <q-icon :name="module.icon"></q-icon>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${module.title}`) }}</q-item-section>-->
|
|
||||||
<!-- <q-item-section side>-->
|
|
||||||
<!-- <div-->
|
|
||||||
<!-- @click="onToggleFavoriteModule(module.name, $event)"-->
|
|
||||||
<!-- class="row items-center"-->
|
|
||||||
<!-- v-if="module.name != 'dashboard'"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-icon name="vn:pin"></q-icon>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- <template v-for="section in module.children" :key="section.title">-->
|
|
||||||
<!-- <q-item-->
|
|
||||||
<!-- clickable-->
|
|
||||||
<!-- v-ripple-->
|
|
||||||
<!-- active-class="text-primary"-->
|
|
||||||
<!-- :to="{ name: section.stateName }"-->
|
|
||||||
<!-- v-if="!section.roles || !section.roles.length || hasAny(section.roles)"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <q-item-section avatar :if="section.icon">-->
|
|
||||||
<!-- <q-icon :name="section.icon" />-->
|
|
||||||
<!-- </q-item-section>-->
|
|
||||||
<!-- <q-item-section>{{ t(`${module.name}.pageTitles.${section.title}`) }}</q-item-section>-->
|
|
||||||
<!-- </q-item>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </q-expansion-item>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- </q-list>-->
|
|
||||||
<!-- </q-expansion-item>-->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!--<style>-->
|
<style>
|
||||||
<!--.module .icon-pin,-->
|
.pinned .icon-pin,
|
||||||
<!--.module .icon-pin_off {-->
|
.pinned .icon-pin_off {
|
||||||
<!-- visibility: hidden;-->
|
visibility: hidden;
|
||||||
<!--}-->
|
}
|
||||||
<!--.module:hover .icon-pin,-->
|
|
||||||
<!--.module:hover .icon-pin_off {-->
|
.pinned:hover .icon-pin,
|
||||||
<!-- visibility: visible;-->
|
.pinned:hover .icon-pin_off {
|
||||||
<!--}-->
|
visibility: visible;
|
||||||
<!--</style>-->
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const item = computed(() => props.item);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-item active-class="text-primary" :to="{ name: item.name }" clickable v-ripple>
|
||||||
|
<q-item-section avatar v-if="item.icon">
|
||||||
|
<q-icon :name="item.icon" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar v-if="!item.icon">
|
||||||
|
<q-icon name="disabled_by_default" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>{{ t(item.title) }}</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import LeftMenuItem from './LeftMenuItem.vue';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const item = computed(() => props.item);
|
||||||
|
const isOpened = computed(() => {
|
||||||
|
const { matched } = route;
|
||||||
|
const { name } = item.value;
|
||||||
|
|
||||||
|
return matched.some((item) => item.name === name);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-expansion-item
|
||||||
|
:group="props.group"
|
||||||
|
active-class="text-primary"
|
||||||
|
:label="item.title"
|
||||||
|
:to="{ name: item.name }"
|
||||||
|
expand-separator
|
||||||
|
:default-opened="isOpened"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon :name="item.icon"></q-icon>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>{{ t(item.title) }}</q-item-section>
|
||||||
|
<q-item-section side>
|
||||||
|
<slot name="side" :item="item" />
|
||||||
|
</q-item-section>
|
||||||
|
</template>
|
||||||
|
<template v-for="section in item.children" :key="section.name">
|
||||||
|
<left-menu-item :item="section" />
|
||||||
|
</template>
|
||||||
|
</q-expansion-item>
|
||||||
|
</template>
|
|
@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import { useSession } from 'src/composables/useSession';
|
import { useSession } from 'src/composables/useSession';
|
||||||
import UserPanel from 'components/UserPanel.vue';
|
import UserPanel from 'components/UserPanel.vue';
|
||||||
import FavoriteModules from './FavoriteModules.vue';
|
import PinnedModules from './PinnedModules.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
@ -43,11 +43,11 @@ function onToggleDrawer() {
|
||||||
<q-space></q-space>
|
<q-space></q-space>
|
||||||
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
|
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
|
||||||
<div id="header-actions"></div>
|
<div id="header-actions"></div>
|
||||||
<q-btn id="favoriteModules" icon="apps" flat dense rounded>
|
<q-btn id="pinnedModules" icon="apps" flat dense rounded>
|
||||||
<q-tooltip bottom>
|
<q-tooltip bottom>
|
||||||
{{ t('globals.favoriteModules') }}
|
{{ t('globals.pinnedModules') }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
<FavoriteModules />
|
<PinnedModules />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn rounded dense flat no-wrap id="user">
|
<q-btn rounded dense flat no-wrap id="user">
|
||||||
<q-avatar size="lg">
|
<q-avatar size="lg">
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
||||||
|
|
||||||
|
const navigation = useNavigationStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
navigation.fetchPinned();
|
||||||
|
});
|
||||||
|
|
||||||
|
const pinnedModules = computed(() => navigation.getPinnedModules());
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-menu
|
||||||
|
anchor="bottom left"
|
||||||
|
class="row q-pa-md q-col-gutter-lg"
|
||||||
|
max-width="350px"
|
||||||
|
max-height="400px"
|
||||||
|
v-if="pinnedModules.length"
|
||||||
|
>
|
||||||
|
<div v-for="item of pinnedModules" :key="item.title" class="row no-wrap q-pa-xs flex-item">
|
||||||
|
<q-btn
|
||||||
|
align="evenly"
|
||||||
|
padding="16px"
|
||||||
|
flat
|
||||||
|
stack
|
||||||
|
size="lg"
|
||||||
|
:icon="item.icon"
|
||||||
|
color="primary"
|
||||||
|
class="col-4 button"
|
||||||
|
:to="{ name: item.name }"
|
||||||
|
>
|
||||||
|
<div class="text-center text-primary button-text">
|
||||||
|
{{ t(item.title) }}
|
||||||
|
</div>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</q-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.flex-item {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
width: 100%;
|
||||||
|
line-height: normal;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.button-text {
|
||||||
|
font-size: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -45,7 +45,7 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function updatePreferences() {
|
function updatePreferences() {
|
||||||
if (user.value.darkMode) {
|
if (user.value.darkMode !== null) {
|
||||||
darkMode.value = user.value.darkMode;
|
darkMode.value = user.value.darkMode;
|
||||||
}
|
}
|
||||||
if (user.value.lang) {
|
if (user.value.lang) {
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
// import routes from 'src/router/routes';
|
|
||||||
// import { ref } from 'vue';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
// const favorites = ref([]);
|
|
||||||
//const modules = ref([]);
|
|
||||||
|
|
||||||
// const mainRoute = routes.find((route) => route.path === '/');
|
|
||||||
// const moduleRoutes = (mainRoute && mainRoute.children) || [];
|
|
||||||
//
|
|
||||||
// for (const route of moduleRoutes) {
|
|
||||||
// const module = {
|
|
||||||
// stateName: route.name,
|
|
||||||
// name: route.name.toLowerCase(),
|
|
||||||
// roles: [],
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// if (route.meta) {
|
|
||||||
// Object.assign(module, route.meta);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (route.children && route.children.length) {
|
|
||||||
// const [moduleMain] = route.children;
|
|
||||||
// const routes = moduleMain.children;
|
|
||||||
//
|
|
||||||
// module.children = routes.map((route) => {
|
|
||||||
// const submodule = {
|
|
||||||
// stateName: route.name,
|
|
||||||
// name: route.name,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// Object.assign(submodule, route.meta);
|
|
||||||
//
|
|
||||||
// return submodule;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// modules.value.push(module);
|
|
||||||
// }
|
|
||||||
|
|
||||||
export function useNavigation() {
|
|
||||||
const modules = [
|
|
||||||
'customer',
|
|
||||||
'claim',
|
|
||||||
'ticket'
|
|
||||||
];
|
|
||||||
|
|
||||||
// const salixModules = {
|
|
||||||
// customer: 'Clients',
|
|
||||||
// claim: 'Claims',
|
|
||||||
// entry: 'Entries',
|
|
||||||
// invoiceIn: 'Invoices In',
|
|
||||||
// invoiceOut: 'Invoices Out',
|
|
||||||
// item: 'Items',
|
|
||||||
// monitor: 'Monitors',
|
|
||||||
// order: 'Orders',
|
|
||||||
// route: 'Routes',
|
|
||||||
// supplier: 'Suppliers',
|
|
||||||
// ticket: 'Tickets',
|
|
||||||
// travel: 'Travels',
|
|
||||||
// user: 'Users',
|
|
||||||
// worker: 'Workers',
|
|
||||||
// zone: 'Zones',
|
|
||||||
// };
|
|
||||||
|
|
||||||
// async function fetchFavorites() {
|
|
||||||
// const response = await axios.get('StarredModules/getStarredModules');
|
|
||||||
//
|
|
||||||
// const filteredModules = modules.value.filter((module) => {
|
|
||||||
// return response.data.find((element) => element.moduleFk == salixModules[module.name]);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// return (favorites.value = filteredModules);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
async function togglePinned(moduleName, event) {
|
|
||||||
if (event.defaultPrevented) return;
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
await axios.post('StarredModules/toggleStarredModule', { moduleName });
|
|
||||||
|
|
||||||
// updateFavorites(moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// function updateFavorites(name) {
|
|
||||||
// if (!favorites.value.find((module) => module.name == name)) {
|
|
||||||
// const newStarreModule = modules.value.find((module) => module.name == name);
|
|
||||||
// favorites.value.push(newStarreModule);
|
|
||||||
// } else {
|
|
||||||
// const moduleToRemove = favorites.value.find((module) => module.name == name);
|
|
||||||
// favorites.value.splice(favorites.value.indexOf(moduleToRemove), 1);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return { modules, togglePinned };
|
|
||||||
}
|
|
|
@ -2,9 +2,11 @@ import toLowerCase from './toLowerCase';
|
||||||
import toDate from './toDate';
|
import toDate from './toDate';
|
||||||
import toCurrency from './toCurrency';
|
import toCurrency from './toCurrency';
|
||||||
import toPercentage from './toPercentage';
|
import toPercentage from './toPercentage';
|
||||||
|
import toLowerCamel from './toLowerCamel';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
toLowerCase,
|
toLowerCase,
|
||||||
|
toLowerCamel,
|
||||||
toDate,
|
toDate,
|
||||||
toCurrency,
|
toCurrency,
|
||||||
toPercentage,
|
toPercentage,
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default function toLowerCamel(value) {
|
||||||
|
if (!value) return;
|
||||||
|
if (typeof (value) !== 'string') return value;
|
||||||
|
return value.charAt(0).toLowerCase() + value.slice(1);
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ export default {
|
||||||
backToDashboard: 'Return to dashboard',
|
backToDashboard: 'Return to dashboard',
|
||||||
notifications: 'Notifications',
|
notifications: 'Notifications',
|
||||||
userPanel: 'User panel',
|
userPanel: 'User panel',
|
||||||
favoriteModules: 'Favorite modules',
|
pinnedModules: 'Pinned modules',
|
||||||
darkMode: 'Dark mode',
|
darkMode: 'Dark mode',
|
||||||
logOut: 'Log out',
|
logOut: 'Log out',
|
||||||
dataSaved: 'Data saved',
|
dataSaved: 'Data saved',
|
||||||
|
@ -268,5 +268,9 @@ export default {
|
||||||
summary: 'Summary',
|
summary: 'Summary',
|
||||||
moreOptions: 'More options',
|
moreOptions: 'More options',
|
||||||
},
|
},
|
||||||
|
leftMenu: {
|
||||||
|
addToPinned: 'Add to pinned',
|
||||||
|
removeFromPinned: 'Remove from pinned',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default {
|
||||||
backToDashboard: 'Volver al tablón',
|
backToDashboard: 'Volver al tablón',
|
||||||
notifications: 'Notificaciones',
|
notifications: 'Notificaciones',
|
||||||
userPanel: 'Panel de usuario',
|
userPanel: 'Panel de usuario',
|
||||||
favoriteModules: 'Módulos favoritos',
|
pinnedModules: 'Módulos fijados',
|
||||||
darkMode: 'Modo oscuro',
|
darkMode: 'Modo oscuro',
|
||||||
logOut: 'Cerrar sesión',
|
logOut: 'Cerrar sesión',
|
||||||
dataSaved: 'Datos guardados',
|
dataSaved: 'Datos guardados',
|
||||||
|
@ -267,5 +267,9 @@ export default {
|
||||||
summary: 'Resumen',
|
summary: 'Resumen',
|
||||||
moreOptions: 'Más opciones',
|
moreOptions: 'Más opciones',
|
||||||
},
|
},
|
||||||
|
leftMenu: {
|
||||||
|
addToPinned: 'Añadir a fijados',
|
||||||
|
removeFromPinned: 'Eliminar de fijados',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
// import { useI18n } from 'vue-i18n';
|
import { onMounted, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import LeftMenu from 'components/LeftMenu.vue';
|
||||||
// import { useNavigation } from 'composables/useNavigation';
|
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
||||||
|
|
||||||
// const { t } = useI18n();
|
|
||||||
const state = useState();
|
const state = useState();
|
||||||
// const modules = useNavigation();
|
const navigation = useNavigationStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
navigation.fetchPinned();
|
||||||
|
});
|
||||||
|
|
||||||
|
const pinnedModules = computed(() => navigation.getPinnedModules());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -15,38 +22,34 @@ const state = useState();
|
||||||
<LeftMenu />
|
<LeftMenu />
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
<!-- <q-page-container>-->
|
<q-page-container>
|
||||||
<!-- <q-page class="q-pa-md">-->
|
<q-page class="q-pa-md">
|
||||||
<!-- <div class="row items-start wrap q-col-gutter-md q-mb-lg">-->
|
<div class="row items-start wrap q-col-gutter-md q-mb-lg">
|
||||||
<!-- <div class="col-12 col-md" v-if="modules.favorites.value.length">-->
|
<div class="col-12 col-md" v-if="pinnedModules.length">
|
||||||
<!-- <div class="text-h6 text-grey-8 q-mb-sm">{{ t('globals.favoriteModules') }}</div>-->
|
<div class="text-h6 text-grey-8 q-mb-sm">{{ t('globals.pinnedModules') }}</div>
|
||||||
<!-- <q-card class="row flex-container">-->
|
<q-card class="row flex-container">
|
||||||
<!-- <div-->
|
<div v-for="item of pinnedModules" :key="item.title" class="row no-wrap q-pa-xs flex-item">
|
||||||
<!-- v-for="module of modules.favorites.value"-->
|
<q-btn
|
||||||
<!-- :key="module.title"-->
|
align="evenly"
|
||||||
<!-- class="row no-wrap q-pa-xs flex-item"-->
|
padding="16px"
|
||||||
<!-- >-->
|
flat
|
||||||
<!-- <q-btn-->
|
stack
|
||||||
<!-- align="evenly"-->
|
size="lg"
|
||||||
<!-- padding="16px"-->
|
:icon="item.icon"
|
||||||
<!-- flat-->
|
color="orange-6"
|
||||||
<!-- stack-->
|
class="col-4 button"
|
||||||
<!-- size="lg"-->
|
:to="{ name: item.name }"
|
||||||
<!-- :icon="module.icon"-->
|
>
|
||||||
<!-- color="orange-6"-->
|
<div class="text-center text-primary button-text">
|
||||||
<!-- class="col-4 button"-->
|
{{ t(item.title) }}
|
||||||
<!-- :to="{ name: module.stateName }"-->
|
</div>
|
||||||
<!-- >-->
|
</q-btn>
|
||||||
<!-- <div class="text-center text-primary button-text">-->
|
</div>
|
||||||
<!-- {{ t(`${module.name}.pageTitles.${module.title}`) }}-->
|
</q-card>
|
||||||
<!-- </div>-->
|
</div>
|
||||||
<!-- </q-btn>-->
|
</div>
|
||||||
<!-- </div>-->
|
</q-page>
|
||||||
<!-- </q-card>-->
|
</q-page-container>
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </q-page>-->
|
|
||||||
<!-- </q-page-container>-->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,36 +1,84 @@
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
import { toLowerCamel } from 'src/filters';
|
||||||
|
import { useRole } from 'src/composables/useRole';
|
||||||
|
import routes from 'src/router/modules';
|
||||||
|
|
||||||
export const useNavigationStore = defineStore('navigationStore', () => {
|
export const useNavigationStore = defineStore('navigationStore', () => {
|
||||||
const modules = ['customer', 'claim', 'ticket'];
|
const modules = ['customer', 'claim', 'ticket'];
|
||||||
const pinned = ref([]);
|
const pinnedModules = ref([]);
|
||||||
|
const role = useRole();
|
||||||
|
|
||||||
onMounted(() => fetchPinned())
|
function getModules() {
|
||||||
|
const modulesRoutes = ref([]);
|
||||||
|
for (const module of modules) {
|
||||||
|
const moduleDef = routes.find((route) => toLowerCamel(route.name) === module);
|
||||||
|
|
||||||
|
const item = addMenuItem(module, moduleDef, modulesRoutes.value);
|
||||||
|
if (!item) continue;
|
||||||
|
|
||||||
|
item.module = module;
|
||||||
|
item.isPinned = false;
|
||||||
|
|
||||||
|
if (pinnedModules.value.includes(module)) {
|
||||||
|
item.isPinned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return modulesRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPinnedModules() {
|
||||||
|
const modules = getModules();
|
||||||
|
|
||||||
|
return modules.value.filter((item) => item.isPinned);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMenuItem(module, route, parent) {
|
||||||
|
const { meta } = route;
|
||||||
|
|
||||||
|
if (meta && meta.roles && role.hasAny(meta.roles) === false) return;
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
name: route.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (meta) {
|
||||||
|
item.title = `${module}.pageTitles.${meta.title}`;
|
||||||
|
item.icon = meta.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.push(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchPinned() {
|
async function fetchPinned() {
|
||||||
const response = await axios.get('StarredModules/getStarredModules');
|
if (pinnedModules.value.length) return;
|
||||||
// const filteredModules = modules.value.filter((module) => {
|
|
||||||
// return response.data.find((element) => element.moduleFk == salixModules[module.name]);
|
|
||||||
// });
|
|
||||||
|
|
||||||
return (pinned.value = response.data);
|
const response = await axios.get('StarredModules/getStarredModules');
|
||||||
|
pinnedModules.value = response.data.map((row) => row.moduleFk);
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePinned(module) {
|
function togglePinned(module) {
|
||||||
if (pinned.value.includes(module)) {
|
if (pinnedModules.value.includes(module)) {
|
||||||
const index = pinned.value.indexOf(module);
|
const index = pinnedModules.value.indexOf(module);
|
||||||
pinned.value.splice(index, 1);
|
pinnedModules.value.splice(index, 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinned.value.push(module);
|
pinnedModules.value.push(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modules,
|
modules,
|
||||||
pinned,
|
pinnedModules,
|
||||||
|
getModules,
|
||||||
|
getPinnedModules,
|
||||||
|
fetchPinned,
|
||||||
togglePinned,
|
togglePinned,
|
||||||
|
addMenuItem,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue