Merge remote-tracking branch 'origin/dev' into feature/ZoneLocations
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Javier Segarra 2024-05-22 15:49:23 +02:00
commit e2b72f132c
6 changed files with 207 additions and 145 deletions

View File

@ -1,6 +1,6 @@
{
"name": "salix-front",
"version": "24.22.0",
"version": "24.24.0",
"description": "Salix frontend",
"productName": "Salix",
"author": "Verdnatura",

View File

@ -35,7 +35,7 @@ const $props = defineProps({
downloadModel: {
type: String,
required: false,
default: null,
default: undefined,
},
defaultDmsCode: {
type: String,

View File

@ -170,23 +170,6 @@ watch([year, businessFk], () => refreshData());
ref="WorkerFreelanceRef"
auto-load
/>
<template v-if="stateStore.isHeaderMounted()">
<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">
<WorkerCalendarFilter

View File

@ -1,140 +1,212 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { onMounted, ref, computed } from 'vue';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
import { useRole } from 'src/composables/useRole';
import { ref, computed } from 'vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
import FetchData from 'components/FetchData.vue';
import FormModelPopup from 'src/components/FormModelPopup.vue';
import { useVnConfirm } from 'composables/useVnConfirm';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
const route = useRoute();
const { t } = useI18n();
const { notify } = useNotify();
const { hasAny } = useRole();
const fetchCurrentDeviceRef = ref(null);
const deviceProductionsFilter = {
fields: ['id', 'serialNumber', 'modelFk'],
where: { stateFk: 'idle' },
order: 'id',
};
const deviceProductionsOptions = ref([]);
const newPDA = ref({});
const currentPDA = ref(null);
const paginate = ref();
const dialog = ref();
const route = useRoute();
const { openConfirmationModal } = useVnConfirm();
const routeId = computed(() => route.params.id);
const isAllowedToEdit = computed(() => hasAny(['hr', 'productionAssi']));
const initialData = computed(() => {
return {
userFk: routeId.value,
deviceProductionFk: null,
simSerialNumber: null,
};
});
const setCurrentPDA = (data) => {
currentPDA.value = data;
currentPDA.value.description = `ID: ${currentPDA.value.deviceProductionFk} ${t(
'worker.pda.model'
)}: ${currentPDA.value.deviceProduction.modelFk} ${t('worker.pda.serialNumber')}: ${
currentPDA.value.deviceProduction.serialNumber
}`;
};
const deallocatePDA = async (data) => {
const deallocatePDA = async (deviceProductionFk) => {
try {
await axios.post(`Workers/${route.params.id}/deallocatePDA`, {
pda: currentPDA.value.deviceProductionFk,
pda: deviceProductionFk,
});
data.pda = null;
currentPDA.value = null;
await fetchCurrentDeviceRef.value.fetch();
notify(t('PDA deallocated'), 'positive');
} catch (err) {
console.error('Error deallocating PDA');
}
paginate.value.fetch();
};
onMounted(async () => await fetchCurrentDeviceRef.value.fetch());
function reloadData() {
initialData.value.deviceProductionFk = null;
initialData.value.simSerialNumber = null;
paginate.value.fetch();
}
</script>
<template>
<FetchData
url="DeviceProductions"
:filter="deviceProductionsFilter"
auto-load
@on-fetch="(data) => (deviceProductionsOptions = data)"
/>
<FetchData
ref="fetchCurrentDeviceRef"
url="DeviceProductionUsers"
:filter="{
where: { userFk: route.params.id },
include: { relation: 'deviceProduction' },
}"
auto-load
@on-fetch="(data) => setCurrentPDA(data[0])"
/>
<QPage class="column items-center q-pa-md">
<FormModel
url="DeviceProductionUsers"
:url-create="`Workers/${route.params.id}/allocatePDA`"
model="DeviceProductionUser"
:form-initial-data="newPDA"
<QPage class="column items-center q-pa-md centerCard">
<FetchData
url="workers/getAvailablePda"
@on-fetch="(data) => (deviceProductions = data)"
auto-load
/>
<VnPaginate
ref="paginate"
data-key="WorkerPda"
url="DeviceProductionUsers"
:filter="{ where: { userFk: routeId } }"
order="id"
auto-load
:default-buttons="{ save: { label: 'globals.assign', color: 'primary' } }"
@on-data-saved="(_, data) => setCurrentPDA(data)"
>
<template #form="{ data }">
<QField
v-if="currentPDA && currentPDA.description"
:label="t('worker.pda.currentPDA')"
:model-value="currentPDA.description"
:editable="false"
class="full-width"
<template #body="{ rows }">
<QCard
flat
bordered
:key="row.id"
v-for="row of rows"
class="card q-pt-xs q-mb-sm"
>
<template #control>
<div tabindex="0">
{{ currentPDA.description }}
</div>
</template>
<template v-if="isAllowedToEdit" #append>
<QIcon
name="delete"
size="sm"
class="cursor-pointer"
color="primary"
@click="deallocatePDA(data)"
>
<QTooltip>
{{ t('worker.pda.removePDA') }}
</QTooltip>
</QIcon>
</template>
</QField>
<VnSelect
v-else
:label="t('worker.pda.newPDA')"
v-model="data.pda"
:options="deviceProductionsOptions"
option-label="serialNumber"
option-value="id"
hide-selected
:disable="!isAllowedToEdit"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>ID: {{ scope.opt?.id }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.modelFk }},
{{ scope.opt?.serialNumber }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<QItem>
<QItemSection side-left>
<VnRow>
<QField
:label="t('worker.pda.currentPDA')"
:model-value="row?.deviceProductionFk"
disable
>
<template #control>
<div tabindex="0" style="padding: none">
<span>Id: </span>
<span>
{{ row?.deviceProductionFk }}&nbsp;
</span>
<span>{{ t('Model') }}: </span>
<span>
{{ row?.deviceProduction?.modelFk }}&nbsp;
</span>
<span>{{ t('SIM serial number') }}: </span>
<span>
{{
row?.deviceProduction?.serialNumber
}}&nbsp;
</span>
</div>
</template>
</QField>
<QField
:label="t('Current SIM')"
:model-value="row?.simSerialNumber"
disable
>
<template #control>
<div tabindex="0">{{ row?.simSerialNumber }}</div>
</template>
</QField>
</VnRow>
</QItemSection>
<QItemSection side>
<QIcon
name="delete"
size="sm"
class="cursor-pointer"
color="primary"
@click="
openConfirmationModal(
t(`Remove PDA`),
t('Do you want to remove this PDA?'),
() => deallocatePDA(row.deviceProductionFk)
)
"
>
<QTooltip>
{{ t('worker.pda.removePDA') }}
</QTooltip>
</QIcon>
</QItemSection>
</QItem>
</QCard>
</template>
</FormModel>
</VnPaginate>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="dialog.show()" color="primary" fab icon="add">
<QDialog ref="dialog">
<FormModelPopup
:title="t('Add new device')"
url-create="DeviceProductionUsers"
model="DeviceProductionUser"
:form-initial-data="initialData"
@on-data-saved="reloadData()"
>
<template #form-inputs="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
:label="t('worker.pda.newPDA')"
v-model="data.deviceProductionFk"
:options="deviceProductions"
option-label="id"
option-value="id"
id="deviceProductionFk"
hide-selected
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel
>ID: {{ scope.opt?.id }}</QItemLabel
>
<QItemLabel caption>
{{ scope.opt?.modelFk }},
{{ scope.opt?.serialNumber }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnInput
v-model="data.simSerialNumber"
:label="t('SIM serial number')"
id="simSerialNumber"
use-input
/>
</VnRow>
</template>
</FormModelPopup>
</QDialog>
</QBtn>
<QTooltip>
{{ t('globals.new') }}
</QTooltip>
</QPageSticky>
</QPage>
</template>
<style lang="scss" scoped>
.centerCard {
padding: 5%;
width: 100%;
max-width: 70%;
margin: 0 auto;
}
.label {
color: red;
}
.q-field {
height: 65px;
}
</style>
<i18n>
es:
Remove PDA: Eliminar PDA
Do you want to remove this PDA?: ¿Desea eliminar este PDA?
PDA deallocated: PDA desasignada
SIM serial number: Número de serie de la SIM
Model: Modelo
This PDA is already assigned to another user: Este PDA ya está asignado a otro usuario
Add new device: Añadir nuevo dispositivo
</i18n>

View File

@ -489,23 +489,6 @@ onMounted(async () => {
</QBtnGroup>
</div>
</Teleport>
<template v-if="stateStore.isHeaderMounted()">
<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="260" class="q-pa-md">
<div class="q-pa-md q-mb-md" style="border: 2px solid #222">
<QCardSection horizontal>

View File

@ -0,0 +1,24 @@
describe('WorkerPda', () => {
const deviceProductionField =
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
beforeEach(() => {
cy.viewport(1920, 1080);
cy.login('developer');
cy.visit(`/#/worker/1110/pda`);
});
it('assign pda', () => {
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
cy.get(deviceProductionField).type('{downArrow}{enter}');
cy.get('.vn-row > #simSerialNumber').type('123{enter}');
cy.get('.q-notification__message').should('have.text', 'Data created');
});
it('delete pda', () => {
cy.get('.q-card > .q-item > .q-item__section--side > .q-icon').click();
cy.get(
'.q-card__actions > .q-btn--unelevated > .q-btn__content > .block'
).click();
cy.get('.q-notification__message').should('have.text', 'PDA deallocated');
});
});