0
0
Fork 0

fear: refs #5186 WIP parking section

This commit is contained in:
Jorge Penadés 2024-02-21 10:26:20 +01:00
parent a3ad94e2b5
commit 1af5b270a0
14 changed files with 551 additions and 8 deletions

View File

@ -656,6 +656,7 @@ export default {
summary: 'Summary', summary: 'Summary',
basicData: 'Basic Data', basicData: 'Basic Data',
log: 'Logs', log: 'Logs',
parkingList: 'Parking list',
}, },
list: { list: {
parking: 'Parking', parking: 'Parking',
@ -676,6 +677,32 @@ export default {
recyclable: 'Recyclable', recyclable: 'Recyclable',
}, },
}, },
parking: {
pageTitles: {
parking: 'Parking',
parkingList: 'Parkings list',
summary: 'Summary',
basicData: 'Basic data',
log: 'Logs',
},
list: {
pickingOrder: 'Picking order',
},
searchBar: {
info: 'You can search by parking code',
label: 'Search parking...',
},
summary: {
code: 'Code',
pickingOrder: 'Picking order',
sector: 'Sector',
},
basicData: {
code: 'Code',
pickingOrder: 'Picking order',
sector: 'Sector',
},
},
invoiceIn: { invoiceIn: {
pageTitles: { pageTitles: {
invoiceIns: 'Invoices In', invoiceIns: 'Invoices In',

View File

@ -715,6 +715,7 @@ export default {
summary: 'Resumen', summary: 'Resumen',
basicData: 'Datos básicos', basicData: 'Datos básicos',
log: 'Registros de auditoría', log: 'Registros de auditoría',
parkingList: 'Listado de parkings',
}, },
list: { list: {
parking: 'Parking', parking: 'Parking',
@ -735,6 +736,30 @@ export default {
recyclable: 'Reciclable', recyclable: 'Reciclable',
}, },
}, },
parking: {
pageTitles: {
parking: 'Parking',
parkingList: 'Listado de parkings',
summary: 'Resumen',
basicData: 'Datos básicos',
log: 'Registros de auditoría',
},
list: {
pickingOrder: 'Orden de recogida',
},
searchBar: {
info: 'Puedes buscar por código de parking',
label: 'Buscar parking...',
},
summary: {
code: 'Código',
pickingOrder: 'Orden de recogida',
},
basicData: {
code: 'Código',
pickingOrder: 'Orden de recogida',
},
},
invoiceIn: { invoiceIn: {
pageTitles: { pageTitles: {
invoiceIns: 'Fact. recibidas', invoiceIns: 'Fact. recibidas',

View File

@ -0,0 +1,59 @@
<script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import VnRow from 'components/ui/VnRow.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnInput from 'src/components/common/VnInput.vue';
import FormModel from 'components/FormModel.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
const { t } = useI18n();
const route = useRoute();
const parkingId = route.params?.id || null;
const sectors = ref([]);
const filter = {
fields: ['sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
</script>
<template>
<FetchData
url="Sectors"
:filter="{ fields: ['id', 'description'] }"
sort-by="description"
@on-fetch="(data) => (sectors = data)"
auto-load
/>
<VnSubToolbar />
<FormModel :url="`Parkings/${parkingId}`" model="parking" :filter="filter">
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput v-model="data.code" :label="t('parking.basicData.code')" />
</div>
<div class="col">
<VnInput
v-model="data.pickingOrder"
:label="t('parking.basicData.pickingOrder')"
/>
</div>
</VnRow>
<VnRow>
<div class="col">
<VnSelectFilter
v-model="data.sectorFk"
option-value="id"
option-label="description"
:label="t('parking.basicData.sector')"
:options="sectors"
use-input
input-debounce="0"
/>
</div>
</VnRow>
</template>
</FormModel>
</template>

View File

@ -0,0 +1,56 @@
<script setup>
import { onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { useArrayData } from 'src/composables/useArrayData';
import LeftMenu from 'components/LeftMenu.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import ParkingDescriptor from 'pages/Shelving/Parking/Card/ParkingDescriptor.vue';
const stateStore = useStateStore();
const { t } = useI18n();
const filter = {
fields: ['sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
const route = useRoute();
const arrayData = useArrayData('Parking', {
url: `Parkings/${route.params.id}`,
filter,
});
onMounted(async () => await arrayData.fetch({ append: false }));
watch(
() => route.params.id,
async (newId) => {
if (newId) {
arrayData.store.url = `Parkings/${newId}`;
await arrayData.fetch({ append: false });
}
}
);
</script>
<template>
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
<VnSearchbar
:info="t('parking.searchBar.info')"
:label="t('parking.searchBar.label')"
data-key="Parking"
/>
</Teleport>
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
<QScrollArea class="fit">
<ParkingDescriptor />
<QSeparator />
<LeftMenu source="card" />
</QScrollArea>
</QDrawer>
<QPageContainer>
<QPage>
<RouterView></RouterView>
</QPage>
</QPageContainer>
</template>

View File

@ -0,0 +1,52 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'components/ui/VnLv.vue';
import useCardDescription from 'composables/useCardDescription';
const props = defineProps({
id: {
type: Number,
required: false,
default: null,
},
});
const route = useRoute();
const { t } = useI18n();
const entityId = computed(() => props.id || route.params.id);
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
const header = ref(useCardDescription());
const setHeader = (entity) => (header.value = useCardDescription(entity.code, entity.id));
</script>
<template>
<CardDescriptor
module="Parking"
:url="`Parkings/${entityId}`"
:filter="filter"
:title="header.title"
:subtitle="header.subtitle"
data-key="ParkingData"
@on-fetch="setHeader"
>
<template #body="{ entity: parking }">
<VnLv :label="t('parking.summary.code')" :value="parking.code" />
<VnLv
:label="t('parking.summary.pickingOrder')"
:value="parking.pickingOrder"
/>
<VnLv
:label="t('parking.summary.sector')"
:value="parking.sector?.description"
/>
</template>
</CardDescriptor>
</template>

View File

@ -0,0 +1,6 @@
<script setup>
import VnLog from 'src/components/common/VnLog.vue';
</script>
<template>
<VnLog model="Parking" url="/ParkingLogs" />
</template>

View File

@ -0,0 +1,50 @@
<script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'components/ui/VnLv.vue';
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const route = useRoute();
const { t } = useI18n();
const entityId = computed(() => $props.id || route.params.id);
const filter = {
fields: ['sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
</script>
<template>
<div class="q-pa-md">
<CardSummary ref="summary" :url="`Parkings/${entityId}`" :filter="filter">
<template #header="{ entity: parking }">{{ parking.code }}</template>
<template #body="{ entity: parking }">
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<a class="header" :href="`#/parking/${entityId}/basic-data`">
{{ t('parking.pageTitles.basicData') }}
<QIcon name="open_in_new" color="primary" />
</a>
</QCardSection>
<VnLv :label="t('parking.summary.code')" :value="parking.code" />
<VnLv
:label="t('parking.summary.pickingOrder')"
:value="parking.pickingOrder"
/>
<VnLv
:label="t('parking.summary.sector')"
:value="parking.sector?.description"
/>
</QCard>
</template>
</CardSummary>
</div>
</template>

View File

@ -0,0 +1,77 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
import VnInput from 'components/common/VnInput.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
const { t } = useI18n();
defineProps({
dataKey: {
type: String,
required: true,
},
});
const sectors = ref([]);
const emit = defineEmits(['search']);
</script>
<template>
<FetchData
url="Sectors"
:filter="{ fields: ['id', 'description'] }"
sort-by="description"
@on-fetch="(data) => (sectors = data)"
auto-load
/>
<VnFilterPanel :data-key="dataKey" :search-button="true" @search="emit('search')">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
<template #body="{ params }">
<QItem>
<QItemSection>
<VnInput
:label="t('params.code')"
v-model="params.code"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelectFilter
v-model="params.sectorFk"
option-value="id"
option-label="description"
:label="t('params.sectorFk')"
dense
outlined
rounded
:options="sectors"
use-input
input-debounce="0"
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
<i18n>
en:
params:
code: Code
sectorFk: Sector
search: General Search
es:
params:
code: Código
search: Búsqueda general
</i18n>

View File

@ -0,0 +1,100 @@
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import VnPaginate from 'components/ui/VnPaginate.vue';
import CardList from 'components/ui/CardList.vue';
import VnLv from 'components/ui/VnLv.vue';
import ParkingFilter from './ParkingFilter.vue';
import ParkingSummary from './Card/ParkingSummary.vue';
const stateStore = useStateStore();
const router = useRouter();
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
onMounted(() => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
function exprBuilder(param, value) {
switch (param) {
case 'code':
return { [param]: { like: `%${value}%` } };
case 'sectorFk':
return { [param]: value };
case 'search':
return { or: [{ code: { like: `%${value}%` } }, { id: value }] };
}
}
</script>
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar" />
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<ParkingFilter data-key="ParkingList" />
</QScrollArea>
</QDrawer>
<QPage class="column items-center q-pa-md">
<div class="vn-card-list">
<VnPaginate
data-key="ParkingList"
url="Parkings"
:filter="filter"
:expr-builder="exprBuilder"
:limit="20"
auto-load
order="code"
>
<template #body="{ rows }">
<CardList
v-for="row of rows"
:key="row.id"
:id="row.id"
:title="row.code"
@click="router.push({ path: `/parking/${row.id}` })"
>
<template #list-items>
<VnLv label="Sector" :value="row.sector?.description" />
<VnLv
:label="t('parking.list.pickingOrder')"
:value="row.pickingOrder"
/>
</template>
<template #actions>
<QBtn
:label="t('components.smartCard.openSummary')"
@click.stop="viewSummary(row.id, ParkingSummary)"
color="primary"
/>
</template>
</CardList>
</template>
</VnPaginate>
</div>
</QPage>
</template>

View File

@ -0,0 +1,17 @@
<script setup>
import { useStateStore } from 'stores/useStateStore';
import LeftMenu from 'src/components/LeftMenu.vue';
const stateStore = useStateStore();
</script>
<template>
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
<QScrollArea class="fit text-grey-8">
<LeftMenu />
</QScrollArea>
</QDrawer>
<QPageContainer>
<RouterView></RouterView>
</QPageContainer>
</template>

View File

@ -13,6 +13,7 @@ import Travel from './travel';
import Order from './order'; import Order from './order';
import Department from './department'; import Department from './department';
import Entry from './entry'; import Entry from './entry';
import Parking from './parking';
export default [ export default [
Item, Item,
@ -30,4 +31,5 @@ export default [
invoiceIn, invoiceIn,
Department, Department,
Entry, Entry,
Parking,
]; ];

View File

@ -0,0 +1,63 @@
import { RouterView } from 'vue-router';
export default {
path: '/parking',
name: 'Parking',
meta: {
title: 'parking',
icon: 'garage_home',
},
component: RouterView,
redirect: { name: 'ParkingMain' },
menus: {
main: ['ParkingList'],
card: ['ParkingBasicData', 'ParkingLog'],
},
children: [
{
path: '',
name: 'ParkingMain',
component: () => import('src/pages/Shelving/Parking/ParkingMain.vue'),
redirect: { name: 'ParkingList' },
children: [
{
path: 'list',
name: 'ParkingList',
meta: {
title: 'parkingList',
icon: 'view_list',
},
component: () => import('src/pages/Shelving/Parking/ParkingList.vue'),
},
],
},
{
path: ':id',
name: 'ParkingCard',
component: () => import('src/pages/Shelving/Parking/Card/ParkingCard.vue'),
redirect: { name: 'ParkingSummary' },
children: [
{
name: 'ParkingSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'view_list',
},
component: () =>
import('src/pages/Shelving/Parking/Card/ParkingSummary.vue'),
},
{
name: 'ShelvingBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
roles: ['salesPerson'],
},
component: () => import('pages/Shelving/Card/ShelvingForm.vue'),
},
],
},
],
};

View File

@ -1,17 +1,17 @@
import {RouterView} from "vue-router"; import { RouterView } from 'vue-router';
export default { export default {
path: '/shelving', path: '/shelving',
name: 'Shelving', name: 'Shelving',
meta: { meta: {
title: 'shelving', title: 'shelving',
icon: 'vn:inventory' icon: 'vn:inventory',
}, },
component: RouterView, component: RouterView,
redirect: { name: 'ShelvingMain' }, redirect: { name: 'ShelvingMain' },
menus: { menus: {
main: ['ShelvingList'], main: ['ShelvingList', 'ParkingList'],
card: ['ShelvingBasicData', 'ShelvingLog'] card: ['ShelvingBasicData', 'ShelvingLog'],
}, },
children: [ children: [
{ {
@ -51,8 +51,7 @@ export default {
meta: { meta: {
title: 'summary', title: 'summary',
}, },
component: () => component: () => import('pages/Shelving/Card/ShelvingSummary.vue'),
import('pages/Shelving/Card/ShelvingSummary.vue'),
}, },
{ {
name: 'ShelvingBasicData', name: 'ShelvingBasicData',
@ -75,6 +74,14 @@ export default {
}, },
], ],
}, },
] {
path: 'parking',
name: 'ParkingList',
meta: {
title: 'parkingList',
icon: 'view_list',
},
component: () => import('src/pages/Shelving/Parking/ParkingMain.vue'),
},
],
}; };

View File

@ -13,6 +13,7 @@ import department from './modules/department';
import shelving from 'src/router/modules/shelving'; import shelving from 'src/router/modules/shelving';
import order from 'src/router/modules/order'; import order from 'src/router/modules/order';
import entry from 'src/router/modules/entry'; import entry from 'src/router/modules/entry';
import parking from 'src/router/modules/parking';
const routes = [ const routes = [
{ {
@ -67,6 +68,7 @@ const routes = [
travel, travel,
department, department,
entry, entry,
parking,
{ {
path: '/:catchAll(.*)*', path: '/:catchAll(.*)*',
name: 'NotFound', name: 'NotFound',