ref #6248 breadcrumbs created #99
|
@ -7,6 +7,7 @@ import { useStateStore } from 'stores/useStateStore';
|
|||
import { useQuasar } from 'quasar';
|
||||
import PinnedModules from './PinnedModules.vue';
|
||||
import UserPanel from 'components/UserPanel.vue';
|
||||
import VnBreadCrumbs from './common/VnBreadCrumbs.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const session = useSession();
|
||||
|
@ -61,6 +62,7 @@ const pinnedModulesRef = ref();
|
|||
{{ appName }}
|
||||
<QBadge label="Beta" align="top" />
|
||||
</QToolbarTitle>
|
||||
<VnBreadCrumbs v-if="$q.screen.gt.xs" />
|
||||
<QSpace />
|
||||
<div id="searchbar" class="searchbar"></div>
|
||||
<QSpace />
|
||||
|
@ -112,6 +114,7 @@ const pinnedModulesRef = ref();
|
|||
<div id="actions-append"></div>
|
||||
</div>
|
||||
</QToolbar>
|
||||
<VnBreadCrumbs v-if="$q.screen.xs" class="q-ml-md" />
|
||||
</QHeader>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<script setup>
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useCamelCase } from 'src/composables/useCamelCase';
|
||||
|
||||
const router = useRouter();
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
let params = ref([]);
|
||||
let childRoutes = ref([]);
|
||||
let links = ref([]);
|
||||
let root = ref([]);
|
||||
let lastModel;
|
||||
|
||||
watchEffect(() => {
|
||||
lastModel = undefined;
|
||||
params.value = router.currentRoute.value.path
|
||||
.split('/')
|
||||
.filter((param) => param && isNaN(param));
|
||||
childRoutes.value = router.options.routes[1].children;
|
||||
root.value = params.value[0];
|
||||
setLinks(params);
|
||||
});
|
||||
|
||||
function setLinks(params) {
|
||||
links.value.length = 0;
|
||||
|
||||
if (params.value.includes('dashboard')) return;
|
||||
|
||||
for (let index in params.value) {
|
||||
const path =
|
||||
index < params.value.length - 1
|
||||
? '/' +
|
||||
params.value.filter((item, itemIndex) => itemIndex <= index).join('/')
|
||||
: undefined;
|
||||
links.value.push(getLink(params.value[index], path));
|
||||
}
|
||||
links.value.forEach((link) => {
|
||||
if (link) link.root = root;
|
||||
});
|
||||
}
|
||||
function getLink(param, path) {
|
||||
lastModel = getModel(param);
|
||||
if (!lastModel) return;
|
||||
|
||||
const { icon, title } = lastModel.meta;
|
||||
const breadcrumb = {
|
||||
icon,
|
||||
path,
|
||||
};
|
||||
|
||||
if (quasar.screen.gt.xs) {
|
||||
breadcrumb.name = param;
|
||||
breadcrumb.title = title;
|
||||
}
|
||||
|
||||
return breadcrumb;
|
||||
}
|
||||
|
||||
function getModel(param) {
|
||||
if (!lastModel)
|
||||
return childRoutes.value.find((child) => child.path.substring(1) == param);
|
||||
|
||||
let result = lastModel.children.find((child) => child.path == param);
|
||||
if (result) return result;
|
||||
|
||||
for (const child of lastModel.children) {
|
||||
if (child.children) {
|
||||
result = child.children.find((item) => item.path === param);
|
||||
if (result) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<QBreadcrumbs v-if="links.length && $q.screen.gt.xs" class="q-pa-xs">
|
||||
<QBreadcrumbsEl
|
||||
v-for="(link, index) of links"
|
||||
:key="index"
|
||||
:icon="link.icon"
|
||||
:label="
|
||||
t(`${useCamelCase(link.root)}.pageTitles.${useCamelCase(link.title)}`)
|
||||
"
|
||||
:to="link.path"
|
||||
/>
|
||||
</QBreadcrumbs>
|
||||
<QBreadcrumbs v-else class="q-pa-xs">
|
||||
<QBreadcrumbsEl
|
||||
v-for="(link, index) of links"
|
||||
:key="index"
|
||||
:icon="link.icon"
|
||||
:to="link.path"
|
||||
/>
|
||||
</QBreadcrumbs>
|
||||
</template>
|
||||
<style scoped></style>
|
|
@ -105,7 +105,11 @@ async function search() {
|
|||
class="cursor-pointer"
|
||||
/>
|
||||
|
||||
<QIcon v-if="props.info" name="info" class="cursor-info">
|
||||
<QIcon
|
||||
v-if="props.info && $q.screen.gt.xs"
|
||||
name="info"
|
||||
class="cursor-info"
|
||||
>
|
||||
<QTooltip>{{ props.info }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export function useCamelCase(value) {
|
||||
return value.replace(/[-_](.)/g, (_, char) => char.toUpperCase());
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export function useFirstUpper(str) {
|
||||
return str && str.charAt(0).toUpperCase() + str.substr(1);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useRoute } from 'vue-router';
|
||||
import LeftMenu from 'components/LeftMenu.vue';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
<template>
|
||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
||||
<QScrollArea class="fit">
|
||||
<QSeparator />
|
||||
<LeftMenu source="card" />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<QPageContainer>
|
||||
<QPage>
|
||||
<div class="q-pa-md"><RouterView></RouterView></div>
|
||||
</QPage>
|
||||
</QPageContainer>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Search customer: Buscar cliente
|
||||
You can search by customer id or name: Puedes buscar por id o nombre del cliente
|
||||
</i18n>
|
|
@ -0,0 +1,26 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useRoute } from 'vue-router';
|
||||
import LeftMenu from 'components/LeftMenu.vue';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
<template>
|
||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
||||
<QScrollArea class="fit">
|
||||
<QSeparator />
|
||||
<LeftMenu source="card" />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
|
||||
<div><RouterView></RouterView></div>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Search customer: Buscar cliente
|
||||
You can search by customer id or name: Puedes buscar por id o nombre del cliente
|
||||
</i18n>
|
|
@ -21,13 +21,13 @@ export default {
|
|||
redirect: { name: 'CmrList' },
|
||||
children: [
|
||||
{
|
||||
path: 'cmr/list',
|
||||
path: 'cmr',
|
||||
name: 'CmrList',
|
||||
meta: {
|
||||
title: 'cmrsList',
|
||||
icon: 'fact_check',
|
||||
},
|
||||
component: () => import('src/pages/Route/Cmr/CmrList.vue')
|
||||
component: () => import('src/pages/Route/Cmr/CmrList.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -11,11 +11,11 @@ export default {
|
|||
redirect: { name: 'WagonMain' },
|
||||
menus: {
|
||||
main: ['WagonList', 'WagonTypeList'],
|
||||
card: [],
|
||||
card: ['WagonEdit'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/wagon',
|
||||
path: '',
|
||||
name: 'WagonMain',
|
||||
component: () => import('src/pages/Wagon/WagonMain.vue'),
|
||||
redirect: { name: 'WagonList' },
|
||||
|
@ -27,7 +27,7 @@ export default {
|
|||
title: 'wagonsList',
|
||||
icon: 'vn:trolley',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/WagonList.vue')
|
||||
component: () => import('src/pages/Wagon/WagonList.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
|
@ -36,53 +36,78 @@ export default {
|
|||
title: 'wagonCreate',
|
||||
icon: 'create',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/WagonCreate.vue')
|
||||
component: () => import('src/pages/Wagon/WagonCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
path: 'type',
|
||||
name: 'WagonTypeMain',
|
||||
meta: {
|
||||
title: 'typesList',
|
||||
icon: 'view_list',
|
||||
},
|
||||
redirect: { name: 'WagonTypeList' },
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'WagonTypeList',
|
||||
meta: {
|
||||
title: 'typesList',
|
||||
icon: 'view_list',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/Wagon/Type/WagonTypeList.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'WagonTypeCreate',
|
||||
meta: {
|
||||
title: 'typeCreate',
|
||||
icon: 'create',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/Wagon/Type/WagonTypeCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'WagonTypeCard',
|
||||
component: () =>
|
||||
import('src/pages/Wagon/Type/Card/WagonTypeCard.vue'),
|
||||
redirect: { name: 'WagonTypeEdit' },
|
||||
children: [
|
||||
{
|
||||
path: 'edit',
|
||||
name: 'WagonTypeEdit',
|
||||
meta: {
|
||||
title: 'typeEdit',
|
||||
icon: 'edit',
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Wagon/Type/WagonTypeCreate.vue'
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'WagonCard',
|
||||
path: ':id',
|
||||
component: () => import('src/pages/Wagon/Card/WagonCard.vue'),
|
||||
redirect: { name: 'WagonEdit' },
|
||||
children: [
|
||||
{
|
||||
path: 'edit',
|
||||
name: 'WagonEdit',
|
||||
meta: {
|
||||
title: 'wagonEdit',
|
||||
icon: 'edit',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/WagonCreate.vue')
|
||||
component: () => import('src/pages/Wagon/WagonCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/wagon/type',
|
||||
name: 'WagonTypeMain',
|
||||
component: () => import('src/pages/Wagon/WagonMain.vue'),
|
||||
redirect: { name: 'WagonTypeList' },
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'WagonTypeList',
|
||||
meta: {
|
||||
title: 'typesList',
|
||||
icon: 'view_list',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/Type/WagonTypeList.vue')
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'WagonTypeCreate',
|
||||
meta: {
|
||||
title: 'typeCreate',
|
||||
icon: 'create',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue')
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
name: 'WagonTypeEdit',
|
||||
meta: {
|
||||
title: 'typeEdit',
|
||||
icon: 'edit',
|
||||
},
|
||||
component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue')
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
};
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('VnBreadCrumbs', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('should not be breadcrumbs', () => {
|
||||
cy.get('.q-breadcrumbs').should('not.exist');
|
||||
});
|
||||
it('should get the correct breadcrumbs', () => {
|
||||
cy.get('[href="#/customer"]').click();
|
||||
cy.get('.q-breadcrumbs .q-breadcrumbs--last').should('have.length', 1);
|
||||
cy.get('.q-breadcrumbs .q-breadcrumbs--last').contains('Clientes');
|
||||
cy.get('.q-infinite-scroll > :nth-child(1)').click();
|
||||
cy.get('.q-breadcrumbs .q-breadcrumbs__el').should('have.length', 2);
|
||||
cy.get('.q-breadcrumbs .q-breadcrumbs__el').eq(1).contains('Resumen');
|
||||
});
|
||||
});
|
|
@ -8,17 +8,17 @@ describe('WorkerList', () => {
|
|||
it('should load workers', () => {
|
||||
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
|
||||
.eq(0)
|
||||
.should('have.text', 'victorvd');
|
||||
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
|
||||
.eq(1)
|
||||
.should('have.text', 'JessicaJones');
|
||||
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
|
||||
.eq(2)
|
||||
.eq(1)
|
||||
.should('have.text', 'BruceBanner');
|
||||
cy.get('.card-list-body > .list-items > :nth-child(2) > .value > span')
|
||||
.eq(2)
|
||||
.should('have.text', 'CharlesXavier');
|
||||
});
|
||||
|
||||
it('should open the worker summary', () => {
|
||||
cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(1).click();
|
||||
cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(0).click();
|
||||
cy.get('.summaryHeader div').should('have.text', '1110 - Jessica Jones');
|
||||
cy.get('.summary .header').eq(0).invoke('text').should('include', 'Basic data');
|
||||
cy.get('.summary .header').eq(1).should('have.text', 'User data');
|
||||
|
|
Loading…
Reference in New Issue