191 lines
4.4 KiB
Vue
191 lines
4.4 KiB
Vue
<script setup>
|
|
import { ref, computed, watch } from 'vue';
|
|
import { Calendar } from 'v-calendar';
|
|
import 'v-calendar/style.css';
|
|
|
|
// Props del componente
|
|
const props = defineProps({
|
|
// Días de conflicto a pintar en rojo
|
|
conflictDays: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
// Configuración adicional
|
|
locale: {
|
|
type: String,
|
|
default: 'es'
|
|
}
|
|
});
|
|
|
|
// Emits
|
|
const emit = defineEmits(['monthChanged']);
|
|
|
|
// Variables reactivas
|
|
const currentMonth = ref(new Date());
|
|
const fromPage = ref(null);
|
|
|
|
// Atributos para el calendario (eventos, vacaciones, etc.)
|
|
const attributes = computed(() => {
|
|
const attrs = [];
|
|
|
|
|
|
// Agregar días de conflicto (pintarlos en rojo)
|
|
if (props.conflictDays && props.conflictDays.length > 0) {
|
|
props.conflictDays.forEach((day) => {
|
|
const currentYear = currentMonth.value.getFullYear();
|
|
const currentMonthNumber = currentMonth.value.getMonth();
|
|
const conflictDate = new Date(currentYear, currentMonthNumber, day);
|
|
|
|
attrs.push({
|
|
key: `conflict-${day}`,
|
|
dates: conflictDate,
|
|
highlight: {
|
|
color: 'red',
|
|
fillMode: 'solid'
|
|
},
|
|
popover: {
|
|
label: `Día con conflictos de vacaciones`,
|
|
visibility: 'hover'
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
return attrs;
|
|
});
|
|
|
|
// Configuración del calendario
|
|
const calendarConfig = computed(() => ({
|
|
locale: props.locale,
|
|
firstDayOfWeek: 2, // Lunes
|
|
masks: {
|
|
weekdays: 'WWW',
|
|
navMonths: 'MMMM',
|
|
title: 'MMMM YYYY'
|
|
},
|
|
theme: {
|
|
isDark: false
|
|
}
|
|
}));
|
|
|
|
// Métodos
|
|
const onPageChanged = (page) => {
|
|
// Actualizar el mes actual cuando se cambia de página
|
|
currentMonth.value = new Date(page[0].year, page[0].month - 1, 1);
|
|
emit('monthChanged', page[0].month);
|
|
};
|
|
|
|
// Watch para re-renderizar cuando cambien los días de conflicto o el mes actual
|
|
watch([() => props.conflictDays, currentMonth], () => {
|
|
// Los attributes se recalcularán automáticamente al cambiar estas dependencias
|
|
}, { deep: true });
|
|
|
|
// Exponer métodos para uso externo
|
|
defineExpose({
|
|
currentMonth
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="calendar-container bg-white rounded-lg shadow-md p-4">
|
|
<!-- Header del calendario -->
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-900">Calendario</h3>
|
|
</div>
|
|
|
|
<!-- Calendario principal -->
|
|
<div class="calendar-wrapper">
|
|
<Calendar
|
|
v-model="currentMonth"
|
|
:attributes="attributes"
|
|
:locale="calendarConfig.locale"
|
|
:first-day-of-week="calendarConfig.firstDayOfWeek"
|
|
:masks="calendarConfig.masks"
|
|
class="custom-calendar"
|
|
v-model:from-page="fromPage"
|
|
@update:from-page="onPageChanged"
|
|
@did-move="onPageChanged"
|
|
expanded
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Estilos personalizados para el calendario */
|
|
.calendar-container {
|
|
min-width: 300px;
|
|
}
|
|
|
|
.custom-calendar {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Personalización de v-calendar */
|
|
:deep(.vc-container) {
|
|
--vc-border-radius: 0.5rem;
|
|
--vc-weekday-color: #6B7280;
|
|
--vc-popover-content-bg: white;
|
|
--vc-popover-content-border: 1px solid #E5E7EB;
|
|
border: none;
|
|
font-family: inherit;
|
|
}
|
|
|
|
:deep(.vc-header) {
|
|
padding: 1rem 1rem 0.5rem;
|
|
}
|
|
|
|
:deep(.vc-title) {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: #1F2937;
|
|
}
|
|
|
|
:deep(.vc-weekday) {
|
|
color: #6B7280;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
padding: 0.5rem 0;
|
|
}
|
|
|
|
:deep(.vc-day) {
|
|
min-height: 2rem;
|
|
}
|
|
|
|
:deep(.vc-day-content) {
|
|
width: 2rem;
|
|
height: 2rem;
|
|
border-radius: 0.375rem;
|
|
border: none;
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
:deep(.vc-day-content:hover) {
|
|
background-color: #EFF6FF;
|
|
color: #2563EB;
|
|
}
|
|
|
|
:deep(.vc-day-content.vc-day-content-today) {
|
|
background-color: #DBEAFE;
|
|
color: #1D4ED8;
|
|
font-weight: 600;
|
|
}
|
|
|
|
:deep(.vc-highlights .vc-highlight) {
|
|
border-radius: 0.375rem;
|
|
}
|
|
|
|
:deep(.vc-dots) {
|
|
margin-bottom: 0.125rem;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 640px) {
|
|
.calendar-container {
|
|
min-width: auto;
|
|
margin: 0 -1rem;
|
|
border-radius: 0;
|
|
}
|
|
}
|
|
</style> |