<script setup> import { computed, ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { useSession } from 'composables/useSession'; import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useQuasar } from 'quasar'; import { toDate } from 'src/filters'; import { useRouter } from 'vue-router'; import axios from 'axios'; import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue'; import RouteListTicketsDialog from 'pages/Route/Card/RouteListTicketsDialog.vue'; import RouteSummary from 'pages/Route/Card/RouteSummary.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnInputDate from 'components/common/VnInputDate.vue'; import VnTable from 'components/VnTable/VnTable.vue'; const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); const quasar = useQuasar(); const session = useSession(); const selectedRows = ref([]); const tableRef = ref([]); const confirmationDialog = ref(false); const startingDate = ref(null); const refreshKey = ref(0); const router = useRouter(); const routeFilter = { include: [ { relation: 'workers', scope: { fields: ['id', 'firstName'], }, }, ], }; const columns = computed(() => [ { align: 'left', name: 'id', label: 'Id', chip: { condition: () => true, }, isId: true, columnFilter: { name: 'search', }, }, { align: 'left', name: 'workerFk', label: t('Worker'), create: true, component: 'select', attrs: { url: 'Workers/activeWithInheritedRole', fields: ['id', 'nickname'], optionValue: 'id', optionLabel: 'nickname', }, useLike: false, cardVisible: true, format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef), }, { align: 'left', name: 'agencyModeFk', label: t('Agency'), isTitle: true, cardVisible: true, create: true, component: 'select', attrs: { url: 'agencyModes', fields: ['id', 'name'], optionLabel: 'name', optionValue: 'id', }, }, { align: 'left', name: 'vehicleFk', label: t('Vehicle'), cardVisible: true, create: true, component: 'select', attrs: { url: 'vehicles', fields: ['id', 'numberPlate'], optionLabel: 'numberPlate', optionValue: 'id', }, }, { align: 'left', name: 'created', label: t('Date'), cardVisible: true, create: true, component: 'date', columnFilter: { alias: 'c', inWhere: true, }, format: ({ date }) => toDate(date), }, { align: 'center', name: 'm3', label: 'volume', cardVisible: true, }, { align: 'left', name: 'description', label: t('Description'), isTitle: true, create: true, component: 'input', field: 'description', }, { align: 'left', name: 'started', label: t('hourStarted'), component: 'time', }, { align: 'left', name: 'finished', label: t('hourFinished'), component: 'time', }, { align: 'left', name: 'isOk', label: t('Served'), component: 'checkbox', }, { align: 'right', name: 'tableActions', actions: [ { title: t('Add tickets'), icon: 'vn:ticketAdd', action: (row) => openTicketsDialog(row?.id), }, { title: t('Preview'), icon: 'preview', action: (row) => viewSummary(row?.id, RouteSummary), }, { title: t('Route summary'), icon: 'arrow_forward', isPrimary: true, action: (row) => navigate(row?.id), }, ], }, ]); function navigate(id) { router.push({ path: `/route/${id}` }); } const cloneRoutes = () => { if (!selectedRows.value.length || !startingDate.value) return; axios.post('Routes/clone', { created: startingDate.value, ids: selectedRows.value.map((row) => row?.id), }); tableRef.value.reload(); startingDate.value = null; }; const showRouteReport = () => { const ids = selectedRows.value.map((row) => row?.id); const idString = ids.join(','); let url; if (selectedRows.value.length <= 1) { url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getTokenMultimedia()}`; } else { const params = new URLSearchParams({ access_token: session.getTokenMultimedia(), id: idString, }); url = `api/Routes/downloadZip?${params.toString()}`; } window.open(url, '_blank'); }; function markAsServed() { selectedRows.value.forEach(async (row) => { await axios.patch(`Routes/${row?.id}`, { isOk: true }); }); tableRef.value.reload(); startingDate.value = null; } const openTicketsDialog = (id) => { quasar .dialog({ component: RouteListTicketsDialog, componentProps: { id, }, }) .onOk(() => refreshKey.value++); }; </script> <template> <RouteSearchbar /> <QDialog v-model="confirmationDialog"> <QCard style="min-width: 350px"> <QCardSection> <p class="text-h6 q-ma-none">{{ t('Select the starting date') }}</p> </QCardSection> <QCardSection class="q-pt-none"> <VnInputDate :label="t('Stating date')" v-model="startingDate" autofocus /> </QCardSection> <QCardActions align="right"> <QBtn flat :label="t('Cancel')" v-close-popup class="text-primary" /> <QBtn color="primary" v-close-popup @click="cloneRoutes"> {{ t('globals.clone') }} </QBtn> </QCardActions> </QCard> </QDialog> <VnSubToolbar /> <VnTable ref="tableRef" data-key="RouteList" url="Routes/filter" :columns="columns" :right-search="true" :is-editable="true" :filter="routeFilter" redirect="route" :create="{ urlCreate: 'Routes', title: t('Create route'), onDataSaved: ({ id }) => tableRef.redirect(id), formInitialData: {}, }" save-url="Routes/crud" :disable-option="{ card: true }" :use-model="true" table-height="85vh" v-model:selected="selectedRows" :table="{ 'row-key': 'id', selection: 'multiple', }" > <template #moreBeforeActions> <QBtn icon="vn:clone" color="primary" class="q-mr-sm" :disable="!selectedRows?.length" @click="confirmationDialog = true" > <QTooltip>{{ t('Clone Selected Routes') }}</QTooltip> </QBtn> <QBtn icon="cloud_download" color="primary" class="q-mr-sm" :disable="!selectedRows?.length" @click="showRouteReport" > <QTooltip>{{ t('Download selected routes as PDF') }}</QTooltip> </QBtn> <QBtn icon="check" color="primary" class="q-mr-sm" :disable="!selectedRows?.length" @click="markAsServed()" > <QTooltip>{{ t('Mark as served') }}</QTooltip> </QBtn> </template> </VnTable> </template> <style lang="scss" scoped> .table-input-cell { max-width: 143px; } .route-list { width: 100%; max-height: 100%; } .table-actions { gap: 12px; } th:last-child, td:last-child { background-color: var(--vn-section-color); position: sticky; right: 0; } </style> <i18n> en: newRoute: New Route hourStarted: Started hour hourFinished: Finished hour es: Worker: Trabajador Agency: Agencia Vehicle: Vehículo Date: Fecha Description: Descripción Hour started: Hora inicio Hour finished: Hora fin Served: Servida newRoute: Nueva Ruta Clone Selected Routes: Clonar rutas seleccionadas Select the starting date: Seleccione la fecha de inicio Stating date: Fecha de inicio Cancel: Cancelar Mark as served: Marcar como servidas Download selected routes as PDF: Descargar rutas seleccionadas como PDF Add ticket: Añadir tickets Preview: Vista previa Summary: Resumen Route is closed: La ruta está cerrada Route is not served: La ruta no está servida hourStarted: Hora de inicio hourFinished: Hora de fin </i18n>