Files
radicall/resources/js/Admin/components/shifts/ShiftCalendar.vue
T

104 lines
4.1 KiB
Vue

<script setup>
import { computed, ref } from 'vue';
import FullCalendar from '@fullcalendar/vue3';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import faLocale from '@fullcalendar/core/locales/fa';
import Button from 'primevue/button';
import { buildShiftEvent, formatJalaliDay, formatJalaliRange } from '../../../Shared/shiftCalendarEvents';
const props = defineProps({
shifts: {
type: Array,
required: true
}
})
const emit = defineEmits(['select-shift']);
const doctorPalette = ['#576989', '#800E13', '#50CD89', '#7239EA', '#FFC700', '#F1416C', '#009EF7', '#965457'];
const calendarRef = ref(null);
const viewTitle = ref('');
const doctors = computed(() => {
const unique = new Map();
props.shifts.forEach((shift) => {
if (shift.doctor) unique.set(shift.doctor.id, shift.doctor);
});
return [...unique.values()];
});
const doctorColor = (doctorId) => {
const index = doctors.value.findIndex((doctor) => doctor.id === doctorId);
return doctorPalette[index % doctorPalette.length];
};
const events = computed(() => props.shifts.map((shift) => {
const overrides = shift.doctor
? {
title: shift.doctor.fullname,
classNames: ['shift-event--assigned', ...(shift.is_active ? [] : ['shift-event--inactive'])],
backgroundColor: doctorColor(shift.doctor.id),
borderColor: doctorColor(shift.doctor.id),
}
: {
title: 'شیفت آزاد',
classNames: ['shift-event--open', ...(shift.is_active ? [] : ['shift-event--inactive'])],
};
return buildShiftEvent(shift, overrides);
}));
const calendarOptions = computed(() => ({
plugins: [timeGridPlugin, interactionPlugin],
initialView: 'timeGridWeek',
locale: faLocale,
direction: 'rtl',
firstDay: 6,
headerToolbar: false,
allDaySlot: false,
height: 'auto',
nowIndicator: true,
slotLabelFormat: { hour: '2-digit', minute: '2-digit', hour12: false },
eventTimeFormat: { hour: '2-digit', minute: '2-digit', hour12: false },
dayHeaderContent: (args) => ({
html: `${args.text}<span class="shift-calendar-day-date">${formatJalaliDay(args.date)}</span>`
}),
datesSet: (info) => {
viewTitle.value = formatJalaliRange(info.start, info.end);
},
events: events.value,
eventClick: (info) => {
emit('select-shift', info.event.extendedProps.shift);
},
}))
const goPrev = () => calendarRef.value?.getApi().prev();
const goNext = () => calendarRef.value?.getApi().next();
const goToday = () => calendarRef.value?.getApi().today();
</script>
<template>
<div class="shift-calendar p-4">
<div class="flex flex-wrap items-center justify-between gap-3 pb-4">
<div class="flex items-center gap-2">
<Button label="امروز" size="small" outlined severity="secondary" class="!text-xs" @click="goToday" />
<Button icon="fi fi-rr-angle-small-right" size="small" outlined severity="secondary" class="!w-8 !h-8" :pt="{icon : 'flex !text-xs'}" @click="goPrev" />
<Button icon="fi fi-rr-angle-small-left" size="small" outlined severity="secondary" class="!w-8 !h-8" :pt="{icon : 'flex !text-xs'}" @click="goNext" />
<span class="text-sm font-bold text-client-Fontcolor">{{ viewTitle }}</span>
</div>
<ul class="flex flex-wrap items-center gap-4">
<li v-for="doctor in doctors" :key="doctor.id" class="flex items-center gap-1.5">
<span class="w-3 h-3 rounded" :style="{ background: doctorColor(doctor.id) }"></span>
<span class="text-xs text-client-Fontcolor">{{ doctor.fullname }}</span>
</li>
<li class="flex items-center gap-1.5">
<span class="w-3 h-3 rounded border border-dashed border-[#7188AD] bg-[#F6F7F9]"></span>
<span class="text-xs text-client-Fontcolor">شیفت آزاد</span>
</li>
</ul>
</div>
<FullCalendar ref="calendarRef" :options="calendarOptions" />
</div>
</template>