WIP: feat: #8115 created new function for adding new parkings massively #1476
|
@ -345,6 +345,7 @@ globals:
|
||||||
operator: Operator
|
operator: Operator
|
||||||
parking: Parking
|
parking: Parking
|
||||||
vehicleList: Vehicles
|
vehicleList: Vehicles
|
||||||
|
parkingCreate: New parking
|
||||||
vehicle: Vehicle
|
vehicle: Vehicle
|
||||||
entryPreAccount: Pre-account
|
entryPreAccount: Pre-account
|
||||||
unsavedPopup:
|
unsavedPopup:
|
||||||
|
|
|
@ -350,6 +350,7 @@ globals:
|
||||||
vehicleList: Vehículos
|
vehicleList: Vehículos
|
||||||
vehicle: Vehículo
|
vehicle: Vehículo
|
||||||
entryPreAccount: Precontabilizar
|
entryPreAccount: Precontabilizar
|
||||||
|
parkingCreate: Nuevo parking
|
||||||
unsavedPopup:
|
unsavedPopup:
|
||||||
title: Los cambios que no haya guardado se perderán
|
title: Los cambios que no haya guardado se perderán
|
||||||
subtitle: ¿Seguro que quiere salir sin guardar?
|
subtitle: ¿Seguro que quiere salir sin guardar?
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, onMounted } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const entityId = computed(() => route.params.id ?? null);
|
||||||
|
const isNew = Boolean(!entityId.value);
|
||||||
|
|
||||||
|
const sectors = ref([]);
|
||||||
|
|
||||||
|
const defaultInitialData = {
|
||||||
|
sector: null,
|
||||||
|
block: null,
|
||||||
|
streetFrom: null,
|
||||||
|
streetTo: null,
|
||||||
|
numberFrom: null,
|
||||||
|
numberTo: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSave = (parking, newParking) => {
|
||||||
|
if (isNew) {
|
||||||
|
router.push({ name: 'ParkingSummary', params: { id: newParking?.id } });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VnSubToolbar v-if="isNew" />
|
||||||
|
<FormModel
|
||||||
|
:url-create="isNew ? 'Parkings/multipleParkings' : null"
|
||||||
|
:filter="filter"
|
||||||
|
model="Parking"
|
||||||
|
:auto-load="!isNew"
|
||||||
|
:form-initial-data="isNew ? defaultInitialData : null"
|
||||||
|
>
|
||||||
|
<template #form="{ data, validate }">
|
||||||
|
<VnRow>
|
||||||
|
<VnSelect
|
||||||
|
v-model="data.sector"
|
||||||
|
url="Sectors"
|
||||||
|
option-value="id"
|
||||||
|
option-label="description"
|
||||||
|
:filter-options="['id', 'description']"
|
||||||
|
:fields="['id', 'description']"
|
||||||
|
:label="$t('parking.sector')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow>
|
||||||
|
<VnInput
|
||||||
|
v-model="data.block"
|
||||||
|
:label="$t('parking.block')"
|
||||||
|
:rules="validate('Parking.block')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="data.streetFrom"
|
||||||
|
type="number"
|
||||||
|
:label="$t('parking.streetFrom')"
|
||||||
|
:rules="validate('Parking.streetFrom')"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="data.streetTo"
|
||||||
|
type="number"
|
||||||
|
:label="$t('parking.streetTo')"
|
||||||
|
:rules="validate('Parking.streetTo')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="data.numberFrom"
|
||||||
|
type="number"
|
||||||
|
:label="$t('parking.numberFrom')"
|
||||||
|
:rules="validate('Parking.numberFrom')"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="data.numberTo"
|
||||||
|
type="number"
|
||||||
|
:label="$t('parking.numberTo')"
|
||||||
|
:rules="validate('Parking.numberTo')"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModel>
|
||||||
|
</template>
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref} from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
|
@ -16,6 +16,11 @@ defineProps({
|
||||||
|
|
||||||
const sectors = ref([]);
|
const sectors = ref([]);
|
||||||
const emit = defineEmits(['search']);
|
const emit = defineEmits(['search']);
|
||||||
|
|
||||||
|
const updateParams = () => {
|
||||||
|
emit('search');
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -26,7 +31,11 @@ const emit = defineEmits(['search']);
|
||||||
@on-fetch="(data) => (sectors = data)"
|
@on-fetch="(data) => (sectors = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<VnFilterPanel :data-key="dataKey" :search-button="true" @search="emit('search')">
|
<VnFilterPanel
|
||||||
|
:data-key="dataKey"
|
||||||
|
:search-button="true"
|
||||||
|
@search="updateParams"
|
||||||
|
>
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
@ -36,9 +45,56 @@ const emit = defineEmits(['search']);
|
||||||
<template #body="{ params }">
|
<template #body="{ params }">
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput :label="t('params.code')" v-model="params.code" filled />
|
<VnInput
|
||||||
|
:label="t('params.block')"
|
||||||
|
v-model="params.block"
|
||||||
|
filled
|
||||||
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<div class="row q-gutter-sm">
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.streetFrom')"
|
||||||
|
v-model.number="params.streetFrom"
|
||||||
|
type="number"
|
||||||
|
filled
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.streetTo')"
|
||||||
|
v-model.number="params.streetTo"
|
||||||
|
type="number"
|
||||||
|
filled
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<div class="row q-gutter-sm">
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.numberFrom')"
|
||||||
|
v-model="params.numberFrom"
|
||||||
|
type="number"
|
||||||
|
filled
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.numberTo')"
|
||||||
|
v-model="params.numberTo"
|
||||||
|
type="number"
|
||||||
|
filled
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -64,9 +120,19 @@ en:
|
||||||
code: Code
|
code: Code
|
||||||
sectorFk: Sector
|
sectorFk: Sector
|
||||||
search: General Search
|
search: General Search
|
||||||
|
block: Block
|
||||||
|
streetFrom: Street (From)
|
||||||
|
streetTo: Street (To)
|
||||||
|
numberFrom: Number (From)
|
||||||
|
numberTo: Number (To)
|
||||||
es:
|
es:
|
||||||
params:
|
params:
|
||||||
code: Código
|
code: Código
|
||||||
search: Búsqueda general
|
search: Búsqueda general
|
||||||
|
sectorFk: Sector
|
||||||
</i18n>
|
block: Bloque
|
||||||
|
streetFrom: Calle (Desde)
|
||||||
|
streetTo: Calle (Hasta)
|
||||||
|
numberFrom: Número (Desde)
|
||||||
|
numberTo: Número (Hasta)
|
||||||
|
</i18n>
|
|
@ -1,26 +1,29 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted } from 'vue';
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
|
import { usePrintService } from 'src/composables/usePrintService';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import VnSection from 'src/components/common/VnSection.vue';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import ParkingFilter from './ParkingFilter.vue';
|
import ParkingFilter from './ParkingFilter.vue';
|
||||||
import exprBuilder from './ParkingExprBuilder.js';
|
import exprBuilder from './ParkingExprBuilder.js';
|
||||||
import ParkingSummary from './Card/ParkingSummary.vue';
|
import ParkingSummary from './Card/ParkingSummary.vue';
|
||||||
|
import { QBtn, QTooltip } from 'quasar';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
const { openReport } = usePrintService();
|
||||||
const dataKey = 'ParkingList';
|
const dataKey = 'ParkingList';
|
||||||
|
const tableRef = ref();
|
||||||
|
const selectedRows = ref([]);
|
||||||
|
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
||||||
|
|
||||||
onMounted(() => (stateStore.rightDrawer = true));
|
onMounted(() => (stateStore.rightDrawer = true));
|
||||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
|
||||||
const filter = {
|
|
||||||
fields: ['id', 'sectorFk', 'code', 'pickingOrder'],
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -35,7 +38,7 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'sector',
|
name: 'sector',
|
||||||
label: t('parking.sector'),
|
label: t('parking.sector'),
|
||||||
format: (val) => val.sector.description ?? '',
|
format: (val) => val.sector_description ?? '',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
|
@ -57,44 +60,89 @@ const columns = computed(() => [
|
||||||
action: (row) => viewSummary(row.id, ParkingSummary),
|
action: (row) => viewSummary(row.id, ParkingSummary),
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('globals.downloadPdf'),
|
||||||
|
icon: 'cloud_download',
|
||||||
|
isPrimary: true,
|
||||||
|
action: (row) => openPdf(row.id),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
function openPdf(id) {
|
||||||
|
openReport(`Parkings/${id}/download`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadPdf() {
|
||||||
|
if (selectedRows.value.length === 0) return;
|
||||||
|
const selectedCardsArray = selectedRows.value;
|
||||||
|
|
||||||
|
if (selectedRows.value.length === 1) {
|
||||||
|
const [parking] = selectedCardsArray;
|
||||||
|
openPdf(parking.id);
|
||||||
|
} else {
|
||||||
|
const parkingIdsArray = selectedCardsArray.map((parking) => parking.id);
|
||||||
|
const parkingIds = parkingIdsArray.join(',');
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
ids: parkingIds,
|
||||||
|
};
|
||||||
|
|
||||||
|
openReport(`Parkings/downloadZip`, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnSection
|
<VnSection
|
||||||
:data-key="dataKey"
|
:data-key="dataKey"
|
||||||
prefix="parking"
|
prefix="parking"
|
||||||
|
:columns="columns"
|
||||||
:array-data-props="{
|
:array-data-props="{
|
||||||
url: 'Parkings',
|
url: 'Parkings/filter',
|
||||||
order: ['code'],
|
order: ['code'],
|
||||||
userFilter: filter,
|
|
||||||
exprBuilder,
|
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #advanced-menu>
|
<template #advanced-menu>
|
||||||
<ParkingFilter data-key="ParkingList" />
|
<ParkingFilter data-key="ParkingList" />
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
|
<VnSubToolbar>
|
||||||
|
<template #st-actions>
|
||||||
|
<QBtn
|
||||||
|
color="primary"
|
||||||
|
icon-right="cloud_download"
|
||||||
|
@click="downloadPdf()"
|
||||||
|
:disable="!hasSelectedCards"
|
||||||
|
data-cy="ParkingDownloadPdfBtn"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('globals.downloadPdf') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
</VnSubToolbar>
|
||||||
<VnTable
|
<VnTable
|
||||||
|
ref="tableRef"
|
||||||
:data-key="dataKey"
|
:data-key="dataKey"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
:use-model="true"
|
|
||||||
:disable-option="{ table: true }"
|
|
||||||
redirect="shelving/parking"
|
redirect="shelving/parking"
|
||||||
default-mode="card"
|
v-model:selected="selectedRows"
|
||||||
|
:table="{
|
||||||
|
'row-key': 'id',
|
||||||
|
selection: 'multiple',
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<template #actions="{ row }">
|
|
||||||
<QBtn
|
|
||||||
:label="t('components.smartCard.openSummary')"
|
|
||||||
@click.stop="viewSummary(row.id, ParkingSummary)"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
</VnSection>
|
</VnSection>
|
||||||
</template>
|
<QPageSticky :offset="[20, 20]">
|
||||||
|
<RouterLink :to="{ name: 'ParkingCreate' }">
|
||||||
|
<QBtn fab icon="add" color="primary" v-shortcut="'+'" />
|
||||||
|
<QTooltip>
|
||||||
|
{{ $t('shelving.list.newShelving') }}
|
||||||
|
</QTooltip>
|
||||||
|
</RouterLink>
|
||||||
|
</QPageSticky>
|
||||||
|
</template>
|
|
@ -2,4 +2,9 @@ parking:
|
||||||
pickingOrder: Picking order
|
pickingOrder: Picking order
|
||||||
sector: Sector
|
sector: Sector
|
||||||
search: Search parking
|
search: Search parking
|
||||||
searchInfo: You can search by parking code
|
searchInfo: You can search by parking code
|
||||||
|
block: Block
|
||||||
|
streetFrom: Street from
|
||||||
|
streetTo: Street to
|
||||||
|
numberFrom: Number from
|
||||||
|
numberTo: Number to
|
||||||
|
|
|
@ -2,4 +2,9 @@ parking:
|
||||||
pickingOrder: Orden de recogida
|
pickingOrder: Orden de recogida
|
||||||
sector: Sector
|
sector: Sector
|
||||||
search: Buscar parking
|
search: Buscar parking
|
||||||
searchInfo: Puedes buscar por código de parking
|
searchInfo: Puedes buscar por código de parking
|
||||||
|
block: Bloque
|
||||||
|
streetFrom: Calle desde
|
||||||
|
streetTo: Calle hasta
|
||||||
|
numberFrom: Número desde
|
||||||
|
numberTo: Número hasta
|
||||||
|
|
|
@ -128,6 +128,16 @@ export default {
|
||||||
parkingCard,
|
parkingCard,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'parking/create',
|
||||||
|
name: 'ParkingCreate',
|
||||||
|
meta: {
|
||||||
|
title: 'parkingCreate',
|
||||||
|
icon: 'add',
|
||||||
|
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Shelving/Parking/ParkingCreate.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -145,5 +145,16 @@
|
||||||
"allowedContentTypes": [
|
"allowedContentTypes": [
|
||||||
"application/x-7z-compressed"
|
"application/x-7z-compressed"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"parkingStorage": {
|
||||||
|
"name": "parkingStorage",
|
||||||
|
"connector": "loopback-component-storage",
|
||||||
|
"provider": "filesystem",
|
||||||
|
"root": "./storage/pdfs/parking",
|
||||||
|
"maxFileSize": "52428800",
|
||||||
|
"allowedContentTypes": [
|
||||||
|
"application/octet-stream",
|
||||||
|
"application/pdf"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue