#7119 add VehicleList page and routing configuration #1129

Merged
jorgep merged 71 commits from 7119-createVehicle into dev 2025-02-06 09:24:16 +00:00
22 changed files with 814 additions and 21 deletions

View File

@ -97,7 +97,7 @@ const $props = defineProps({
}); });
const emit = defineEmits(['onFetch', 'onDataSaved']); const emit = defineEmits(['onFetch', 'onDataSaved']);
const modelValue = computed( const modelValue = computed(
() => $props.model ?? `formModel_${route?.meta?.title ?? route.name}` () => $props.model ?? `formModel_${route?.meta?.title ?? route.name}`,
).value; ).value;
const componentIsRendered = ref(false); const componentIsRendered = ref(false);
const arrayData = useArrayData(modelValue); const arrayData = useArrayData(modelValue);
@ -148,7 +148,7 @@ onMounted(async () => {
JSON.stringify(newVal) !== JSON.stringify(originalData.value); JSON.stringify(newVal) !== JSON.stringify(originalData.value);
isResetting.value = false; isResetting.value = false;
}, },
{ deep: true } { deep: true },
); );
} }
}); });
@ -156,7 +156,7 @@ onMounted(async () => {
if (!$props.url) if (!$props.url)
watch( watch(
() => arrayData.store.data, () => arrayData.store.data,
(val) => updateAndEmit('onFetch', val) (val) => updateAndEmit('onFetch', val),
); );
watch( watch(
@ -165,7 +165,7 @@ watch(
originalData.value = null; originalData.value = null;
reset(); reset();
await fetch(); await fetch();
} },
); );
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
@ -254,7 +254,7 @@ function filter(value, update, filterOptions) {
(ref) => { (ref) => {
ref.setOptionIndex(-1); ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true); ref.moveOptionSelection(1, true);
} },
); );
} }

View File

@ -73,7 +73,7 @@ onBeforeMount(async () => {
() => [$props.url, $props.filter], () => [$props.url, $props.filter],
async () => { async () => {
if (!isSameDataKey.value) await getData(); if (!isSameDataKey.value) await getData();
} },
); );
}); });
@ -108,7 +108,7 @@ const iconModule = computed(() => route.matched[1].meta.icon);
const toModule = computed(() => const toModule = computed(() =>
route.matched[1].path.split('/').length > 2 route.matched[1].path.split('/').length > 2
? route.matched[1].redirect ? route.matched[1].redirect
: route.matched[1].children[0].redirect : route.matched[1].children[0].redirect,
); );
</script> </script>

View File

