|
|
|
@ -1,15 +1,12 @@
|
|
|
|
|
<template>
|
|
|
|
|
<ProjectWrapper
|
|
|
|
|
ref="projectWrapper"
|
|
|
|
|
class="project-list"
|
|
|
|
|
:project-id="projectId"
|
|
|
|
|
:view-id
|
|
|
|
|
>
|
|
|
|
|
<ProjectWrapper ref="projectWrapper" class="project-list" :project-id="projectId" :view-id>
|
|
|
|
|
<template #header>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template #default>
|
|
|
|
|
<FullCalendar :options="calendarOptions" ref="calendar"/>
|
|
|
|
|
<div class="card">
|
|
|
|
|
<FullCalendar :options="calendarOptions" ref="calendar" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
</ProjectWrapper>
|
|
|
|
@ -19,9 +16,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import {ref, computed, nextTick, onMounted, watch, type Ref} from 'vue'
|
|
|
|
|
import { ref, computed, nextTick, onMounted, watch, type Ref } from 'vue'
|
|
|
|
|
import draggable from 'zhyswan-vuedraggable'
|
|
|
|
|
import {isSavedFilter} from '@/services/savedFilter'
|
|
|
|
|
import { isSavedFilter } from '@/services/savedFilter'
|
|
|
|
|
import ProjectWrapper from '@/components/project/ProjectWrapper.vue'
|
|
|
|
|
import FullCalendar from '@fullcalendar/vue3'
|
|
|
|
|
import timeGridPlugin from '@fullcalendar/timegrid'
|
|
|
|
@ -66,150 +63,177 @@ onMounted(() => {
|
|
|
|
|
if(calendar.value)
|
|
|
|
|
calendar.value.calendar.addEvent({
|
|
|
|
|
id: createEventId(),
|
|
|
|
|
title: 'All-day event',
|
|
|
|
|
start: todayStr
|
|
|
|
|
});
|
|
|
|
|
title: 'All-day event',
|
|
|
|
|
start: todayStr
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
let initialEvents = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function is_midnight(time?: Date) {
|
|
|
|
|
return (time && time.getHours() == 0 && time.getMinutes() == 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
allTasks,
|
|
|
|
|
() => {
|
|
|
|
|
console.log(allTasks.value);
|
|
|
|
|
for(let task of allTasks.value) {
|
|
|
|
|
if(task.startDate)
|
|
|
|
|
calendar.value.calendar.addEvent({
|
|
|
|
|
id: task.id,
|
|
|
|
|
title: task.title,
|
|
|
|
|
start: task.startDate,
|
|
|
|
|
end: task.endDate,
|
|
|
|
|
extendedProps: {
|
|
|
|
|
done: task.done
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
for (let task of allTasks.value) {
|
|
|
|
|
let allDay = (task.startDate && is_midnight(task.startDate) && task.endDate && (is_midnight(task.endDate) || is_midnight(task.endDate)));
|
|
|
|
|
|
|
|
|
|
if (task.startDate)
|
|
|
|
|
calendar.value.calendar.addEvent({
|
|
|
|
|
id: task.id,
|
|
|
|
|
title: task.title,
|
|
|
|
|
start: task.startDate,
|
|
|
|
|
end: task.endDate,
|
|
|
|
|
allDay: allDay,
|
|
|
|
|
color: task.hexColor,
|
|
|
|
|
extendedProps: {
|
|
|
|
|
exists: true,
|
|
|
|
|
task: task
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
const INITIAL_EVENTS = [
|
|
|
|
|
{
|
|
|
|
|
id: createEventId(),
|
|
|
|
|
title: 'All-day event',
|
|
|
|
|
start: todayStr
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: createEventId(),
|
|
|
|
|
title: 'Timed event',
|
|
|
|
|
start: todayStr + 'T12:00:00'
|
|
|
|
|
}
|
|
|
|
|
]*/
|
|
|
|
|
|
|
|
|
|
function createEventId() {
|
|
|
|
|
return String(eventGuid++)
|
|
|
|
|
function createEventId() {
|
|
|
|
|
return String(eventGuid++)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
const {
|
|
|
|
|
projectId,
|
|
|
|
|
viewId,
|
|
|
|
|
} = defineProps<{
|
|
|
|
|
projectId: IProject['id'],
|
|
|
|
|
viewId: IProjectView['id'],
|
|
|
|
|
}>()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function handleWeekendsToggle() {
|
|
|
|
|
calendarOptions.value.weekends = calendarOptions.value.weekends // update a property
|
|
|
|
|
};
|
|
|
|
|
calendarOptions.value.weekends = calendarOptions.value.weekends // update a property
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function handleDateSelect(selectInfo: { view: { calendar: any }; startStr: any; endStr: any; allDay: any }) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//let title = prompt('Please enter a new title for your event')
|
|
|
|
|
let title = "test"
|
|
|
|
|
let calendarApi = selectInfo.view.calendar
|
|
|
|
|
|
|
|
|
|
calendarApi.unselect() // clear date selection
|
|
|
|
|
//let title = prompt('Please enter a new title for your event')
|
|
|
|
|
let title = "test"
|
|
|
|
|
let calendarApi = selectInfo.view.calendar
|
|
|
|
|
|
|
|
|
|
if (title) {
|
|
|
|
|
calendarApi.addEvent({
|
|
|
|
|
id: createEventId(),
|
|
|
|
|
title,
|
|
|
|
|
start: selectInfo.startStr,
|
|
|
|
|
end: selectInfo.endStr,
|
|
|
|
|
allDay: selectInfo.allDay
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
calendarApi.unselect() // clear date selection
|
|
|
|
|
|
|
|
|
|
function handleEventClick(clickInfo: { event: any }) {
|
|
|
|
|
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
|
|
|
|
|
clickInfo.event.extendedProps.done != clickInfo.event.extendedProps.done
|
|
|
|
|
console.log("here")
|
|
|
|
|
clickInfo.view.calendar.render()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if (title) {
|
|
|
|
|
calendarApi.addEvent({
|
|
|
|
|
id: createEventId(),
|
|
|
|
|
title,
|
|
|
|
|
start: selectInfo.startStr,
|
|
|
|
|
end: selectInfo.endStr,
|
|
|
|
|
allDay: selectInfo.allDay
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function handleEventClick(clickInfo: { event: any }) {
|
|
|
|
|
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
|
|
|
|
|
clickInfo.event.extendedProps.task.done != clickInfo.event.extendedProps.task.done
|
|
|
|
|
console.log("here")
|
|
|
|
|
clickInfo.view.calendar.render()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function parseTime(time: Date | null) {
|
|
|
|
|
if(time)
|
|
|
|
|
return time.getHours() + ":" + String(time.getMinutes()).padStart(2,0)
|
|
|
|
|
if (time)
|
|
|
|
|
return time.getHours() + ":" + String(time.getMinutes()).padStart(2, 0)
|
|
|
|
|
else
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function eventRender (info: any) {
|
|
|
|
|
console.log(info);
|
|
|
|
|
function eventRender(info: any) {
|
|
|
|
|
const event = info.event;
|
|
|
|
|
console.log(event.extendedProps);
|
|
|
|
|
let timeEl = document.createElement("p");
|
|
|
|
|
let titleEl = document.createElement("p");
|
|
|
|
|
timeEl.innerHTML = parseTime(event.start)
|
|
|
|
|
titleEl.innerHTML = event.title
|
|
|
|
|
if(event.end)
|
|
|
|
|
timeEl.innerHTML += " - " + parseTime(event.end);
|
|
|
|
|
if (event.end)
|
|
|
|
|
timeEl.innerHTML += " - " + parseTime(event.end);
|
|
|
|
|
|
|
|
|
|
if(event.extendedProps.done) {
|
|
|
|
|
if (event.extendedProps.task.done) {
|
|
|
|
|
let strikethroughEl = document.createElement("s");
|
|
|
|
|
strikethroughEl.innerHTML = titleEl.innerHTML;
|
|
|
|
|
titleEl = strikethroughEl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { domNodes: [titleEl, timeEl] }
|
|
|
|
|
// {description: "Lecture", department: "BioChemistry"}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
import { useAuthStore } from '@/stores/auth'
|
|
|
|
|
import { useTaskStore } from '@/stores/tasks'
|
|
|
|
|
import TaskService from '@/services/task'
|
|
|
|
|
import TaskModel from '@/models/task'
|
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
|
const taskStore = useTaskStore()
|
|
|
|
|
const taskService = new TaskService()
|
|
|
|
|
let firstDayOfWeek = Math.min(authStore.settings.weekStart ?? 0, 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function eventAddHandler(addEvent:any) {
|
|
|
|
|
if(addEvent.event.extendedProps.exists) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const task = new TaskModel({
|
|
|
|
|
title: addEvent.event.title,
|
|
|
|
|
projectId: projectId,
|
|
|
|
|
startDate: addEvent.event.start.toString(),
|
|
|
|
|
endDate: addEvent.event.end.toString(),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return {domNodes: [titleEl, timeEl]}
|
|
|
|
|
// {description: "Lecture", department: "BioChemistry"}
|
|
|
|
|
}
|
|
|
|
|
const createdTask = await taskService.create(task)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function eventChangeHandler(changeEvent:any) {
|
|
|
|
|
let task: ITask = changeEvent.event.extendedProps.task;
|
|
|
|
|
task.startDate = changeEvent.event.start;
|
|
|
|
|
task.endDate = changeEvent.event.end;
|
|
|
|
|
|
|
|
|
|
const updatedTask = await taskService.update(task)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const calendarOptions = ref({
|
|
|
|
|
plugins: [
|
|
|
|
|
timeGridPlugin,
|
|
|
|
|
interactionPlugin // needed for dateClick
|
|
|
|
|
],
|
|
|
|
|
headerToolbar: {
|
|
|
|
|
left: 'prev,next today',
|
|
|
|
|
center: 'title',
|
|
|
|
|
right: 'timeGridWeek,timeGridDay'
|
|
|
|
|
},
|
|
|
|
|
initialView: 'timeGridWeek',
|
|
|
|
|
initialEvents: initialEvents, // alternatively, use the `events` setting to fetch from a feed
|
|
|
|
|
editable: true,
|
|
|
|
|
selectable: true,
|
|
|
|
|
selectMirror: true,
|
|
|
|
|
dayMaxEvents: true,
|
|
|
|
|
weekends: true,
|
|
|
|
|
select: handleDateSelect,
|
|
|
|
|
eventClick: handleEventClick,
|
|
|
|
|
eventContent: eventRender
|
|
|
|
|
/* you can update a remote database when these fire:
|
|
|
|
|
eventAdd:
|
|
|
|
|
eventChange:
|
|
|
|
|
eventRemove:
|
|
|
|
|
*/
|
|
|
|
|
});
|
|
|
|
|
plugins: [
|
|
|
|
|
timeGridPlugin,
|
|
|
|
|
interactionPlugin // needed for dateClick
|
|
|
|
|
],
|
|
|
|
|
headerToolbar: {
|
|
|
|
|
left: 'prev,next today',
|
|
|
|
|
center: 'title',
|
|
|
|
|
right: 'timeGridWeek,timeGridDay'
|
|
|
|
|
},
|
|
|
|
|
initialView: 'timeGridWeek',
|
|
|
|
|
initialEvents: initialEvents, // alternatively, use the `events` setting to fetch from a feed
|
|
|
|
|
editable: true,
|
|
|
|
|
selectable: true,
|
|
|
|
|
selectMirror: true,
|
|
|
|
|
dayMaxEvents: true,
|
|
|
|
|
weekends: true,
|
|
|
|
|
firstDay: firstDayOfWeek,
|
|
|
|
|
select: handleDateSelect,
|
|
|
|
|
eventClick: handleEventClick,
|
|
|
|
|
eventContent: eventRender,
|
|
|
|
|
eventAdd: eventAddHandler,
|
|
|
|
|
eventChange: eventChangeHandler
|
|
|
|
|
/* you can update a remote database when these fire:
|
|
|
|
|
eventAdd:
|
|
|
|
|
eventRemove:
|
|
|
|
|
*/
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.fc {
|
|
|
|
|
padding: .5rem;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
</style>
|