0
0
Fork 0

Merge pull request 'Desarrollo de los submodulos basic data, notes y pbx' (!245) from hyervoni/salix-front-mindshore:features/ms_submodulos_worker into dev

Reviewed-on: verdnatura/salix-front#245
Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
Javier Segarra 2024-04-08 06:19:28 +00:00
commit dafc9f83b9
9 changed files with 364 additions and 12 deletions

View File

@ -227,6 +227,7 @@ watch(formUrl, async () => {
defineExpose({ defineExpose({
save, save,
isLoading, isLoading,
hasChanges,
}); });
</script> </script>
<template> <template>

View File

@ -82,6 +82,11 @@ select:-webkit-autofill {
color: $white; color: $white;
} }
.card-width {
max-width: 800px;
width: 100%;
}
.vn-card { .vn-card {
background-color: var(--vn-section-color); background-color: var(--vn-section-color);
color: var(--vn-text-color); color: var(--vn-text-color);

View File

@ -851,12 +851,14 @@ export default {
pageTitles: { pageTitles: {
workers: 'Workers', workers: 'Workers',
list: 'List', list: 'List',
basicData: 'Basic data',
summary: 'Summary', summary: 'Summary',
notifications: 'Notifications',
workerCreate: 'New worker', workerCreate: 'New worker',
department: 'Department', department: 'Department',
basicData: 'Basic data',
notes: 'Notes',
pda: 'PDA', pda: 'PDA',
notifications: 'Notifications',
pbx: 'Private Branch Exchange',
log: 'Log', log: 'Log',
}, },
list: { list: {

View File

@ -850,12 +850,14 @@ export default {
pageTitles: { pageTitles: {
workers: 'Trabajadores', workers: 'Trabajadores',
list: 'Listado', list: 'Listado',
basicData: 'Datos básicos',
summary: 'Resumen', summary: 'Resumen',
notifications: 'Notificaciones',
workerCreate: 'Nuevo trabajador', workerCreate: 'Nuevo trabajador',
department: 'Departamentos', department: 'Departamentos',
basicData: 'Datos básicos',
notes: 'Notas',
pda: 'PDA', pda: 'PDA',
notifications: 'Notificaciones',
pbx: 'Centralita',
log: 'Historial', log: 'Historial',
}, },
list: { list: {

View File

@ -0,0 +1,168 @@
<script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import FormModel from 'src/components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
const route = useRoute();
const { t } = useI18n();
const workersOptions = ref([]);
const countriesOptions = ref([]);
const educationLevelsOptions = ref([]);
const workerFilter = {
include: [
{
relation: 'user',
scope: {
fields: ['name', 'emailVerified'],
include: { relation: 'emailUser', scope: { fields: ['email'] } },
},
},
{ relation: 'sip', scope: { fields: ['extension', 'secret'] } },
{ relation: 'department', scope: { include: { relation: 'department' } } },
],
};
const workersFilter = {
fields: ['id', 'nickname'],
order: 'nickname ASC',
limit: 30,
};
const countriesFilter = {
fields: ['id', 'country', 'code'],
order: 'country ASC',
limit: 30,
};
const educationLevelsFilter = { fields: ['id', 'name'], order: 'name ASC', limit: 30 };
const maritalStatus = [
{ code: 'M', name: t('Married') },
{ code: 'S', name: t('Single') },
];
</script>
<template>
<FetchData
:filter="workersFilter"
@on-fetch="(data) => (workersOptions = data)"
auto-load
url="Workers/search"
/>
<FetchData
:filter="countriesFilter"
@on-fetch="(data) => (countriesOptions = data)"
auto-load
url="Countries"
/>
<FetchData
:filter="educationLevelsFilter"
@on-fetch="(data) => (educationLevelsOptions = data)"
auto-load
url="EducationLevels"
/>
<FormModel
:filter="workerFilter"
:url="`Workers/${route.params.id}`"
auto-load
model="Worker"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnInput :label="t('Name')" clearable v-model="data.firstName" />
<VnInput :label="t('Last name')" clearable v-model="data.lastName" />
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnInput v-model="data.phone" :label="t('Business phone')" clearable />
<VnInput
v-model="data.mobileExtension"
:label="t('Mobile extension')"
clearable
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelectFilter
:label="t('Boss')"
:options="workersOptions"
hide-selected
option-label="nickname"
option-value="id"
v-model="data.bossFk"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.nickname }},
{{ scope.opt?.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
<VnSelectFilter
:label="t('Marital status')"
:options="maritalStatus"
hide-selected
option-label="name"
option-value="code"
v-model="data.maritalStatus"
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelectFilter
:label="t('Origin country')"
:options="countriesOptions"
hide-selected
option-label="country"
option-value="id"
v-model="data.originCountryFk"
/>
<VnSelectFilter
:label="t('Education level')"
:options="educationLevelsOptions"
hide-selected
option-label="name"
option-value="id"
v-model="data.educationLevelFk"
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnInput v-model="data.SSN" :label="t('SSN')" clearable />
<VnInput
v-model="data.locker"
type="number"
:label="t('Locker')"
clearable
/>
</VnRow>
</template>
</FormModel>
</template>
<i18n>
es:
Name: Nombre
Last name: Apellidos
Business phone: Teléfono de empresa
Mobile extension: Extensión móvil
Boss: Jefe
Marital status: Estado civil
Married: Casado/a
Single: Soltero/a
Origin country: País origen
Education level: Nivel educación
SSN: NSS
Locker: Taquilla
</i18n>

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
@ -7,6 +7,7 @@ import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
import { useState } from 'src/composables/useState';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -23,6 +24,7 @@ const $props = defineProps({
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
const state = useState();
const entityId = computed(() => { const entityId = computed(() => {
return $props.id || route.params.id; return $props.id || route.params.id;
@ -53,7 +55,18 @@ const filter = {
], ],
}; };
const sip = computed(() => worker.value?.sip && worker.value.sip.extension); const sip = ref(null);
watch(
() => [worker.value?.sip?.extension, state.get('extension')],
([newWorkerSip, newStateExtension], [oldWorkerSip, oldStateExtension]) => {
if (newStateExtension !== oldStateExtension || sip.value === oldStateExtension) {
sip.value = newStateExtension;
} else if (newWorkerSip !== oldWorkerSip && sip.value !== newStateExtension) {
sip.value = newWorkerSip;
}
}
);
function getWorkerAvatar() { function getWorkerAvatar() {
const token = getTokenMultimedia(); const token = getTokenMultimedia();

View File

@ -0,0 +1,38 @@
<script setup>
import { useRoute } from 'vue-router';
import VnNotes from 'src/components/ui/VnNotes.vue';
const route = useRoute();
const filter = {
order: 'created DESC',
where: { workerFk: route.params.id },
include: {
relation: 'worker',
scope: {
fields: ['id', 'firstName', 'lastName'],
include: {
relation: 'user',
scope: {
fields: ['id', 'nickname'],
},
},
},
},
};
const body = {
workerFk: route.params.id,
};
</script>
<template>
<VnNotes
style="overflow-y: auto"
:add-note="{ type: Boolean, default: true }"
url="WorkerObservations"
:filter="filter"
:body="body"
/>
</template>

View File

@ -0,0 +1,70 @@
<script setup>
import { watch, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { useState } from 'src/composables/useState';
import FormModel from 'src/components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n();
const state = useState();
const route = useRoute();
const workerPBXForm = ref();
const extension = ref(null);
const filter = {
include: [
{
relation: 'sip',
},
],
};
watch(
() => route.params.id,
() => state.set('extension', null)
);
const onFetch = (data) => {
state.set('extension', data?.sip?.extension);
extension.value = state.get('extension');
};
const updateModelValue = (data) => {
state.set('extension', data);
workerPBXForm.value.hasChanges = true;
};
</script>
<template>
<FormModel
ref="workerPBXForm"
:filter="filter"
:url="`Workers/${route.params.id}`"
url-update="Sips"
auto-load
:mapper="
() => ({
userFk: +route.params.id,
extension,
})
"
model="DeviceProductionUser"
@on-fetch="onFetch"
>
<template #form="{}">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
:label="t('worker.summary.sipExtension')"
v-model="extension"
@update:model-value="updateModelValue"
/>
</div>
</VnRow>
</template>
</FormModel>
</template>

View File

@ -12,7 +12,14 @@ export default {
redirect: { name: 'WorkerMain' }, redirect: { name: 'WorkerMain' },
menus: { menus: {
main: ['WorkerList', 'WorkerDepartment'], main: ['WorkerList', 'WorkerDepartment'],
card: ['WorkerNotificationsManager', 'WorkerPda', 'WorkerLog'], card: [
'WorkerBasicData',
'WorkerNotes',
'WorkerPda',
'WorkerNotificationsManager',
'WorkerPBX',
'WorkerLog',
],
departmentCard: ['BasicData'], departmentCard: ['BasicData'],
}, },
children: [ children: [
@ -66,6 +73,52 @@ export default {
}, },
component: () => import('src/pages/Worker/Card/WorkerSummary.vue'), component: () => import('src/pages/Worker/Card/WorkerSummary.vue'),
}, },
{
path: 'basic-data',
name: 'WorkerBasicData',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('src/pages/Worker/Card/WorkerBasicData.vue'),
},
{
path: 'notes',
name: 'NotesCard',
redirect: { name: 'WorkerNotes' },
children: [
{
path: '',
name: 'WorkerNotes',
meta: {
title: 'notes',
icon: 'vn:notes',
},
component: () =>
import('src/pages/Worker/Card/WorkerNotes.vue'),
},
{
path: 'create',
name: 'WorkerNoteCreate',
meta: {
title: 'note-create',
},
component: () =>
import(
'src/pages/Worker/components/WorkerNoteCreate.vue'
),
},
],
},
{
name: 'WorkerPda',
path: 'pda',
meta: {
title: 'pda',
icon: 'phone_android',
},
component: () => import('src/pages/Worker/Card/WorkerPda.vue'),
},
{ {
name: 'WorkerNotificationsManager', name: 'WorkerNotificationsManager',
path: 'notifications', path: 'notifications',
@ -77,13 +130,13 @@ export default {
import('src/pages/Worker/Card/WorkerNotificationsManager.vue'), import('src/pages/Worker/Card/WorkerNotificationsManager.vue'),
}, },
{ {
name: 'WorkerPda', path: 'pbx',
path: 'pda', name: 'WorkerPBX',
meta: { meta: {
title: 'pda', title: 'pbx',
icon: 'phone_android', icon: 'vn:pbx',
}, },
component: () => import('src/pages/Worker/Card/WorkerPda.vue'), component: () => import('src/pages/Worker/Card/WorkerPBX.vue'),
}, },
{ {
name: 'WorkerLog', name: 'WorkerLog',