@ -208,4 +208,13 @@ async function fetch() {
.summaryHeader { .summaryHeader {
color: $white; color: $white;
} }
.cardSummary :deep(.q-card__section[content]) {
display: flex;
flex-wrap: wrap;
padding: 0;
> * {
flex: 1;
}
}
</style> </style>

View File

@ -114,7 +114,7 @@ async function clearFilters() {
arrayData.resetPagination(); arrayData.resetPagination();
// Filtrar los params no removibles // Filtrar los params no removibles
const removableFilters = Object.keys(userParams.value).filter((param) => const removableFilters = Object.keys(userParams.value).filter((param) =>
$props.unremovableParams.includes(param) $props.unremovableParams.includes(param),
); );
const newParams = {}; const newParams = {};
// Conservar solo los params que no son removibles // Conservar solo los params que no son removibles
@ -162,13 +162,13 @@ const formatTags = (tags) => {
const tags = computed(() => { const tags = computed(() => {
const filteredTags = tagsList.value.filter( const filteredTags = tagsList.value.filter(
(tag) => !($props.customTags || []).includes(tag.label) (tag) => !($props.customTags || []).includes(tag.label),
); );
return formatTags(filteredTags); return formatTags(filteredTags);
}); });
const customTags = computed(() => const customTags = computed(() =>
tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label)) tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label)),
); );
async function remove(key) { async function remove(key) {
@ -188,10 +188,13 @@ function formatValue(value) {
const getLocale = (label) => { const getLocale = (label) => {
const param = label.split('.').at(-1); const param = label.split('.').at(-1);
const globalLocale = `globals.params.${param}`; const globalLocale = `globals.params.${param}`;
const moduleName = route.meta.moduleName;
const moduleLocale = `${moduleName.toLowerCase()}.${param}`;
if (te(globalLocale)) return t(globalLocale); if (te(globalLocale)) return t(globalLocale);
else if (te(t(`params.${param}`))); else if (te(moduleLocale)) return t(moduleLocale);
else { else {
const camelCaseModuleName = route.meta.moduleName.charAt(0).toLowerCase() + route.meta.moduleName.slice(1); const camelCaseModuleName =
moduleName.charAt(0).toLowerCase() + moduleName.slice(1);
return t(`${camelCaseModuleName}.params.${param}`); return t(`${camelCaseModuleName}.params.${param}`);
} }
}; };

View File

@ -212,6 +212,10 @@ select:-webkit-autofill {
justify-content: center; justify-content: center;
} }
.q-card__section[dense] {
padding: 0;
}
input[type='number'] { input[type='number'] {
-moz-appearance: textfield; -moz-appearance: textfield;
} }

View File

@ -332,10 +332,13 @@ globals:
wasteRecalc: Waste recaclulate wasteRecalc: Waste recaclulate
operator: Operator operator: Operator
parking: Parking parking: Parking
vehicleList: Vehicles
vehicle: Vehicle
unsavedPopup: unsavedPopup:
title: Unsaved changes will be lost title: Unsaved changes will be lost
subtitle: Are you sure exit without saving? subtitle: Are you sure exit without saving?
params: params:
description: Description
clientFk: Client id clientFk: Client id
salesPersonFk: Sales person salesPersonFk: Sales person
warehouseFk: Warehouse warehouseFk: Warehouse
@ -358,7 +361,13 @@ globals:
correctingFk: Rectificative correctingFk: Rectificative
daysOnward: Days onward daysOnward: Days onward
countryFk: Country countryFk: Country
countryCodeFk: Country
companyFk: Company companyFk: Company
model: Model
fuel: Fuel
active: Active
inactive: Inactive
deliveryPoint: Delivery point
errors: errors:
statusUnauthorized: Access denied statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred statusInternalServerError: An internal server error has ocurred

View File

@ -332,10 +332,13 @@ globals:
wasteRecalc: Recalcular mermas wasteRecalc: Recalcular mermas
operator: Operario operator: Operario
parking: Parking parking: Parking
vehicleList: Vehículos
vehicle: Vehículo
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?
params: params:
description: Descripción
clientFk: Id cliente clientFk: Id cliente
salesPersonFk: Comercial salesPersonFk: Comercial
warehouseFk: Almacén warehouseFk: Almacén
@ -356,6 +359,7 @@ globals:
daysOnward: Días adelante daysOnward: Días adelante
packing: ITP packing: ITP
countryFk: País countryFk: País
countryCodeFk: País
companyFk: Empresa companyFk: Empresa
errors: errors:
statusUnauthorized: Acceso denegado statusUnauthorized: Acceso denegado

View File

@ -74,7 +74,7 @@ const { openConfirmationModal } = useVnConfirm();
openConfirmationModal( openConfirmationModal(
t('Are you sure you want to delete it?'), t('Are you sure you want to delete it?'),
t('Delete department'), t('Delete department'),
removeDepartment removeDepartment,
) )
" "
> >

View File

@ -100,7 +100,7 @@ const emit = defineEmits(['search']);
<VnSelect <VnSelect
:label="t('Vehicle')" :label="t('Vehicle')"
v-model="params.vehicleFk" v-model="params.vehicleFk"
url="Vehicles" url="Vehicles/active"
sort-by="numberPlate ASC" sort-by="numberPlate ASC"
option-value="id" option-value="id"
option-label="numberPlate" option-label="numberPlate"

View File

@ -99,7 +99,7 @@ const onSave = (data, response) => {
<VnSelect <VnSelect
:label="t('Vehicle')" :label="t('Vehicle')"
v-model="data.vehicleFk" v-model="data.vehicleFk"
url="Vehicles" url="Vehicles/active"
sort-by="numberPlate ASC" sort-by="numberPlate ASC"
option-value="id" option-value="id"
option-label="numberPlate" option-label="numberPlate"

View File

@ -96,8 +96,7 @@ const columns = computed(() => [
create: true, create: true,
component: 'select', component: 'select',
attrs: { attrs: {
url: 'vehicles', url: 'vehicles/active',
fields: ['id', 'numberPlate'],
optionLabel: 'numberPlate', optionLabel: 'numberPlate',
optionFilterValue: 'numberPlate', optionFilterValue: 'numberPlate',
find: { find: {

View File

@ -0,0 +1,162 @@
<script setup>
import { ref } from 'vue';
import FormModel from 'components/FormModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
const warehouses = ref([]);
const companies = ref([]);
const countries = ref([]);
const fuelTypes = ref([]);
const bankPolicies = ref([]);
const deliveryPoints = ref([]);
</script>
<template>
<FetchData
url="Warehouses"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (warehouses = data)"
auto-load
/>
<FetchData
url="Companies"
:filter="{ fields: ['id', 'code'] }"
@on-fetch="(data) => (companies = data)"
auto-load
/>
<FetchData
url="Countries"
:filter="{ fields: ['code'] }"
@on-fetch="(data) => (countries = data)"
auto-load
/>
<FetchData
url="FuelTypes"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (fuelTypes = data)"
auto-load
/>
<FetchData
url="DeliveryPoints"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (deliveryPoints = data)"
auto-load
/>
<FormModel model="Vehicle" :url-update="`Vehicles/${$route.params.id}`">
<template #form="{ data }">
<VnRow>
<VnInput v-model="data.description" :label="$t('globals.description')" />
<VnInput v-model="data.numberPlate" :label="$t('vehicle.numberPlate')" />
</VnRow>
<VnRow>
<VnInput
v-model="data.model"
:label="$t('globals.model')"
:required="true"
/>
<VnSelect
url="VehicleTypes"
v-model="data.vehicleTypeFk"
:label="$t('globals.type')"
/>
</VnRow>
<VnRow>
<VnInput
v-model="data.tradeMark"
:label="$t('vehicle.tradeMark')"
:required="true"
/>
<VnInput v-model="data.chassis" :label="$t('vehicle.chassis')" />
</VnRow>
<VnRow>
<VnSelect
v-model="data.fuelTypeFk"
:label="$t('globals.fuel')"
:options="fuelTypes"
/>
<VnSelect
v-model="data.deliveryPointFk"
:label="$t('globals.deliveryPoint')"
:options="deliveryPoints"
/>
</VnRow>
<VnRow>
<VnSelect
v-model="data.companyFk"
:label="$t('globals.company')"
:options="companies"
option-label="code"
/>
<VnSelect
v-model="data.warehouseFk"
:label="$t('globals.warehouse')"
:options="warehouses"
/>
</VnRow>
<VnRow>
<VnSelect
url="Suppliers"
:filter="{ fields: ['id', 'name'] }"
v-model="data.supplierFk"
:label="$t('globals.supplier')"
/>
<VnSelect
url="Suppliers"
:filter="{ fields: ['id', 'name'] }"
v-model="data.supplierCoolerFk"
:label="$t('vehicle.supplierCooler')"
/>
</VnRow>
<VnRow>
<VnSelect
url="BankPolicies"
:filter="{ fields: ['id', 'ref'] }"
v-model="data.bankPolicyFk"
:label="$t('vehicle.leasing')"
:options="bankPolicies"
option-label="ref"
option-value="id"
/>
<VnInput v-model="data.leasing" :label="$t('vehicle.nLeasing')" />
</VnRow>
<VnRow>
<VnInputNumber v-model="data.import" :label="$t('globals.amount')" />
<VnInputNumber
v-model="data.importCooler"
:label="$t('vehicle.amountCooler')"
/>
</VnRow>
<VnRow>
<VnSelect
url="Ppes"
option-label="id"
v-model="data.ppeFk"
:label="$t('vehicle.ppe')"
/>
<VnSelect
v-model="data.countryCodeFk"
:label="$t('globals.country')"
:options="countries"
option-label="code"
option-value="code"
/>
</VnRow>
<VnRow>
<VnInput v-model="data.vin" :label="$t('vehicle.vin')" />
<span :style="{ 'align-self': $q.screen.gt.xs ? 'end' : 'unset' }">
<QCheckbox
v-model="data.isActive"
:label="$t('vehicle.isActive')"
:false-value="0"
:true-value="1"
dense
class="q-mt-sm"
/>
</span>
</VnRow>
</template>
</FormModel>
</template>

View File

@ -0,0 +1,13 @@
<script setup>
import VnCardBeta from 'components/common/VnCardBeta.vue';
import VehicleDescriptor from './VehicleDescriptor.vue';
import VehicleFilter from '../VehicleFilter.js';
</script>
<template>
<VnCardBeta
data-key="Vehicle"
base-url="Vehicles"
:filter="VehicleFilter"
:descriptor="VehicleDescriptor"
/>
</template>

View File

@ -0,0 +1,50 @@
<script setup>
import VnLv from 'src/components/ui/VnLv.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
const { notify } = useNotify();
</script>
<template>
<CardDescriptor
:url="`Vehicles/${$route.params.id}`"
module="Vehicle"
data-key="Vehicle"
title="numberPlate"
:to-module="{ name: 'VehicleList' }"
>
<template #menu="{ entity }">
<QItem
data-cy="delete"
v-ripple
clickable
@click="
async () => {
try {
await axios.delete(`Vehicles/${entity.id}`);
notify('vehicle.remove', 'positive');
$router.push({ name: 'VehicleList' });
} catch (e) {
throw e;
}
}
"
>
<QItemSection>
{{ $t('vehicle.delete') }}
</QItemSection>
</QItem>
</template>
<template #body="{ entity }">
<VnLv :label="$t('vehicle.numberPlate')" :value="entity.numberPlate" />
<VnLv :label="$t('vehicle.tradeMark')" :value="entity.tradeMark" />
<VnLv :label="$t('globals.model')" :value="entity.model" />
<VnLv :label="$t('globals.country')" :value="entity.countryCodeFk" />
</template>
</CardDescriptor>
</template>
<i18n>
es:
Vehicle removed: Vehículo eliminado
</i18n>

View File

@ -0,0 +1,127 @@
<script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import VehicleFilter from '../VehicleFilter.js';
import { downloadFile } from 'src/composables/downloadFile';
import { dashIfEmpty } from 'src/filters';
const props = defineProps({ id: { type: [Number, String], default: null } });
const route = useRoute();
const entityId = computed(() => props.id || +route.params.id);
const links = {
'basic-data': `#/vehicle/${entityId.value}/basic-data`,
notes: `#/vehicle/${entityId.value}/notes`,
dms: `#/vehicle/${entityId.value}/dms`,
'invoice-in': `#/vehicle/${entityId.value}/invoice-in`,
events: `#/vehicle/${entityId.value}/events`,
};
</script>
<template>
<CardSummary data-key="Vehicle" :url="`Vehicles/${entityId}`" :filter="VehicleFilter">
<template #header="{ entity }">
<div>{{ entity.id }} - {{ entity.numberPlate }}</div>
</template>
<template #body="{ entity }">
<QCard class="vn-one">
<QCardSection dense>
<VnTitle
:url="links['basic-data']"
:text="$t('globals.pageTitles.basicData')"
/>
</QCardSection>
<QCardSection content>
<QList dense>
<VnLv
:label="$t('globals.description')"
:value="entity.description"
/>
<VnLv
:label="$t('vehicle.tradeMark')"
:value="entity.tradeMark"
/>
<VnLv :label="$t('globals.model')" :value="entity.model" />
<VnLv :label="$t('globals.supplier')">
<template #value>
<span class="link">
{{ entity.supplier?.name }}
<SupplierDescriptorProxy :id="entity.supplierFk" />
</span>
</template>
</VnLv>
<VnLv :label="$t('vehicle.supplierCooler')">
<template #value>
<span class="link">
{{ entity.supplierCooler?.name }}
<SupplierDescriptorProxy
:id="entity.supplierCoolerFk"
/>
</span>
</template>
</VnLv>
<VnLv :label="$t('vehicle.vin')" :value="entity.vin" />
</QList>
<QList dense>
<VnLv :label="$t('vehicle.chassis')" :value="entity.chassis" />
<VnLv
:label="$t('globals.fuel')"
:value="entity.fuelType?.name"
/>
<VnLv :label="$t('vehicle.ppe')" :value="entity.ppeFk" />
<VnLv :label="$t('vehicle.nLeasing')" :value="entity.leasing" />
<VnLv
:label="$t('vehicle.leasing')"
:value="entity.bankPolicy?.ref"
>
<template #value>
<span v-text="dashIfEmpty(entity.bankPolicy?.name)" />
<QBtn
v-if="entity.bankPolicy?.dmsFk"
class="q-ml-xs"
color="primary"
flat
dense
icon="cloud_download"
@click="downloadFile(entity.bankPolicy?.dmsFk)"
>
<QTooltip>{{ $t('globals.download') }}</QTooltip>
</QBtn>
</template>
</VnLv>
<VnLv :label="$t('globals.amount')" :value="entity.import" />
</QList>
<QList dense>
<VnLv
:label="$t('globals.warehouse')"
:value="entity.warehouse?.name"
/>
<VnLv
:label="$t('globals.company')"
:value="entity.company?.code"
/>
<VnLv
:label="$t('globals.deliveryPoint')"
:value="entity.deliveryPoint?.name"
/>
<VnLv
:label="$t('globals.country')"
:value="entity.countryCodeFk"
/>
<VnLv
:label="$t('vehicle.isKmTruckRate')"
:value="!!entity.isKmTruckRate"
/>
<VnLv
:label="$t('vehicle.isActive')"
:value="!!entity.isActive"
/>
</QList>
</QCardSection>
</QCard>
</template>
</CardSummary>
</template>

View File

@ -0,0 +1,76 @@
export default {
fields: [
'id',
'description',
'isActive',
'isKmTruckRate',
'warehouseFk',
'companyFk',
'numberPlate',
'chassis',
'supplierFk',
'supplierCoolerFk',
'tradeMark',
'fuelTypeFk',
'import',
'importCooler',
'vin',
'model',
'ppeFk',
'countryCodeFk',
'leasing',
'bankPolicyFk',
'vehicleTypeFk',
'deliveryPointFk',
],
include: [
{
relation: 'warehouse',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'company',
scope: {
fields: ['id', 'code'],
},
},
{
relation: 'supplier',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'supplierCooler',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'fuelType',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'bankPolicy',
scope: {
fields: ['id', 'ref', 'dmsFk'],
},
},
{
relation: 'ppe',
scope: {
fields: ['id'],
},
},
{
relation: 'deliveryPoint',
scope: {
fields: ['id', 'name'],
},
},
],
};

View File

@ -0,0 +1,224 @@
<script setup>
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import VnTable from 'components/VnTable/VnTable.vue';
import FetchData from 'src/components/FetchData.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import VehicleSummary from 'src/pages/Route/Vehicle/Card/VehicleSummary.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSection from 'src/components/common/VnSection.vue';
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const warehouses = ref([]);
const companies = ref([]);
const countries = ref([]);
const vehicleStates = ref([]);
const vehicleTypes = ref([]);
const columns = computed(() => [
{
name: 'isActive',
columnFilter: false,
align: 'center',
},
{
name: 'id',
label: t('globals.id'),
isId: true,
chip: {
condition: () => true,
},
},
{
name: 'description',
label: t('globals.description'),
},
{
name: 'tradeMark',
label: t('vehicle.tradeMark'),
cardVisible: true,
},
{
name: 'numberPlate',
label: t('vehicle.numberPlate'),
isTitle: true,
},
{
name: 'vehicleTypeFk',
label: t('globals.type'),
format: (row) => row.type,
columnFilter: {
component: 'select',
name: 'vehicleTypeFk',
options: vehicleTypes.value,
},
cardVisible: true,
},
{
name: 'vehicleStateFk',
label: t('globals.state'),
columnFilter: {
component: 'select',
name: 'vehicleStateFk',
optionLabel: 'state',
options: vehicleStates.value,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.state),
},
{
name: 'chassis',
label: t('vehicle.chassis'),
},
{
name: 'leasing',
label: t('vehicle.leasing'),
},
{
name: 'warehouseFk',
label: t('globals.warehouse'),
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouse),
columnFilter: {
component: 'select',
name: 'warehouseFk',
options: warehouses.value,
},
cardVisible: true,
},
{
name: 'companyFk',
label: t('globals.company'),
format: (row, dashIfEmpty) => dashIfEmpty(row.company),
columnFilter: {
component: 'select',
name: 'companyFk',
optionLabel: 'code',
options: companies.value,
},
},
{
name: 'countryCodeFk',
label: t('globals.country'),
columnFilter: {
component: 'select',
name: 'countryCodeFk',
optionValue: 'code',
optionLabel: 'code',
options: countries.value,
},
},
{
align: 'right',
name: 'tableActions',
actions: [
{
title: t('components.smartCard.openSummary'),
icon: 'preview',
action: (row) => viewSummary(row.id, VehicleSummary),
},
],
},
]);
</script>
<template>
<FetchData
url="Warehouses"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (warehouses = data)"
auto-load
/>
<FetchData
url="Companies"
:filter="{ fields: ['id', 'code'] }"
@on-fetch="(data) => (companies = data)"
auto-load
/>
<FetchData
url="Countries"
:filter="{ fields: ['code'] }"
@on-fetch="(data) => (countries = data)"
auto-load
/>
<FetchData
url="VehicleStates"
:filter="{ fields: ['id', 'state'] }"
@on-fetch="(data) => (vehicleStates = data)"
auto-load
/>
<FetchData
url="VehicleTypes"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (vehicleTypes = data)"
auto-load
/>
<VnSection
data-key="VehicleList"
:columns="columns"
prefix="vehicle"
:array-data-props="{
url: 'Vehicles/filter',
}"
>
<template #body>
<VnTable
ref="tableRef"
data-key="VehicleList"
:columns="columns"
redirect="route/vehicle"
:create="{
urlCreate: 'Vehicles',
title: t('vehicle.create'),
onDataSaved: ({ id }) => $refs.tableRef.redirect(id),
formInitialData: { isActive: true, isKmTruckRate: false },
}"
:use-model="true"
:right-search="false"
>
<template #column-isActive="{ row }">
<span>
<QIcon
v-if="!row.isActive"
name="vn:inactive-car"
color="primary"
size="xs"
>
<QTooltip>{{ $t('globals.inactive') }}</QTooltip>
</QIcon>
</span>
</template>
<template #more-create-dialog="{ data }">
<VnInput
v-model="data.numberPlate"
:label="$t('vehicle.numberPlate')"
:uppercase="true"
/>
<VnInput v-model="data.tradeMark" :label="$t('vehicle.tradeMark')" />
<VnInput v-model="data.model" :label="$t('globals.model')" />
<VnSelect
v-model="data.vehicleTypeFk"
:label="$t('globals.type')"
:options="vehicleTypes"
/>
<VnSelect
v-model="data.warehouseFk"
:label="$t('globals.warehouse')"
:options="warehouses"
/>
<VnSelect
v-model="data.countryCodeFk"
:label="$t('globals.country')"
option-value="code"
option-label="code"
:options="countries"
/>
<VnInput
v-model="data.description"
:label="$t('globals.description')"
/>
<QCheckbox to v-model="data.isActive" :label="$t('globals.active')" />
</template>
</VnTable>
</template>
</VnSection>
</template>

View File

@ -0,0 +1,20 @@
vehicle:
tradeMark: Trade Mark
numberPlate: Nº Plate
chassis: Chassis
leasing: Leasing
isKmTruckRate: Trailer
delete: Delete Vehicle
supplierCooler: Supplier Cooler
vin: VIN
ppe: Ppe
isActive: Active
nLeasing: Nº Leasing
create: Create Vehicle
amountCooler: Amount cooler
remove: Vehicle removed
search: Search Vehicle
searchInfo: Search by id or number plate
params:
vehicleTypeFk: Type
vehicleStateFk: State

View File

@ -0,0 +1,20 @@
vehicle:
tradeMark: Marca
numberPlate: Matrícula
chassis: Nº de bastidor
leasing: Leasing
isKmTruckRate: Trailer
delete: Eliminar vehículo
supplierCooler: Proveedor Frío
vin: VIN
ppe: Nº Inmovilizado
create: Crear vehículo
amountCooler: Importe frío
isActive: Activo
nLeasing: Nº leasing
remove: Vehículo eliminado
search: Buscar Vehículo
searchInfo: Buscar por id o matrícula
params:
vehicleTypeFk: Tipo
vehicleStateFk: Estado

View File

@ -160,6 +160,36 @@ const roadmapCard = {
], ],
}; };
const vehicleCard = {
path: ':id',
name: 'VehicleCard',
component: () => import('src/pages/Route/Vehicle/Card/VehicleCard.vue'),
redirect: { name: 'VehicleSummary' },
meta: {
menu: ['VehicleBasicData'],
},
children: [
{
name: 'VehicleSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'view_list',
},
component: () => import('src/pages/Route/Vehicle/Card/VehicleSummary.vue'),
},
{
name: 'VehicleBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('src/pages/Route/Vehicle/Card/VehicleBasicData.vue'),
},
],
};
export default { export default {
name: 'Route', name: 'Route',
path: '/route', path: '/route',
@ -174,6 +204,7 @@ export default {
'RouteRoadmap', 'RouteRoadmap',
'CmrList', 'CmrList',
'AgencyList', 'AgencyList',
'VehicleList',
], ],
}, },
component: RouterView, component: RouterView,
@ -280,6 +311,27 @@ export default {
agencyCard, agencyCard,
], ],
}, },
{
path: 'vehicle',
name: 'RouteVehicle',
redirect: { name: 'VehicleList' },
meta: {
title: 'vehicle',
icon: 'directions_car',
},
component: () => import('src/pages/Route/Vehicle/VehicleList.vue'),
children: [
{
path: 'list',
name: 'VehicleList',
meta: {
title: 'vehicleList',
icon: 'directions_car',
},
},
vehicleCard,
],
},
], ],
}, },
], ],

