679 lines
24 KiB
Vue
679 lines
24 KiB
Vue
<template>
|
|
<div class="card app-calendar-wrapper">
|
|
<div class="row g-0">
|
|
<div class="col-3 border-end text-center" id="app-calendar-sidebar">
|
|
<div class="card-body">
|
|
<img
|
|
v-if="user"
|
|
:src="`${profileImgUrl}profile/${user.profile}`"
|
|
alt="Profile Image"
|
|
class="w-px-50 h-px-50 rounded-circle profile-img"
|
|
@error="$event.target.src = '/img/icons/icon.png'"
|
|
/>
|
|
<p class="mt-2 fw-bold">
|
|
{{ user.name }}
|
|
</p>
|
|
|
|
<CommuterBtn :userId="user.id" :checkedInProject="checkedInProject || {}" ref="workTimeComponentRef" />
|
|
|
|
<MainEventList
|
|
:categoryList="categoryList"
|
|
:baseUrl="baseUrl"
|
|
:birthdayList="birthdayList"
|
|
:vacationList="vacationList"
|
|
:birthdayPartyList="birthdayPartyList"
|
|
:dinnerList="dinnerList"
|
|
:teaTimeList="teaTimeList"
|
|
:workShopList="workShopList"
|
|
@handle-click-vacation="handleClickVacation"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col app-calendar-content">
|
|
<div class="card shadow-none border-0">
|
|
<div class="card-body">
|
|
<full-calendar
|
|
ref="fullCalendarRef"
|
|
:events="calendarEvents"
|
|
:options="calendarOptions"
|
|
defaultView="dayGridMonth"
|
|
class="flatpickr-calendar-only"
|
|
>
|
|
</full-calendar>
|
|
<input ref="calendarDatepicker" type="text" class="d-none" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<EventModal
|
|
v-if="showModal"
|
|
:position="modalPosition"
|
|
:selected-date="selectedDate"
|
|
:base-url="baseUrl"
|
|
:date-events="currentDateEvents"
|
|
@select="handleEventSelect"
|
|
@delete="handleEventDelete"
|
|
@insert="handleEventInsert"
|
|
@close="handleCloseModal"
|
|
/>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { inject, onMounted, reactive, ref, watch, nextTick } from 'vue';
|
|
import { fetchHolidays } from '@c/calendar/holiday';
|
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
|
import { useProjectStore } from '@/stores/useProjectStore';
|
|
import { useToastStore } from '@s/toastStore';
|
|
import { useWeatherStore } from '@/stores/useWeatherStore';
|
|
import { useDatePicker } from '@/stores/useDatePicker';
|
|
import { storeToRefs } from 'pinia';
|
|
import router from '@/router';
|
|
import FullCalendar from '@fullcalendar/vue3';
|
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
|
import interactionPlugin from '@fullcalendar/interaction';
|
|
import CommuterBtn from '@c/commuters/CommuterBtn.vue';
|
|
import MainEventList from '@c/main/MainEventList.vue';
|
|
import EventModal from '@c/main/EventModal.vue';
|
|
import $api from '@api';
|
|
import 'flatpickr/dist/flatpickr.min.css';
|
|
import '@/assets/css/app-calendar.css';
|
|
|
|
const baseUrl = import.meta.env.VITE_DOMAIN;
|
|
const profileImgUrl = import.meta.env.VITE_SERVER_IMG_URL;
|
|
const user = ref({});
|
|
const userStore = useUserInfoStore();
|
|
const projectStore = useProjectStore();
|
|
const weatherStore = useWeatherStore();
|
|
const datePickerStore = useDatePicker();
|
|
const { dailyWeatherList } = storeToRefs(weatherStore);
|
|
|
|
const dayjs = inject('dayjs');
|
|
const fullCalendarRef = ref(null);
|
|
const workTimeComponentRef = ref(null);
|
|
const calendarEvents = ref([]);
|
|
const calendarDatepicker = ref(null);
|
|
//const dailyWeatherList = ref([]);
|
|
|
|
const selectedProject = ref(null);
|
|
const checkedInProject = ref(null);
|
|
|
|
// 이벤트 모달 관련
|
|
const showModal = ref(false);
|
|
const modalPosition = ref({ x: 0, y: 0 });
|
|
const selectedDate = ref('');
|
|
|
|
// 공통 함수
|
|
const $common = inject('common');
|
|
const toastStore = useToastStore();
|
|
|
|
// 롱프레스 관련 변수 추가
|
|
const pressTimer = ref(null);
|
|
const longPressDelay = 500; // 0.5초
|
|
|
|
/************* category ***************/
|
|
|
|
// 이벤트 카테고리 데이터 로딩
|
|
const categoryList = ref([]);
|
|
const fetchCategoryList = async () => {
|
|
const { data } = await $api.get('main/category');
|
|
if (data) categoryList.value = [...data.data.filter(categoryInfo => categoryInfo.CMNCODODR != 0)];
|
|
};
|
|
|
|
/************* init ***************/
|
|
const monthBirthdayList = ref([]);
|
|
const monthVacationList = ref([]);
|
|
const monthBirthdayPartyList = ref([]);
|
|
const monthDinnerList = ref([]);
|
|
const monthTeaTimeList = ref([]);
|
|
const monthWorkShopList = ref([]);
|
|
|
|
const birthdayList = ref([]);
|
|
const vacationList = ref([]);
|
|
const birthdayPartyList = ref([]);
|
|
const dinnerList = ref([]);
|
|
const teaTimeList = ref([]);
|
|
const workShopList = ref([]);
|
|
|
|
const currentDateEvents = ref([]);
|
|
|
|
// 생일자, 휴가자, 이벤트 일정 조회
|
|
const fetchEventList = async param => {
|
|
const { data } = await $api.get(`main/eventList?${param}`);
|
|
const res = data?.data;
|
|
|
|
// 기존의 공휴일 이벤트는 유지
|
|
const holidayEvents = calendarEvents.value.filter(event => event.classNames?.includes('holiday-event'));
|
|
calendarEvents.value = [...holidayEvents, ...dailyWeatherList.value];
|
|
|
|
// 생일자
|
|
if (res?.memberBirthdayList?.length) {
|
|
monthBirthdayList.value = [...res.memberBirthdayList];
|
|
res.memberBirthdayList.forEach(member => {
|
|
addEvent($common.dateFormatter(member.MEMBERBTH, 'YMD'), 'birthday', `${member.MEMBERNAM}`);
|
|
});
|
|
}
|
|
|
|
// 휴가자
|
|
if (res?.memberVacationList?.length) {
|
|
monthVacationList.value = [...res.memberVacationList];
|
|
res.memberVacationList.forEach(member => {
|
|
addEvent($common.dateFormatter(member.LOCVACUDT, 'YMD'), 'vacation', `${member.MEMBERNAM}`);
|
|
});
|
|
}
|
|
|
|
// 초기화
|
|
monthBirthdayPartyList.value = [];
|
|
monthDinnerList.value = [];
|
|
monthTeaTimeList.value = [];
|
|
monthWorkShopList.value = [];
|
|
|
|
if (res?.eventList?.length) {
|
|
res.eventList.forEach(item => {
|
|
switch (item.CMNCODVAL) {
|
|
case 300203:
|
|
monthBirthdayPartyList.value = [...monthBirthdayPartyList.value, item];
|
|
addEvent($common.dateFormatter(item.LOCEVTTME, 'YMD'), 'birthdayParty', '생일파티');
|
|
break;
|
|
|
|
case 300204:
|
|
monthDinnerList.value = [...monthDinnerList.value, item];
|
|
addEvent($common.dateFormatter(item.LOCEVTTME, 'YMD'), 'dinner', '회식');
|
|
break;
|
|
|
|
case 300205:
|
|
monthTeaTimeList.value = [...monthTeaTimeList.value, item];
|
|
addEvent($common.dateFormatter(item.LOCEVTTME, 'YMD'), 'teaTime', '티타임');
|
|
break;
|
|
|
|
case 300206:
|
|
monthWorkShopList.value = [...monthWorkShopList.value, item];
|
|
addEvent($common.dateFormatter(item.LOCEVTTME, 'YMD'), 'workshop', '워크샵');
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// 달력에 이벤트 데이터 추가
|
|
const addEvent = (date, type, title) => {
|
|
// 생일의 경우 달력의 현재 년도로 변경하여 처리
|
|
if (type === 'birthday') {
|
|
const calendarApi = fullCalendarRef.value?.getApi();
|
|
|
|
if (calendarApi) {
|
|
const calendarDate = calendarApi.currentData.currentDate;
|
|
const { year } = $common.formatDateTime(new Date(calendarDate));
|
|
const birthDate = $common.dateFormatter(date, 'MD');
|
|
date = `${year}-${birthDate}`;
|
|
}
|
|
}
|
|
|
|
// 같은 날짜와 타입의 이벤트가 이미 있는지 확인
|
|
const existingEvent = calendarEvents.value.find(
|
|
event => $common.dateFormatter(event.start, 'MD') === $common.dateFormatter(date, 'MD') && event.type == type,
|
|
);
|
|
|
|
// 없는 경우에만 추가
|
|
if (!existingEvent) {
|
|
calendarEvents.value.push({
|
|
start: date,
|
|
type: type,
|
|
title: title,
|
|
classNames: [`${type}-event`],
|
|
});
|
|
}
|
|
};
|
|
|
|
// 해당일 기준 이벤트 리스트 필터링
|
|
const useFilterEventList = (month, day) => {
|
|
// 생일자
|
|
if (monthBirthdayList.value) {
|
|
birthdayList.value = $common.filterTargetByDate(monthBirthdayList.value, 'MEMBERBTH', month, day);
|
|
}
|
|
|
|
// 휴가자
|
|
if (monthVacationList.value) {
|
|
vacationList.value = $common.filterTargetByDate(monthVacationList.value, 'LOCVACUDT', month, day);
|
|
}
|
|
|
|
// 생일파티
|
|
if (monthBirthdayPartyList.value) {
|
|
birthdayPartyList.value = $common.filterTargetByDate(monthBirthdayPartyList.value, 'LOCEVTTME', month, day);
|
|
}
|
|
|
|
// 회식
|
|
if (monthDinnerList.value) {
|
|
dinnerList.value = $common.filterTargetByDate(monthDinnerList.value, 'LOCEVTTME', month, day);
|
|
}
|
|
|
|
// 티타임
|
|
if (monthTeaTimeList.value) {
|
|
teaTimeList.value = $common.filterTargetByDate(monthTeaTimeList.value, 'LOCEVTTME', month, day);
|
|
}
|
|
|
|
// 워크샵
|
|
if (monthWorkShopList.value) {
|
|
workShopList.value = $common.filterTargetByDate(monthWorkShopList.value, 'LOCEVTTME', month, day);
|
|
}
|
|
};
|
|
|
|
// 캘린더 데이터 가져오기
|
|
const fetchData = async () => {
|
|
// FullCalendar API 인스턴스 가져오기
|
|
const calendarApi = fullCalendarRef.value?.getApi();
|
|
if (!calendarApi) return;
|
|
|
|
const date = calendarApi.currentData.currentDate;
|
|
const { year, month } = $common.formatDateTime(new Date(date));
|
|
|
|
try {
|
|
// 현재 표시 중인 월의 공휴일 정보 가져오기
|
|
const holidayEvents = await fetchHolidays(year, month);
|
|
calendarEvents.value = [...holidayEvents]; // 공휴일 정보로 초기화
|
|
|
|
// 이벤트 데이터 가져오기
|
|
const param = new URLSearchParams();
|
|
param.append('year', year);
|
|
param.append('month', month);
|
|
param.append('day', '1'); // 해당 월의 첫날
|
|
|
|
await fetchEventList(param);
|
|
} catch (error) {
|
|
console.error('공휴일 정보 로딩 실패:', error);
|
|
}
|
|
};
|
|
|
|
// 캘린더 이동 함수 (이전, 다음, 오늘)
|
|
const moveCalendar = async (value = 0) => {
|
|
const calendarApi = fullCalendarRef.value?.getApi();
|
|
|
|
if (value === 1) {
|
|
calendarApi.prev(); // 이전 달로 이동
|
|
} else if (value === 2) {
|
|
calendarApi.next(); // 다음 달로 이동
|
|
} else if (value === 3) {
|
|
calendarApi.today(); // 오늘 날짜로 이동
|
|
}
|
|
|
|
await fetchData();
|
|
};
|
|
|
|
// 날짜 선택 가능 여부를 확인하는 공통 함수
|
|
const isSelectableDate = date => {
|
|
const checkDate = dayjs(date);
|
|
const isWeekend = checkDate.day() === 0 || checkDate.day() === 6; // 주말체크
|
|
// 공휴일 체크
|
|
const isHoliday = calendarEvents.value.some(
|
|
event =>
|
|
event.classNames?.includes('holiday-event') && dayjs(event.start).format('YYYY-MM-DD') === checkDate.format('YYYY-MM-DD'),
|
|
);
|
|
|
|
return !isWeekend && !isHoliday;
|
|
};
|
|
|
|
// 날짜 셀 클래스 추가 함수
|
|
const getCellClassNames = arg => {
|
|
const cellDate = dayjs(arg.date);
|
|
const classes = [];
|
|
|
|
// 선택 불가능한 날짜(과거, 주말, 공휴일)에 동일한 클래스 추가
|
|
if (!isSelectableDate(cellDate)) {
|
|
classes.push('fc-day-sat-sun');
|
|
} else {
|
|
// 선택 가능한 날짜 포인터 클래스 추가
|
|
classes.push('clickable');
|
|
}
|
|
|
|
return classes;
|
|
};
|
|
|
|
// 날짜 클릭 이벤트 핸들러
|
|
let todayEL = null;
|
|
const handleDateClick = info => {
|
|
if (isSelectableDate(info.date)) {
|
|
if ($common.isToday(info.date)) {
|
|
// 오늘 날짜 클릭 시 클래스 제거하고 요소 저장
|
|
todayEL = info.dayEl;
|
|
todayEL.classList.remove('fc-day-today');
|
|
} else if (todayEL) {
|
|
// 다른 날짜 클릭 시 저장된 오늘 요소에 클래스 다시 추가
|
|
todayEL.classList.add('fc-day-today');
|
|
todayEL = null;
|
|
}
|
|
}
|
|
const { month, day } = $common.formatDateTime(new Date(info.dateStr));
|
|
useFilterEventList(month, day);
|
|
};
|
|
|
|
// 오늘 날짜 노란색 배경 복구
|
|
const colorToday = e => {
|
|
if (todayEL != null && !todayEL.classList.contains('fc-day-today')) todayEL.classList.add('fc-day-today');
|
|
};
|
|
|
|
// 이벤트 모달 핸들러
|
|
const handleMouseDown = (date, jsEvent) => {
|
|
if (showModal.value) showModal.value = false;
|
|
|
|
// 해당 날짜의 이벤트 필터링
|
|
const dateEvents = calendarEvents.value.filter(
|
|
event => $common.dateFormatter(event.start, 'YMD') === $common.dateFormatter(date, 'YMD'),
|
|
);
|
|
|
|
pressTimer.value = setTimeout(() => {
|
|
modalPosition.value = {
|
|
x: jsEvent.clientX,
|
|
y: jsEvent.clientY,
|
|
};
|
|
|
|
selectedDate.value = date;
|
|
currentDateEvents.value = dateEvents;
|
|
showModal.value = true;
|
|
pressTimer.value = null;
|
|
}, longPressDelay);
|
|
};
|
|
|
|
// 이벤트 모달 외부 클릭 시 닫힘
|
|
const handleMouseUp = () => {
|
|
if (pressTimer.value) {
|
|
clearTimeout(pressTimer.value);
|
|
pressTimer.value = null;
|
|
}
|
|
};
|
|
|
|
// 이벤트 삭제 api
|
|
const toggleEvent = async (date, code, title) => {
|
|
const { data } = await $api.post('main/toggleEvent', {
|
|
date: date,
|
|
code: code,
|
|
title: title,
|
|
});
|
|
|
|
if (data?.code === 200) toastStore.onToast(data.message);
|
|
|
|
const { year, month, day } = $common.formatDateTime(new Date(date));
|
|
const param = new URLSearchParams();
|
|
param.append('year', year);
|
|
param.append('month', month);
|
|
param.append('day', day);
|
|
|
|
await fetchEventList(param);
|
|
useFilterEventList(month, day);
|
|
};
|
|
|
|
// 이벤트 추가 api
|
|
const insertEvent = async (date, code, title, place, time) => {
|
|
const dateTime = $common.dateFormatter(`${date} ${time}`);
|
|
const { data } = await $api.post('main/inserEvent', {
|
|
date: dateTime,
|
|
code: code,
|
|
title: title,
|
|
place: place,
|
|
});
|
|
|
|
if (data?.code === 200) toastStore.onToast(data.message);
|
|
|
|
const { year, month, day } = $common.formatDateTime(new Date(date));
|
|
const param = new URLSearchParams();
|
|
param.append('year', year);
|
|
param.append('month', month);
|
|
param.append('day', day);
|
|
|
|
await fetchEventList(param);
|
|
useFilterEventList(month, day);
|
|
};
|
|
|
|
// 이벤트 선택 핸들러
|
|
const handleEventSelect = data => {
|
|
toggleEvent(data.date, data.code, data.title);
|
|
showModal.value = false;
|
|
};
|
|
|
|
// 이벤트 추가 핸들러
|
|
const handleEventInsert = data => {
|
|
insertEvent(data.date, data.code, data.title, data.place, data.time);
|
|
showModal.value = false;
|
|
};
|
|
|
|
// 이벤트 삭제 핸들러
|
|
const handleEventDelete = data => {
|
|
toggleEvent(data.date, data.code, data.title);
|
|
showModal.value = false;
|
|
};
|
|
|
|
// 이벤트 모달 닫기
|
|
const handleCloseModal = () => {
|
|
showModal.value = false;
|
|
};
|
|
|
|
// 달력 이벤트 아이콘 표시 함수
|
|
const handleEventContent = item => {
|
|
if (!item.event) return null;
|
|
|
|
// 공휴일인 경우 텍스트로 표시
|
|
if (item.event.classNames?.includes('holiday-event')) {
|
|
return {
|
|
html: `<div class="holiday-text" style="color: white;">${item.event.title}</div>`,
|
|
};
|
|
}
|
|
|
|
// 현재 이벤트의 타입만 확인
|
|
const eventType = item.event.extendedProps.type;
|
|
if (!eventType) return null;
|
|
|
|
let iconCode = '';
|
|
switch (eventType) {
|
|
case 'birthday':
|
|
iconCode = '300201';
|
|
break;
|
|
case 'vacation':
|
|
iconCode = '300202';
|
|
break;
|
|
case 'birthdayParty':
|
|
iconCode = '300203';
|
|
break;
|
|
case 'dinner':
|
|
iconCode = '300204';
|
|
break;
|
|
case 'teaTime':
|
|
iconCode = '300205';
|
|
break;
|
|
case 'workshop':
|
|
iconCode = '300206';
|
|
break;
|
|
default:
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
html: `<img src="${baseUrl}img/main-category-img/main-${iconCode}.png" class="calendar-event-icon" style="width: 20px; height: 20px; margin: 2px;" />`,
|
|
};
|
|
};
|
|
|
|
// 캘린더 옵션 설정
|
|
const calendarOptions = reactive({
|
|
plugins: [dayGridPlugin, interactionPlugin],
|
|
initialView: 'dayGridMonth',
|
|
headerToolbar: {
|
|
left: 'today',
|
|
center: 'title',
|
|
right: 'prev,next',
|
|
},
|
|
locale: 'kr',
|
|
events: calendarEvents,
|
|
eventOrder: 'sortIdx',
|
|
contentHeight: 'auto',
|
|
eventContent: handleEventContent,
|
|
selectable: true,
|
|
selectAllow: selectInfo => isSelectableDate(selectInfo.start),
|
|
dateClick: handleDateClick,
|
|
dayCellDidMount: arg => {
|
|
// 날씨 정보 업데이트
|
|
addWeatherInfo(arg);
|
|
const dateCell = arg.el;
|
|
|
|
// 마우스 홀드시 이벤트 모달
|
|
dateCell.addEventListener('mousedown', e => {
|
|
if (!isSelectableDate(arg.date)) return; // 공휴일 제외
|
|
const date = $common.dateFormatter(arg.date, 'YMD');
|
|
handleMouseDown(date, e);
|
|
});
|
|
dateCell.addEventListener('mouseup', handleMouseUp);
|
|
dateCell.addEventListener('mouseleave', handleMouseUp);
|
|
},
|
|
dayCellClassNames: getCellClassNames,
|
|
unselectAuto: true,
|
|
droppable: false,
|
|
eventDisplay: 'block',
|
|
customButtons: {
|
|
prev: {
|
|
text: 'PREV',
|
|
click: () => moveCalendar(1),
|
|
},
|
|
today: {
|
|
text: 'TODAY',
|
|
click: () => moveCalendar(3),
|
|
},
|
|
next: {
|
|
text: 'NEXT',
|
|
click: () => moveCalendar(2),
|
|
},
|
|
},
|
|
});
|
|
|
|
// 날짜 정보 업데이트
|
|
const addWeatherInfo = arg => {
|
|
const dateStr = $common.dateFormatter(arg.date, 'YMD');
|
|
// 해당 셀의 날짜와 일치하는 데이터
|
|
const theDayWeatherInfo = dailyWeatherList.value.find(weather => weather.date === dateStr);
|
|
const dayTopEl = arg.el.querySelector('.fc-daygrid-day-top');
|
|
const isWeatherInfoExist = dayTopEl.getElementsByClassName('weather-icon').length > 0; // 중복 방지
|
|
|
|
if (theDayWeatherInfo && !isWeatherInfoExist) {
|
|
let weatherIconUrl = `https://openweathermap.org/img/wn/${theDayWeatherInfo.icon}.png`;
|
|
if (theDayWeatherInfo.icon === '01d' || theDayWeatherInfo.icon === '01n') {
|
|
weatherIconUrl = '/img/icons/sunny-custom.png';
|
|
}
|
|
// 날씨 이미지 세팅
|
|
const weatherEl = document.createElement('img');
|
|
weatherEl.src = weatherIconUrl;
|
|
weatherEl.alt = theDayWeatherInfo.description;
|
|
weatherEl.className = 'weather-icon';
|
|
weatherEl.style.width = '28px';
|
|
weatherEl.style.height = '28px';
|
|
|
|
// 해당 셀에 이미지 넣기
|
|
dayTopEl.classList.add('align-items-center');
|
|
dayTopEl.prepend(weatherEl); // 이상하게 가장 앞에 넣어야 일자 뒤에 나옴 reverse 옵션이 있는듯
|
|
}
|
|
};
|
|
|
|
// 날씨 데이터 변경 감지하여 날씨 정보 업데이트
|
|
watch(dailyWeatherList, async () => {
|
|
await nextTick(); // DOM이 업데이트된 후 실행
|
|
document.querySelectorAll('.fc-daygrid-day').forEach(dayCell => {
|
|
addWeatherInfo({
|
|
el: dayCell,
|
|
date: dayCell.dataset.date,
|
|
});
|
|
});
|
|
});
|
|
|
|
const handleWheelEvent = e => {
|
|
handleCloseModal();
|
|
};
|
|
|
|
// 선택한 날의 이벤트 중에 휴가자 항목을 누를때 휴가페이지 이동
|
|
const handleClickVacation = () => {
|
|
router.push('/vacation');
|
|
};
|
|
|
|
// 달력 뷰 변경 감지 (월 변경 시 데이터 다시 가져오기)
|
|
watch(
|
|
() => fullCalendarRef.value?.getApi().currentData.viewTitle,
|
|
async () => {
|
|
await fetchData();
|
|
},
|
|
);
|
|
|
|
// selectbox 프로젝트 선택 변경 사항 감지
|
|
watch(
|
|
() => projectStore.selectedProject,
|
|
newProject => {
|
|
if (newProject) {
|
|
selectedProject.value = newProject.PROJCTSEQ;
|
|
checkedInProject.value = newProject;
|
|
}
|
|
},
|
|
);
|
|
|
|
onMounted(async () => {
|
|
await userStore.userInfo();
|
|
user.value = userStore.user;
|
|
|
|
// 저장된 선택 프로젝트 가져오기
|
|
const storedProject = projectStore.getSelectedProject();
|
|
if (storedProject) {
|
|
selectedProject.value = storedProject.PROJCTSEQ;
|
|
checkedInProject.value = storedProject;
|
|
}
|
|
|
|
// 오늘 기준 데이터 호출
|
|
const { year, month, day } = $common.getToday();
|
|
const param = new URLSearchParams();
|
|
param.append('year', year);
|
|
param.append('month', month);
|
|
param.append('day', day);
|
|
|
|
// 이벤트 카테고리 호출
|
|
await fetchCategoryList();
|
|
await fetchEventList(param);
|
|
useFilterEventList(month, day);
|
|
|
|
// 스크롤 감지 이벤트 리스너
|
|
window.addEventListener('wheel', handleWheelEvent);
|
|
window.addEventListener('click', colorToday);
|
|
|
|
datePickerStore.initDatePicker(fullCalendarRef, async (year, month, options) => {
|
|
// 데이터 다시 불러오기
|
|
await fetchData();
|
|
});
|
|
});
|
|
</script>
|
|
<style scoped>
|
|
::v-deep(.fc-h-event) {
|
|
background-color: transparent;
|
|
}
|
|
|
|
::v-deep(.event-modal) {
|
|
padding: 8px;
|
|
border: 1px solid #ddd;
|
|
}
|
|
|
|
::v-deep(.event-icon-select:hover) {
|
|
transform: scale(1.1);
|
|
transition: transform 0.2s;
|
|
}
|
|
|
|
/* 이벤트 모달 노출 시 텍스트 선택 방지 */
|
|
::v-deep(.fc-daygrid-day) {
|
|
user-select: none;
|
|
}
|
|
|
|
::v-deep(.fc-daygrid-day-events) {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
/* align-content: flex-start;
|
|
align-items: center;
|
|
text-align: center !important; */
|
|
}
|
|
|
|
/* 공휴일만 가로로 넗게 나오게 */
|
|
::v-deep(.fc-daygrid-event-harness:has(.holiday-event)) {
|
|
width: 100% !important;
|
|
}
|
|
</style>
|