forked from verdnatura/salix-front
Last changes
This commit is contained in:
parent
dae08c322d
commit
4b6038d1d2
|
@ -23,7 +23,8 @@ const businessFk = ref(null);
|
||||||
const year = ref(Date.vnNew().getFullYear());
|
const year = ref(Date.vnNew().getFullYear());
|
||||||
const contractHolidays = ref(null);
|
const contractHolidays = ref(null);
|
||||||
const yearHolidays = ref(null);
|
const yearHolidays = ref(null);
|
||||||
const events = ref({});
|
const eventsMap = ref({});
|
||||||
|
const festiveEventsMap = ref({});
|
||||||
|
|
||||||
const onFetchActiveContract = (data) => {
|
const onFetchActiveContract = (data) => {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
@ -31,21 +32,27 @@ const onFetchActiveContract = (data) => {
|
||||||
hasWorkCenter.value = Boolean(data?.workCenterFk);
|
hasWorkCenter.value = Boolean(data?.workCenterFk);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addEvent = (day, newEvent) => {
|
const addEvent = (day, newEvent, isFestive = false) => {
|
||||||
const timestamp = new Date(day).getTime();
|
const timestamp = new Date(day).getTime();
|
||||||
let event = events.value[timestamp];
|
let event = eventsMap.value[timestamp];
|
||||||
|
|
||||||
if (event) {
|
if (!event) {
|
||||||
|
eventsMap.value[timestamp] = newEvent;
|
||||||
|
if (isFestive)
|
||||||
|
festiveEventsMap.value[timestamp] = JSON.parse(JSON.stringify(newEvent));
|
||||||
|
} else {
|
||||||
const oldName = event.name;
|
const oldName = event.name;
|
||||||
|
const oldEventWasFestive = event.isFestive;
|
||||||
Object.assign(event, newEvent);
|
Object.assign(event, newEvent);
|
||||||
|
event.isFestive = oldEventWasFestive;
|
||||||
event.name = `${oldName}, ${event.name}`;
|
event.name = `${oldName}, ${event.name}`;
|
||||||
} else events.value[timestamp] = newEvent;
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFetchAbsences = (data) => {
|
const onFetchAbsences = (data) => {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
events.value = {};
|
eventsMap.value = {};
|
||||||
|
|
||||||
if (data.holidays) {
|
if (data.holidays) {
|
||||||
data.holidays.forEach((holiday) => {
|
data.holidays.forEach((holiday) => {
|
||||||
|
@ -53,10 +60,14 @@ const onFetchAbsences = (data) => {
|
||||||
const holidayType = holiday.type && holiday.type.name;
|
const holidayType = holiday.type && holiday.type.name;
|
||||||
const holidayName = holidayDetail || holidayType;
|
const holidayName = holidayDetail || holidayType;
|
||||||
|
|
||||||
addEvent(holiday.dated, {
|
addEvent(
|
||||||
|
holiday.dated,
|
||||||
|
{
|
||||||
name: holidayName,
|
name: holidayName,
|
||||||
className: 'festive',
|
isFestive: true,
|
||||||
});
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (data.absences) {
|
if (data.absences) {
|
||||||
|
@ -67,10 +78,10 @@ const onFetchAbsences = (data) => {
|
||||||
color: type.rgb,
|
color: type.rgb,
|
||||||
type: type.code,
|
type: type.code,
|
||||||
absenceId: absence.id,
|
absenceId: absence.id,
|
||||||
|
isFestive: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log('events:: ', events.value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAbsences = async () => {
|
const getAbsences = async () => {
|
||||||
|
@ -120,7 +131,10 @@ const refreshData = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeletedEvent = (timestamp) => {
|
const onDeletedEvent = (timestamp) => {
|
||||||
delete events.value[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];
|
||||||
};
|
};
|
||||||
|
|
||||||
watch([year, businessFk], () => refreshData());
|
watch([year, businessFk], () => refreshData());
|
||||||
|
@ -161,6 +175,8 @@ watch([year, businessFk], () => refreshData());
|
||||||
v-model:business-fk="businessFk"
|
v-model:business-fk="businessFk"
|
||||||
v-model:year="year"
|
v-model:year="year"
|
||||||
v-model:absence-type="absenceType"
|
v-model:absence-type="absenceType"
|
||||||
|
:contract-holidays="contractHolidays"
|
||||||
|
:year-holidays="yearHolidays"
|
||||||
/>
|
/>
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
|
@ -195,7 +211,7 @@ watch([year, businessFk], () => refreshData());
|
||||||
:month="month"
|
:month="month"
|
||||||
:absence-type="absenceType"
|
:absence-type="absenceType"
|
||||||
:business-fk="businessFk"
|
:business-fk="businessFk"
|
||||||
:events="events"
|
:events="eventsMap"
|
||||||
@refresh="refreshData"
|
@refresh="refreshData"
|
||||||
@on-deleted-event="onDeletedEvent"
|
@on-deleted-event="onDeletedEvent"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -20,7 +20,15 @@ const props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
absenceType: {
|
absenceType: {
|
||||||
type: Number,
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
contractHolidays: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
yearHolidays: {
|
||||||
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -29,10 +37,7 @@ const emit = defineEmits(['update:businessFk', 'update:year', 'update:absenceTyp
|
||||||
|
|
||||||
const selectedBusinessFk = computed({
|
const selectedBusinessFk = computed({
|
||||||
get: () => props.businessFk,
|
get: () => props.businessFk,
|
||||||
set: (value) => {
|
set: (value) => emit('update:businessFk', value),
|
||||||
console.log('businessFk', value);
|
|
||||||
emit('update:businessFk', value);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedYear = computed({
|
const selectedYear = computed({
|
||||||
|
@ -76,42 +81,61 @@ const yearList = ref(generateYears());
|
||||||
@on-fetch="(data) => (contractList = data)"
|
@on-fetch="(data) => (contractList = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<QItem v-if="contractHolidays" class="q-py-md">
|
|
||||||
<QItemSection class="text-center">
|
<div
|
||||||
<p class="holiday-title q-mb-sm">
|
v-if="contractHolidays"
|
||||||
|
class="q-pa-md q-mb-md q-ma-md color-vn-text"
|
||||||
|
style="border: 2px solid black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
{{ t('Contract') }} #{{ selectedBusinessFk }}
|
{{ t('Contract') }} #{{ selectedBusinessFk }}
|
||||||
</p>
|
</span>
|
||||||
<div>
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
{{ t('Used') }} {{ contractHolidays.holidaysEnjoyed || 0 }} {{ t('of') }}
|
{{ t('Used') }} {{ contractHolidays.holidaysEnjoyed || 0 }} {{ t('of') }}
|
||||||
{{ contractHolidays.totalHolidays || 0 }}
|
{{ contractHolidays.totalHolidays || 0 }}
|
||||||
{{ t('days') }}
|
{{ t('days') }}
|
||||||
</div>
|
</span>
|
||||||
<div>
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
{{ t('Spent') }} {{ contractHolidays.hoursEnjoyed || 0 }} {{ t('of') }}
|
{{ t('Spent') }} {{ contractHolidays.hoursEnjoyed || 0 }} {{ t('of') }}
|
||||||
{{ contractHolidays.totalHours || 0 }} {{ t('hours') }}
|
{{ contractHolidays.totalHours || 0 }} {{ t('hours') }}
|
||||||
</div>
|
</span>
|
||||||
<div>
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
{{ t('Paid holidays') }}
|
{{ t('Paid holidays') }}
|
||||||
{{ contractHolidays.payedHolidays || 0 }}
|
{{ contractHolidays.payedHolidays || 0 }}
|
||||||
{{ t('days') }}
|
{{ t('days') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
</div>
|
</div>
|
||||||
</QItemSection>
|
<div
|
||||||
</QItem>
|
v-if="contractHolidays"
|
||||||
<QSeparator />
|
class="q-pa-md q-mb-md q-ma-md color-vn-text"
|
||||||
<QItem v-if="yearHolidays" class="q-py-md">
|
style="border: 2px solid black"
|
||||||
<QItemSection class="text-center">
|
>
|
||||||
<p class="holiday-title q-mb-sm">{{ t('Year') }} {{ selectedYear }}</p>
|
<QCardSection horizontal>
|
||||||
<div>
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('Year') }} {{ selectedYear }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
{{ t('Used') }} {{ yearHolidays.holidaysEnjoyed || 0 }} {{ t('of') }}
|
{{ t('Used') }} {{ yearHolidays.holidaysEnjoyed || 0 }} {{ t('of') }}
|
||||||
{{ yearHolidays.totalHolidays || 0 }} {{ t('days') }}
|
{{ yearHolidays.totalHolidays || 0 }} {{ t('days') }}
|
||||||
</div>
|
</span>
|
||||||
<div>
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
{{ t('Spent') }} {{ yearHolidays.hoursEnjoyed || 0 }} {{ t('of') }}
|
{{ t('Spent') }} {{ yearHolidays.hoursEnjoyed || 0 }} {{ t('of') }}
|
||||||
{{ yearHolidays.totalHours || 0 }} {{ t('hours') }}
|
{{ yearHolidays.totalHours || 0 }} {{ t('hours') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
</div>
|
</div>
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QSeparator />
|
|
||||||
<QList dense class="list q-gutter-y-sm q-my-lg">
|
<QList dense class="list q-gutter-y-sm q-my-lg">
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
|
@ -172,17 +196,18 @@ const yearList = ref(generateYears());
|
||||||
</QItem>
|
</QItem>
|
||||||
</QList>
|
</QList>
|
||||||
<QSeparator />
|
<QSeparator />
|
||||||
<QList dense class="list q-my-lg">
|
<QList dense class="list q-my-lg no-pointer-events">
|
||||||
<QItem>
|
<QItem>
|
||||||
<WorkerDateLabel avatar-class="worker-calendar-festive">
|
<WorkerDateLabel avatar-class="worker-calendar-festive">
|
||||||
Festive
|
{{ t('Festive') }}
|
||||||
</WorkerDateLabel>
|
</WorkerDateLabel>
|
||||||
<WorkerDateLabel avatar-class="worker-calendar-today">
|
<WorkerDateLabel avatar-class="worker-calendar-today">
|
||||||
Current day
|
{{ t('Current day') }}
|
||||||
</WorkerDateLabel>
|
</WorkerDateLabel>
|
||||||
</QItem>
|
</QItem>
|
||||||
</QList>
|
</QList>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.worker-calendar-festive {
|
.worker-calendar-festive {
|
||||||
border: 2px solid $negative;
|
border: 2px solid $negative;
|
||||||
|
@ -192,12 +217,6 @@ const yearList = ref(generateYears());
|
||||||
border: 2px solid $info;
|
border: 2px solid $info;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="scss" scoped>
|
|
||||||
.holiday-title {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, ref, watch } from 'vue';
|
import { onBeforeMount, ref, watch, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
@ -48,6 +48,12 @@ const weekdayStore = useWeekdayStore();
|
||||||
const selectedDate = ref();
|
const selectedDate = ref();
|
||||||
const calendarEventDates = [];
|
const calendarEventDates = [];
|
||||||
const today = ref(date.formatDate(Date.vnNew(), 'YYYY-MM-DD'));
|
const today = ref(date.formatDate(Date.vnNew(), 'YYYY-MM-DD'));
|
||||||
|
const todayTimestamp = computed(() => {
|
||||||
|
const date = Date.vnNew();
|
||||||
|
date.setHours(0, 0, 0, 0);
|
||||||
|
return date.getTime();
|
||||||
|
});
|
||||||
|
const _year = computed(() => props.year);
|
||||||
|
|
||||||
const updateSelectedDate = (year) => {
|
const updateSelectedDate = (year) => {
|
||||||
const _date = new Date(year, props.month - 1, 1);
|
const _date = new Date(year, props.month - 1, 1);
|
||||||
|
@ -67,10 +73,9 @@ const createEvent = async (date) => {
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('CREATE data:: ', data);
|
|
||||||
if (data) emit('refresh');
|
if (data) emit('refresh');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error creating event:: ', error);
|
console.error('error creating event:: ', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,12 +93,11 @@ const editEvent = async (event) => {
|
||||||
|
|
||||||
if (data) emit('refresh');
|
if (data) emit('refresh');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error editing event:: ', error);
|
console.error('error editing event:: ', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteEvent = async (event, date) => {
|
const deleteEvent = async (event, date) => {
|
||||||
console.log('deleteEvent:: ', event);
|
|
||||||
const params = { absenceId: event.absenceId };
|
const params = { absenceId: event.absenceId };
|
||||||
const { data } = await axios.delete(`Workers/${route.params.id}/deleteAbsence`, {
|
const { data } = await axios.delete(`Workers/${route.params.id}/deleteAbsence`, {
|
||||||
params,
|
params,
|
||||||
|
@ -117,8 +121,14 @@ const handleDateSelected = (date) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEventSelected = (event, { year, month, day }) => {
|
const handleEventSelected = (event, { year, month, day }) => {
|
||||||
|
if (!props.absenceType) {
|
||||||
|
notify(t('Choose an absence type from the right menu'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const date = new Date(year, month - 1, day);
|
const date = new Date(year, month - 1, day);
|
||||||
if (event.type == props.absenceType.code) deleteEvent(event, date);
|
if (!event.absenceId) createEvent(date);
|
||||||
|
else if (event.type == props.absenceType.code) deleteEvent(event, date);
|
||||||
else editEvent(event);
|
else editEvent(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,20 +141,34 @@ const getEventAttrs = (timestamp) => {
|
||||||
const event = getEventByTimestamp(timestamp);
|
const event = getEventByTimestamp(timestamp);
|
||||||
if (!event) return {};
|
if (!event) return {};
|
||||||
|
|
||||||
const { name, color } = event;
|
const { name, color, isFestive } = event;
|
||||||
|
|
||||||
// Atributos a asignar a cada slot que representa un evento en el calendario
|
// Atributos a asignar a cada slot que representa un evento en el calendario
|
||||||
return {
|
|
||||||
|
const attrs = {
|
||||||
title: name,
|
title: name,
|
||||||
style: `background-color: ${color};`,
|
style: color ? `background-color: ${color};` : '',
|
||||||
|
label: timestamp.day,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isFestive) {
|
||||||
|
attrs.class = '--festive';
|
||||||
|
attrs.label = event.absenceId ? timestamp.day : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isToday = (timestamp) => {
|
||||||
|
const { year, month, day } = timestamp;
|
||||||
|
return todayTimestamp.value === new Date(year, month - 1, day).getTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
updateSelectedDate(props.year);
|
updateSelectedDate(_year.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(props.year, (newValue) => {
|
watch(_year, (newValue) => {
|
||||||
updateSelectedDate(newValue);
|
updateSelectedDate(newValue);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -173,16 +197,20 @@ watch(props.year, (newValue) => {
|
||||||
>
|
>
|
||||||
<template #day="{ scope: { timestamp } }">
|
<template #day="{ scope: { timestamp } }">
|
||||||
<!-- Este slot representa cada día del calendario y muestra un botón representando el correspondiente evento -->
|
<!-- Este slot representa cada día del calendario y muestra un botón representando el correspondiente evento -->
|
||||||
<QButton
|
<QBtn
|
||||||
v-if="getEventByTimestamp(timestamp)"
|
v-if="getEventByTimestamp(timestamp)"
|
||||||
v-bind="{ ...getEventAttrs(timestamp) }"
|
v-bind="{ ...getEventAttrs(timestamp) }"
|
||||||
@click="
|
@click="
|
||||||
handleEventSelected(getEventByTimestamp(timestamp), timestamp)
|
handleEventSelected(getEventByTimestamp(timestamp), timestamp)
|
||||||
"
|
"
|
||||||
|
rounded
|
||||||
|
dense
|
||||||
|
flat
|
||||||
class="calendar-event"
|
class="calendar-event"
|
||||||
>
|
:class="{
|
||||||
{{ timestamp.day }}
|
'--today': isToday(timestamp),
|
||||||
</QButton>
|
}"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</QCalendarMonth>
|
</QCalendarMonth>
|
||||||
</template>
|
</template>
|
||||||
|
@ -190,6 +218,11 @@ watch(props.year, (newValue) => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
:root {
|
||||||
|
--calendar-border-current-dark: #84d0e2 2px solid;
|
||||||
|
--calendar-border-current: #84d0e2 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
.q-calendar__button {
|
.q-calendar__button {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--vn-accent-color);
|
background-color: var(--vn-accent-color);
|
||||||
|
@ -197,6 +230,10 @@ watch(props.year, (newValue) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.q-calendar__button--bordered {
|
||||||
|
color: $info !important;
|
||||||
|
}
|
||||||
|
|
||||||
.q-calendar-month__day--content {
|
.q-calendar-month__day--content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1;
|
top: 1;
|
||||||
|
@ -213,13 +250,20 @@ watch(props.year, (newValue) => {
|
||||||
.calendar-event {
|
.calendar-event {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
|
||||||
width: 2em;
|
width: 2em;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
line-height: 1.715em;
|
line-height: 1.715em;
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&.--today {
|
||||||
|
border: 2px solid $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--festive {
|
||||||
|
border: 2px solid $negative;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
|
@ -18,7 +18,7 @@ defineEmits(['update:selected']);
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QChip
|
<QChip
|
||||||
class="chip glossy"
|
class="chip"
|
||||||
:selected="selected"
|
:selected="selected"
|
||||||
:style="selected ? { backgroundColor: color } : null"
|
:style="selected ? { backgroundColor: color } : null"
|
||||||
@update:selected="$emit('update:selected', $event)"
|
@update:selected="$emit('update:selected', $event)"
|
||||||
|
@ -26,7 +26,6 @@ defineEmits(['update:selected']);
|
||||||
<QAvatar
|
<QAvatar
|
||||||
:color="color"
|
:color="color"
|
||||||
:class="avatarClass"
|
:class="avatarClass"
|
||||||
class="glossy"
|
|
||||||
:style="{ backgroundColor: color }"
|
:style="{ backgroundColor: color }"
|
||||||
/>
|
/>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
Loading…
Reference in New Issue