View File

@ -0,0 +1,13 @@
describe('Vehicle', () => {
beforeEach(() => {
cy.viewport(1920, 1080);
cy.login('deliveryAssistant');
cy.visit(`/#/route/vehicle/7`);
});
it('should delete a vehicle', () => {
cy.openActionsDescriptor();
cy.get('[data-cy="delete"]').click();
cy.checkNotification('Vehicle removed');
});
});

View File

@ -1,5 +1,6 @@
describe('ZoneBasicData', () => { describe('ZoneBasicData', () => {
const priceBasicData = '[data-cy="Price_input"]'; const priceBasicData = '[data-cy="Price_input"]';
const saveBtn = '.q-btn-group > .q-btn--standard';
beforeEach(() => { beforeEach(() => {
cy.viewport(1280, 720); cy.viewport(1280, 720);
@ -8,20 +9,27 @@ describe('ZoneBasicData', () => {
}); });
it('should throw an error if the name is empty', () => { it('should throw an error if the name is empty', () => {
cy.get('[data-cy="zone-basic-data-name"] input').type('{selectall}{backspace}'); cy.intercept('GET', /\/api\/Zones\/4./).as('zone');
cy.get('.q-btn-group > .q-btn--standard').click();
cy.wait('@zone').then(() => {
cy.get('[data-cy="zone-basic-data-name"] input').type(
'{selectall}{backspace}',
);
});
cy.get(saveBtn).click();
cy.checkNotification("can't be blank"); cy.checkNotification("can't be blank");
}); });
it('should throw an error if the price is empty', () => { it('should throw an error if the price is empty', () => {
cy.get(priceBasicData).clear(); cy.get(priceBasicData).clear();
cy.get('.q-btn-group > .q-btn--standard').click(); cy.get(saveBtn).click();
cy.checkNotification('cannot be blank'); cy.checkNotification('cannot be blank');
}); });
it("should edit the basicData's zone", () => { it("should edit the basicData's zone", () => {
cy.get('.q-card > :nth-child(1)').type(' modified'); cy.get('.q-card > :nth-child(1)').type(' modified');
cy.get('.q-btn-group > .q-btn--standard').click(); cy.get(saveBtn).click();
cy.checkNotification('Data saved'); cy.checkNotification('Data saved');
}); });
}); });