feat: add shift management functionality
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user