267 lines
7.9 KiB
Vue
267 lines
7.9 KiB
Vue
<script setup>
|
|
import { nextTick, ref, watch, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { useAcl } from 'src/composables/useAcl';
|
|
|
|
import WorkerCalendarFilter from 'pages/Worker/Card/WorkerCalendarFilter.vue';
|
|
import FetchData from 'components/FetchData.vue';
|
|
import WorkerCalendarItem from 'pages/Worker/Card/WorkerCalendarItem.vue';
|
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
|
|
import axios from 'axios';
|
|
import VnNotes from 'src/components/ui/VnNotes.vue';
|
|
import { useStateStore } from 'src/stores/useStateStore';
|
|
const stateStore = useStateStore();
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const { t } = useI18n();
|
|
const acl = useAcl();
|
|
const canSeeNotes = computed(() =>
|
|
acl.hasAny([{ model: 'Worker', props: '__get__business', accessType: 'READ' }]),
|
|
);
|
|
const workerIsFreelance = ref();
|
|
const WorkerFreelanceRef = ref();
|
|
const workerCalendarFilterRef = ref(null);
|
|
const workerCalendarRef = ref(null);
|
|
const absenceType = ref(null);
|
|
const hasWorkCenter = ref(false);
|
|
const isSubordinate = ref(false);
|
|
const businessFk = ref(null);
|
|
const year = ref(Date.vnNew().getFullYear());
|
|
const contractHolidays = ref(null);
|
|
const yearHolidays = ref(null);
|
|
const eventsMap = ref({});
|
|
const festiveEventsMap = ref({});
|
|
const saveUrl = ref();
|
|
const body = {
|
|
workerFk: route.params.id,
|
|
};
|
|
|
|
const onFetchActiveContract = (data) => {
|
|
if (!data) return;
|
|
businessFk.value = data?.businessFk;
|
|
hasWorkCenter.value = Boolean(data?.workCenterFk);
|
|
};
|
|
|
|
const addEvent = (day, newEvent, isFestive = false) => {
|
|
const timestamp = new Date(day).getTime();
|
|
let event = eventsMap.value[timestamp];
|
|
|
|
if (!event) {
|
|
eventsMap.value[timestamp] = newEvent;
|
|
if (isFestive)
|
|
festiveEventsMap.value[timestamp] = JSON.parse(JSON.stringify(newEvent));
|
|
} else {
|
|
const oldName = event.name;
|
|
const oldEventWasFestive = event.isFestive;
|
|
Object.assign(event, newEvent);
|
|
event.isFestive = oldEventWasFestive;
|
|
event.name = `${oldName}, ${event.name}`;
|
|
}
|
|
};
|
|
|
|
const onFetchAbsences = (data) => {
|
|
if (!data) return;
|
|
|
|
eventsMap.value = {};
|
|
|
|
if (data.holidays) {
|
|
data.holidays.forEach((holiday) => {
|
|
const holidayDetail = holiday?.detail?.name;
|
|
const holidayType = holiday?.type?.name;
|
|
const holidayName = holidayDetail || holidayType;
|
|
|
|
addEvent(
|
|
holiday.dated,
|
|
{
|
|
name: holidayName,
|
|
isFestive: true,
|
|
},
|
|
true,
|
|
);
|
|
});
|
|
}
|
|
if (data.absences) {
|
|
data.absences.forEach((absence) => {
|
|
let type = absence.absenceType;
|
|
addEvent(absence.dated, {
|
|
name: type.name,
|
|
color: type.rgb,
|
|
type: type.code,
|
|
absenceId: absence.id,
|
|
isFestive: false,
|
|
isHoliday: false,
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
const getAbsences = async () => {
|
|
try {
|
|
const params = {
|
|
workerFk: route.params.id,
|
|
businessFk: businessFk.value,
|
|
year: year.value,
|
|
};
|
|
const { data } = await axios.get('Calendars/absences', { params });
|
|
if (data) onFetchAbsences(data);
|
|
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching absences:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const getHolidays = async (params) => {
|
|
try {
|
|
const { data } = await axios.get(`Workers/${route.params.id}/holidays`, {
|
|
params,
|
|
});
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching holidays:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const updateContractHolidays = async () => {
|
|
contractHolidays.value = await getHolidays({
|
|
businessFk: businessFk.value,
|
|
year: year.value,
|
|
});
|
|
};
|
|
|
|
const updateYearHolidays = async () => {
|
|
yearHolidays.value = await getHolidays({ year: year.value });
|
|
};
|
|
|
|
const refreshData = () => {
|
|
updateYearHolidays();
|
|
updateContractHolidays();
|
|
getAbsences();
|
|
WorkerFreelanceRef.value.fetch();
|
|
};
|
|
|
|
const onDeletedEvent = (timestamp) => {
|
|
delete eventsMap.value[timestamp];
|
|
// Si el evento que eliminamos se encontraba dentro de un dia festivo, volvemos a agregar el evento festivo
|
|
if (festiveEventsMap.value[timestamp])
|
|
eventsMap.value[timestamp] = festiveEventsMap.value[timestamp];
|
|
};
|
|
const activeContractRef = ref(null);
|
|
|
|
watch(
|
|
() => router.currentRoute.value.params.id,
|
|
async () => {
|
|
await nextTick();
|
|
await activeContractRef.value.fetch();
|
|
},
|
|
);
|
|
watch([year, businessFk], () => refreshData());
|
|
</script>
|
|
|
|
<template>
|
|
<FetchData
|
|
ref="activeContractRef"
|
|
:url="`Workers/${route.params.id}/activeContract`"
|
|
@on-fetch="onFetchActiveContract"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
:url="`Workers/${route.params.id}/isSubordinate`"
|
|
@on-fetch="(data) => (isSubordinate = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
:url="`Workers/${route.params.id}`"
|
|
@on-fetch="(data) => (workerIsFreelance = data.isFreelance)"
|
|
ref="WorkerFreelanceRef"
|
|
auto-load
|
|
/>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<WorkerCalendarFilter
|
|
ref="workerCalendarFilterRef"
|
|
v-model:business-fk="businessFk"
|
|
v-model:year="year"
|
|
v-model:absence-type="absenceType"
|
|
:contract-holidays="contractHolidays"
|
|
:year-holidays="yearHolidays"
|
|
/>
|
|
</template>
|
|
</RightMenu>
|
|
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown() && canSeeNotes">
|
|
<VnNotes
|
|
:just-input="true"
|
|
:url="`Workers/${route.params.id}/business`"
|
|
:filter="{ fields: ['id', 'notes', 'workerFk'] }"
|
|
:save-url="saveUrl"
|
|
@on-fetch="
|
|
(data) => {
|
|
saveUrl = `Businesses/${data.id}`;
|
|
}
|
|
"
|
|
:body="body"
|
|
/>
|
|
</Teleport>
|
|
<QPage class="column items-center">
|
|
<QCard v-if="workerIsFreelance">
|
|
<QCardSection class="text-center">
|
|
{{ t('Autonomous worker') }}
|
|
</QCardSection>
|
|
</QCard>
|
|
<QCard v-else class="full-width">
|
|
<QIcon
|
|
v-if="isSubordinate"
|
|
name="info"
|
|
size="sm"
|
|
class="absolute"
|
|
style="top: 14px; right: 14px"
|
|
>
|
|
<QTooltip max-width="250px">
|
|
{{ t('addAbsencesText') }}
|
|
</QTooltip>
|
|
</QIcon>
|
|
<div class="calendar-container">
|
|
<WorkerCalendarItem
|
|
ref="workerCalendarRef"
|
|
v-for="month in 12"
|
|
:key="month"
|
|
:year="year"
|
|
:month="month"
|
|
:absence-type="absenceType"
|
|
:business-fk="businessFk"
|
|
:events="eventsMap"
|
|
@refresh="refreshData"
|
|
@on-deleted-event="onDeletedEvent"
|
|
/>
|
|
</div>
|
|
</QCard>
|
|
</QPage>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.calendar-container {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 32px;
|
|
padding: 40px;
|
|
justify-content: center;
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
en:
|
|
addAbsencesText: To start adding absences, click an absence type from the right menu and then on the day you want to add an absence
|
|
|
|
es:
|
|
Search worker: Buscar trabajador
|
|
You can search by worker id or name: Puedes buscar por id o nombre del trabajador
|
|
addAbsencesText: Para empezar a añadir ausencias, haz clic en un tipo de ausencia desde el menu de la derecha y después en el día que quieres añadir la ausencia
|
|
</i18n>
|