feat: refs #8606 adapt module to VnCatdBeta
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Jon Elias 2025-02-21 10:14:59 +01:00
parent eab18e4d14
commit 705ca0402a
16 changed files with 259 additions and 302 deletions

View File

@ -33,6 +33,10 @@ const props = defineProps({
type: String, type: String,
default: '', default: '',
}, },
userFilter: {
type: Object,
default: null,
},
filter: { filter: {
type: Object, type: Object,
default: null, default: null,

View File

@ -148,8 +148,7 @@ export function useArrayData(key, userOptions) {
} }
async function applyFilter({ filter, params }, fetchOptions = {}) { async function applyFilter({ filter, params }, fetchOptions = {}) {
if (filter) store.userFilter = filter; if (filter) store.filter = filter;
store.filter = {};
if (params) store.userParams = { ...params }; if (params) store.userParams = { ...params };
const response = await fetch(fetchOptions); const response = await fetch(fetchOptions);

View File

@ -337,5 +337,5 @@ input::-webkit-inner-spin-button {
} }
.containerShrinked { .containerShrinked {
width: 80%; width: 70%;
} }

View File

@ -1,38 +1,7 @@
<script setup> <script setup>
import { useRoute } from 'vue-router'; import VnCardBeta from 'src/components/common/VnCardBeta.vue';
import { computed } from 'vue';
import VnCard from 'components/common/VnCard.vue';
import ZoneDescriptor from './ZoneDescriptor.vue'; import ZoneDescriptor from './ZoneDescriptor.vue';
import ZoneFilterPanel from '../ZoneFilterPanel.vue';
import filter from './ZoneFilter.js';
const route = useRoute();
const routeName = computed(() => route.name);
function notIsLocations(ifIsFalse, ifIsTrue) {
if (routeName.value != 'ZoneLocations') return ifIsFalse;
return ifIsTrue;
}
</script> </script>
<template> <template>
<VnCard <VnCardBeta data-key="Zone" url="Zones" :descriptor="ZoneDescriptor" />
data-key="Zone"
:url="notIsLocations('Zones', undefined)"
:descriptor="ZoneDescriptor"
:filter="filter"
:filter-panel="notIsLocations(ZoneFilterPanel, undefined)"
:search-data-key="notIsLocations('ZoneList', undefined)"
:searchbar-props="{
url: notIsLocations('Zones', 'ZoneLocations'),
label: notIsLocations($t('list.searchZone'), $t('list.searchLocation')),
info: $t('list.searchInfo'),
whereFilter: notIsLocations((value) => {
return /^\d+$/.test(value)
? { id: value }
: { name: { like: `%${value}%` } };
}),
}"
/>
</template> </template>

View File

@ -1,18 +1,14 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref, reactive } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import ZoneEventsPanel from './ZoneEventsPanel.vue'; import ZoneEventsPanel from './ZoneEventsPanel.vue';
import ZoneCalendarGrid from '../ZoneCalendarGrid.vue'; import ZoneCalendarGrid from '../ZoneCalendarGrid.vue';
import ZoneEventInclusionForm from './ZoneEventInclusionForm.vue'; import ZoneEventInclusionForm from './ZoneEventInclusionForm.vue';
import ZoneEventExclusionForm from './ZoneEventExclusionForm.vue'; import ZoneEventExclusionForm from './ZoneEventExclusionForm.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import { useStateStore } from 'stores/useStateStore';
import { reactive } from 'vue';
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore();
const firstDay = ref(); const firstDay = ref();
const lastDay = ref(); const lastDay = ref();
@ -43,14 +39,16 @@ const onZoneEventFormClose = () => {
</script> </script>
<template> <template>
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()"> <RightMenu>
<ZoneEventsPanel <template #right-panel>
:first-day="firstDay" <ZoneEventsPanel
:last-day="lastDay" :first-day="firstDay"
:events="events" :last-day="lastDay"
v-model:formModeName="formModeName" :events="events"
/> v-model:formModeName="formModeName"
</Teleport> />
</template>
</RightMenu>
<QPage class="q-pa-md flex justify-center"> <QPage class="q-pa-md flex justify-center">
<ZoneCalendarGrid <ZoneCalendarGrid
v-model:events="events" v-model:events="events"

View File

@ -1,6 +1,7 @@
<script setup> <script setup>
import { onMounted, ref, computed, watch, onUnmounted } from 'vue'; import { onMounted, ref, computed, watch, onUnmounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useStateStore } from 'stores/useStateStore';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import axios from 'axios'; import axios from 'axios';
@ -30,7 +31,7 @@ const emit = defineEmits(['update:tickedNodes']);
const route = useRoute(); const route = useRoute();
const state = useState(); const state = useState();
const stateStore = useStateStore();
const treeRef = ref(); const treeRef = ref();
const expanded = ref([]); const expanded = ref([]);
@ -82,7 +83,7 @@ const onNodeExpanded = async (nodeKeysArray) => {
await fetchNodeLeaves(lastNodeKey, true); await fetchNodeLeaves(lastNodeKey, true);
} else { } else {
const difference = new Set( const difference = new Set(
[...previousExpandedNodes.value].filter((x) => !nodeKeysSet.has(x)) [...previousExpandedNodes.value].filter((x) => !nodeKeysSet.has(x)),
); );
const collapsedNode = Array.from(difference).pop(); const collapsedNode = Array.from(difference).pop();
const node = treeRef.value?.getNodeByKey(collapsedNode); const node = treeRef.value?.getNodeByKey(collapsedNode);
@ -135,7 +136,7 @@ watch(
} }
previousExpandedNodes.value = new Set(expanded.value); previousExpandedNodes.value = new Set(expanded.value);
}, },
{ immediate: true } { immediate: true },
); );
const reFetch = async () => { const reFetch = async () => {
@ -153,6 +154,16 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<Teleport to="#section-searchbar" v-if="stateStore.isHeaderMounted()">
<VnSearchbar
v-if="!showSearchBar"
:data-key="datakey"
:url="url"
:redirect="false"
:search-remove-params="false"
:label="$t('Search locations')"
/>
</Teleport>
<VnInput <VnInput
v-if="showSearchBar" v-if="showSearchBar"
v-model="store.userParams.search" v-model="store.userParams.search"
@ -163,13 +174,6 @@ onUnmounted(() => {
<QBtn color="primary" icon="search" dense flat @click="reFetch()" /> <QBtn color="primary" icon="search" dense flat @click="reFetch()" />
</template> </template>
</VnInput> </VnInput>
<VnSearchbar
v-if="!showSearchBar"
:data-key="datakey"
:url="url"
:redirect="false"
:search-remove-params="false"
/>
<QTree <QTree
ref="treeRef" ref="treeRef"
:nodes="nodes" :nodes="nodes"

View File

@ -2,5 +2,5 @@
import VnLog from 'src/components/common/VnLog.vue'; import VnLog from 'src/components/common/VnLog.vue';
</script> </script>
<template> <template>
<VnLog model="Zone" url="/ZoneLogs"></VnLog> <VnLog model="Zone" />
</template> </template>

View File

@ -1,74 +0,0 @@
<script setup>
import { useI18n } from 'vue-i18n';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
const { t } = useI18n();
const exprBuilder = (param, value) => {
switch (param) {
case 'name':
return {
name: { like: `%${value}%` },
};
case 'code':
return {
code: { like: `%${value}%` },
};
case 'agencyModeFk':
return {
agencyModeFk: value,
};
case 'search':
return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
}
};
const tableFilter = {
include: [
{
relation: 'agencyMode',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'address',
scope: {
fields: ['id', 'nickname', 'provinceFk', 'postalCode'],
include: [
{
relation: 'province',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'postcode',
scope: {
fields: ['code', 'townFk'],
include: {
relation: 'town',
scope: {
fields: ['id', 'name'],
},
},
},
},
],
},
},
],
};
</script>
<template>
<VnSearchbar
data-key="ZonesList"
url="Zones"
:filter="tableFilter"
:expr-builder="exprBuilder"
:label="t('list.searchZone')"
:info="t('list.searchInfo')"
custom-route-redirect-name="ZoneSummary"
/>
</template>

View File

@ -60,10 +60,11 @@ onMounted(async () => {
<template> <template>
<CardSummary <CardSummary
data-key="Zone" data-key="ZoneSummary"
ref="summary" ref="summary"
:url="`Zones/${entityId}`" :url="`Zones/${entityId}`"
:filter="filter" :filter="filter"
:entity-id="entityId"
> >
<template #header="{ entity }"> <template #header="{ entity }">
<div>#{{ entity.id }} - {{ entity.name }}</div> <div>#{{ entity.id }} - {{ entity.name }}</div>

View File

@ -3,7 +3,6 @@ import { ref } from 'vue';
import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue'; import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue';
import ZoneCalendarGrid from './ZoneCalendarGrid.vue'; import ZoneCalendarGrid from './ZoneCalendarGrid.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import ZoneSearchbar from './Card/ZoneSearchbar.vue';
const firstDay = ref(null); const firstDay = ref(null);
const lastDay = ref(null); const lastDay = ref(null);
@ -11,7 +10,6 @@ const events = ref([]);
</script> </script>
<template> <template>
<ZoneSearchbar />
<RightMenu> <RightMenu>
<template #right-panel> <template #right-panel>
<ZoneDeliveryPanel /> <ZoneDeliveryPanel />

View File

@ -63,6 +63,15 @@ const agencies = ref([]);
</VnSelect> </VnSelect>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnInput
:label="t('list.price')"
v-model="params.price"
is-outlined
/>
</QItemSection>
</QItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>

View File

@ -14,9 +14,8 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnInputTime from 'src/components/common/VnInputTime.vue'; import VnInputTime from 'src/components/common/VnInputTime.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import VnSection from 'src/components/common/VnSection.vue';
import ZoneFilterPanel from './ZoneFilterPanel.vue'; import ZoneFilterPanel from './ZoneFilterPanel.vue';
import ZoneSearchbar from './Card/ZoneSearchbar.vue';
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
@ -25,7 +24,7 @@ const { viewSummary } = useSummaryDialog();
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const tableRef = ref(); const tableRef = ref();
const warehouseOptions = ref([]); const warehouseOptions = ref([]);
const dataKey = 'ZoneList';
const tableFilter = { const tableFilter = {
include: [ include: [
{ {
@ -115,7 +114,6 @@ const columns = computed(() => [
inWhere: true, inWhere: true,
}, },
columnClass: 'shrink-column', columnClass: 'shrink-column',
component: 'number',
}, },
{ {
align: 'center', align: 'center',
@ -171,82 +169,113 @@ function formatRow(row) {
return dashIfEmpty(`${row?.address?.nickname}, return dashIfEmpty(`${row?.address?.nickname},
${row?.address?.postcode?.town?.name} (${row?.address?.province?.name})`); ${row?.address?.postcode?.town?.name} (${row?.address?.province?.name})`);
} }
const exprBuilder = (param, value) => {
switch (param) {
case 'name':
return {
name: { like: `%${value}%` },
};
case 'code':
return {
code: { like: `%${value}%` },
};
case 'agencyModeFk':
return {
agencyModeFk: value,
};
case 'search':
return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
case 'price':
return {
price: value,
};
}
};
</script> </script>
<template> <template>
<ZoneSearchbar /> <VnSection
<RightMenu> :data-key="dataKey"
<template #right-panel> :columns="columns"
<ZoneFilterPanel data-key="ZonesList" /> prefix="zone"
:array-data-props="{
url: 'Zones',
order: ['id ASC'],
userFilter: tableFilter,
exprBuilder,
}"
>
<template #advanced-menu>
<ZoneFilterPanel :data-key="dataKey" />
</template> </template>
</RightMenu> <template #body>
<div class="table-container"> <div class="table-container">
<div class="column items-center"> <div class="column items-center">
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="ZonesList" :data-key="dataKey"
url="Zones" :columns="columns"
:create="{ :right-search="false"
urlCreate: 'Zones', redirect="Zone"
title: t('list.createZone'), :create="{
onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`), urlCreate: 'Zones',
formInitialData: {}, title: t('list.createZone'),
}" onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`),
:user-filter="tableFilter" formInitialData: {},
:columns="columns" }"
redirect="zone" table-height="85vh"
:right-search="false" >
table-height="85vh" <template #column-addressFk="{ row }">
order="id ASC" {{ dashIfEmpty(formatRow(row)) }}
> </template>
<template #column-addressFk="{ row }"> <template #more-create-dialog="{ data }">
{{ dashIfEmpty(formatRow(row)) }} <VnSelect
</template> url="AgencyModes"
<template #more-create-dialog="{ data }"> v-model="data.agencyModeFk"
<VnSelect option-value="id"
url="AgencyModes" option-label="name"
v-model="data.agencyModeFk" :label="t('list.agency')"
option-value="id" />
option-label="name" <VnInput
:label="t('list.agency')" v-model="data.price"
/> :label="t('list.price')"
<VnInput min="0"
v-model="data.price" type="number"
:label="t('list.price')" required="true"
min="0" />
type="number" <VnInput
required="true" v-model="data.bonus"
/> :label="t('zone.bonus')"
<VnInput min="0"
v-model="data.bonus" type="number"
:label="t('zone.bonus')" />
min="0" <VnInput
type="number" v-model="data.travelingDays"
/> :label="t('zone.travelingDays')"
<VnInput type="number"
v-model="data.travelingDays" min="0"
:label="t('zone.travelingDays')" />
type="number" <VnInputTime v-model="data.hour" :label="t('list.close')" />
min="0" <VnSelect
/> url="Warehouses"
<VnInputTime v-model="data.hour" :label="t('list.close')" /> v-model="data.warehouseFK"
<VnSelect option-value="id"
url="Warehouses" option-label="name"
v-model="data.warehouseFK" :label="t('list.warehouse')"
option-value="id" :options="warehouseOptions"
option-label="name" />
:label="t('list.warehouse')" <QCheckbox
:options="warehouseOptions" v-model="data.isVolumetric"
/> :label="t('list.isVolumetric')"
<QCheckbox :toggle-indeterminate="false"
v-model="data.isVolumetric" />
:label="t('list.isVolumetric')" </template>
:toggle-indeterminate="false" </VnTable>
/> </div>
</template> </div>
</VnTable> </template>
</div> </VnSection>
</div>
</template> </template>
<i18n> <i18n>

View File

@ -7,7 +7,6 @@ import FetchData from 'components/FetchData.vue';
import { toDateFormat } from 'src/filters/date.js'; import { toDateFormat } from 'src/filters/date.js';
import { useWeekdayStore } from 'src/stores/useWeekdayStore'; import { useWeekdayStore } from 'src/stores/useWeekdayStore';
import ZoneSearchbar from './Card/ZoneSearchbar.vue';
const { t } = useI18n(); const { t } = useI18n();
const weekdayStore = useWeekdayStore(); const weekdayStore = useWeekdayStore();
@ -53,7 +52,6 @@ onMounted(() => weekdayStore.initStore());
@on-fetch="(data) => (details = data)" @on-fetch="(data) => (details = data)"
auto-load auto-load
/> />
<ZoneSearchbar />
<VnSubToolbar /> <VnSubToolbar />
<QPage class="column items-center q-pa-md"> <QPage class="column items-center q-pa-md">
<QCard class="containerShrinked q-pa-md"> <QCard class="containerShrinked q-pa-md">

View File

@ -15,6 +15,8 @@ zone:
bonus: Bonus bonus: Bonus
closing: Closing closing: Closing
travelingDays: Traveling days travelingDays: Traveling days
search: Search zone
searchInfo: Search zone by id or name
list: list:
clone: Clone clone: Clone
id: Id id: Id

View File

@ -15,6 +15,8 @@ zone:
bonus: Bonificación bonus: Bonificación
closing: Cierre closing: Cierre
travelingDays: Días de viaje travelingDays: Días de viaje
search: Buscar zona
searchInfo: Buscar zona por Id o nombre
list: list:
clone: Clonar clone: Clonar
id: Id id: Id

View File

@ -1,24 +1,12 @@
import { RouterView } from 'vue-router'; import { RouterView } from 'vue-router';
export default { const zoneCard = {
path: '/zone', name: 'ZoneCard',
name: 'Zone', path: ':id',
component: () => import('src/pages/Zone/Card/ZoneCard.vue'),
redirect: { name: 'ZoneSummary' },
meta: { meta: {
title: 'zones', menu: [
icon: 'vn:zone',
moduleName: 'Zone',
keyBinding: 'z',
},
component: RouterView,
redirect: { name: 'ZoneMain' },
menus: {
main: [
'ZoneList',
'ZoneDeliveryDays',
'ZoneUpcomingList',
'ZoneUpcomingDeliveries',
],
card: [
'ZoneBasicData', 'ZoneBasicData',
'ZoneWarehouses', 'ZoneWarehouses',
'ZoneHistory', 'ZoneHistory',
@ -28,17 +16,109 @@ export default {
}, },
children: [ children: [
{ {
path: '/zone', name: 'ZoneSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'launch',
},
component: () => import('src/pages/Zone/Card/ZoneSummary.vue'),
},
{
path: 'basic-data',
name: 'ZoneBasicData',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('src/pages/Zone/Card/ZoneBasicData.vue'),
},
{
path: 'location',
name: 'ZoneLocations',
meta: {
title: 'locations',
icon: 'my_location',
},
component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
},
{
path: 'warehouses',
name: 'ZoneWarehouses',
meta: {
title: 'warehouses',
icon: 'home',
},
component: () => import('src/pages/Zone/Card/ZoneWarehouses.vue'),
},
{
path: 'log',
name: 'ZoneHistory',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
},
{
path: 'events',
name: 'ZoneEvents',
meta: {
title: 'calendar',
icon: 'vn:calendar',
},
component: () => import('src/pages/Zone/Card/ZoneEvents.vue'),
},
],
};
export default {
name: 'Zone',
path: '/zone',
meta: {
title: 'zones',
icon: 'vn:zone',
moduleName: 'Zone',
keyBinding: 'z',
menu: [
'ZoneList',
'ZoneDeliveryDays',
'ZoneUpcomingList',
'ZoneUpcomingDeliveries',
],
},
component: RouterView,
redirect: { name: 'ZoneMain' },
children: [
{
name: 'ZoneMain', name: 'ZoneMain',
path: '',
component: () => import('src/components/common/VnModule.vue'), component: () => import('src/components/common/VnModule.vue'),
redirect: { name: 'ZoneList' }, redirect: { name: 'ZoneIndexMain' },
children: [ children: [
{ {
path: 'list', path: '',
name: 'ZoneList', name: 'ZoneIndexMain',
redirect: { name: 'ZoneList' },
component: () => import('src/pages/Zone/ZoneList.vue'),
children: [
{
name: 'ZoneList',
path: 'list',
meta: {
title: 'list',
icon: 'view_list',
},
},
zoneCard,
],
},
{
path: 'create',
name: 'ZoneCreate',
meta: { meta: {
title: 'zonesList', title: 'zoneCreate',
icon: 'view_list', icon: 'add',
}, },
component: () => import('src/pages/Zone/ZoneList.vue'), component: () => import('src/pages/Zone/ZoneList.vue'),
}, },
@ -62,67 +142,5 @@ export default {
}, },
], ],
}, },
{
name: 'ZoneCard',
path: ':id',
component: () => import('src/pages/Zone/Card/ZoneCard.vue'),
redirect: { name: 'ZoneSummary' },
children: [
{
name: 'ZoneSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'launch',
},
component: () => import('src/pages/Zone/Card/ZoneSummary.vue'),
},
{
name: 'ZoneBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('src/pages/Zone/Card/ZoneBasicData.vue'),
},
{
name: 'ZoneLocations',
path: 'location',
meta: {
title: 'locations',
icon: 'my_location',
},
component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
},
{
name: 'ZoneWarehouses',
path: 'warehouses',
meta: {
title: 'warehouses',
icon: 'home',
},
component: () => import('src/pages/Zone/Card/ZoneWarehouses.vue'),
},
{
name: 'ZoneHistory',
path: 'log',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
},
{
name: 'ZoneEvents',
path: 'events',
meta: {
title: 'calendar',
icon: 'vn:calendar',
},
component: () => import('src/pages/Zone/Card/ZoneEvents.vue'),
},
],
},
], ],
}; };