휴가 수정정
This commit is contained in:
parent
f71651729e
commit
bb1715c71b
@ -44,6 +44,30 @@
|
||||
.flatpickr-calendar:after {
|
||||
display: none !important;
|
||||
}
|
||||
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
||||
.fc-toolbar-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 클릭 가능한 날짜 (오늘 + 미래) */
|
||||
.fc-daygrid-day.clickable {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
}
|
||||
/* 마우스를 올렸을 때 효과 */
|
||||
.fc-daygrid-day.clickable:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05); /* 연한 배경 효과 */
|
||||
}
|
||||
/* 주말 (토요일, 일요일) 및 공휴일 */
|
||||
.fc-day-sat-sun {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6; /* 흐려 보이게 */
|
||||
}
|
||||
/* 과거 날짜 (오늘 이전) */
|
||||
.fc-daygrid-day.past {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6; /* 흐려 보이게 */
|
||||
}
|
||||
|
||||
|
||||
/* 본인 모달 */
|
||||
|
||||
@ -116,12 +140,32 @@
|
||||
|
||||
/* 버튼 호버 효과 */
|
||||
.custom-button:hover i {
|
||||
color: #007BFF; /* 호버 시 아이콘 색상 변경 (파란색) */
|
||||
color: #ff0800; /* 호버 시 아이콘 색상 변경 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 모달 배경 투명하게 */
|
||||
.modal-dialog {
|
||||
background: none !important; /* 배경 제거 */
|
||||
box-shadow: none !important; /* 음영 제거 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 모달 내용 스타일 */
|
||||
.modal-content {
|
||||
background: #fff; /* 기존 흰색 배경 유지 */
|
||||
border-radius: 8px;
|
||||
box-shadow: none !important; /* 내부 음영 제거 */
|
||||
padding: 20px;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grayscaleImg {
|
||||
filter: grayscale(100%);
|
||||
|
||||
@ -2,21 +2,21 @@
|
||||
<div class="menu gap-4 justify-content-center mt-5">
|
||||
|
||||
<button
|
||||
class="btn btn-info"
|
||||
class="btn btn-warning"
|
||||
:class="{ active: halfDayType === 'AM' }"
|
||||
@click="toggleHalfDay('AM')"
|
||||
>
|
||||
<i class="bi bi-sun"></i>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-warning"
|
||||
class="btn btn-info"
|
||||
:class="{ active: halfDayType === 'PM' }"
|
||||
@click="toggleHalfDay('PM')"
|
||||
>
|
||||
<i class="bi bi-moon"></i>
|
||||
</button>
|
||||
<div class="save-button-container">
|
||||
<button class="btn btn-success" @click="addVacationRequests">
|
||||
<button class="btn btn-success" @click="addVacationRequests" :disabled="isDisabled">
|
||||
✔
|
||||
</button>
|
||||
</div>
|
||||
@ -26,6 +26,10 @@
|
||||
<script setup>
|
||||
import { defineEmits, ref } from "vue";
|
||||
|
||||
defineProps({
|
||||
isDisabled: Boolean
|
||||
});
|
||||
|
||||
const emit = defineEmits(["toggleHalfDay", "addVacationRequests"]);
|
||||
const halfDayType = ref(null);
|
||||
|
||||
@ -39,6 +43,73 @@ const addVacationRequests = () => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped>
|
||||
/* 버튼 기본 스타일 */
|
||||
.btn {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* 마우스를 올렸을 때 */
|
||||
.btn:hover {
|
||||
filter: brightness(90%);
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* 버튼이 눌렸을 때 */
|
||||
.btn:active {
|
||||
transform: scale(0.9);
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 선택된 (눌린) 버튼 */
|
||||
.btn.active {
|
||||
border: 3px solid #fff; /* 흰색 테두리 강조 */
|
||||
box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* AM 버튼 (선택된 상태) */
|
||||
.btn-warning.active {
|
||||
background-color: #ffca2c !important; /* 진한 노란색 */
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* PM 버튼 (선택된 상태) */
|
||||
.btn-info.active {
|
||||
background-color: #0b5ed7 !important; /* 진한 파란색 */
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* ✔ 버튼 */
|
||||
.btn-success {
|
||||
font-size: 24px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* ✔ 버튼 마우스 오버 */
|
||||
.btn-success:hover {
|
||||
background-color: #198754;
|
||||
box-shadow: 0px 4px 10px rgba(25, 135, 84, 0.4);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* ✔ 버튼 클릭 */
|
||||
.btn-success:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0px 2px 5px rgba(25, 135, 84, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<div class="modal-body">
|
||||
<p>선물할 연차 개수를 선택하세요.</p>
|
||||
|
||||
<div class="justify-content-center d-sm-flex gap-sm-3 align-items-md-center">
|
||||
<div class="justify-content-center d-sm-flex gap-sm-3 align-items-md-center mt-8">
|
||||
<button @click="decreaseCount" :disabled="grantCount < 2" class="count-btn">-</button>
|
||||
<span class="text-dark fw-bold fs-4">{{ grantCount }}</span>
|
||||
<button @click="increaseCount" :disabled="grantCount >= availableQuota" class="count-btn">+</button>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 연차 데이터 없음 -->
|
||||
<p v-else class="text-sm-center mt-5 text-gray">
|
||||
<p v-else class="text-sm-center mt-10 text-gray">
|
||||
🚫 사용한 연차가 없습니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<HalfDayButtons
|
||||
@toggleHalfDay="toggleHalfDay"
|
||||
@addVacationRequests="saveVacationChanges"
|
||||
:isDisabled="!hasChanges"
|
||||
/>
|
||||
</div>
|
||||
<ProfileList
|
||||
@ -106,6 +107,64 @@
|
||||
const calendarDatepicker = ref(null);
|
||||
let fpInstance = null;
|
||||
|
||||
/** ✅ 변경사항 여부 확인 */
|
||||
const hasChanges = computed(() => {
|
||||
return (
|
||||
selectedDates.value.size > 0 ||
|
||||
myVacations.value.some(vac => selectedDates.value.has(vac.date.split("T")[0]))
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
/** ✅ selectedDates가 변경될 때 버튼 상태 즉시 업데이트 */
|
||||
watch(
|
||||
() => Array.from(selectedDates.value.keys()), // keys()를 Array로 변환해서 감시
|
||||
(newKeys) => {
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function handleDateClick(info) {
|
||||
const clickedDateStr = info.dateStr;
|
||||
const clickedDate = info.date;
|
||||
const todayStr = new Date().toISOString().split("T")[0];
|
||||
|
||||
if (
|
||||
clickedDate.getDay() === 0 ||
|
||||
clickedDate.getDay() === 6 ||
|
||||
holidayDates.value.has(clickedDateStr) ||
|
||||
clickedDateStr < todayStr
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isMyVacation = myVacations.value.some(vac => {
|
||||
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
||||
return vacDate === clickedDateStr && !vac.receiverId;
|
||||
});
|
||||
|
||||
if (isMyVacation) {
|
||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
} else {
|
||||
selectedDates.value.set(clickedDateStr, "delete");
|
||||
}
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedDates.value.has(clickedDateStr)) {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
const type = halfDayType.value
|
||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
||||
: "700103";
|
||||
selectedDates.value.set(clickedDateStr, type);
|
||||
halfDayType.value = null;
|
||||
updateCalendarEvents();
|
||||
}
|
||||
|
||||
const calendarOptions = reactive({
|
||||
plugins: [dayGridPlugin, interactionPlugin],
|
||||
initialView: "dayGridMonth",
|
||||
@ -309,47 +368,6 @@
|
||||
return "full-day";
|
||||
};
|
||||
|
||||
function handleDateClick(info) {
|
||||
const clickedDateStr = info.dateStr;
|
||||
const clickedDate = info.date;
|
||||
const todayStr = new Date().toISOString().split("T")[0];
|
||||
|
||||
if (
|
||||
clickedDate.getDay() === 0 ||
|
||||
clickedDate.getDay() === 6 ||
|
||||
holidayDates.value.has(clickedDateStr) ||
|
||||
clickedDateStr < todayStr
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isMyVacation = myVacations.value.some(vac => {
|
||||
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
||||
return vacDate === clickedDateStr && !vac.receiverId;
|
||||
});
|
||||
|
||||
if (isMyVacation) {
|
||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
} else {
|
||||
selectedDates.value.set(clickedDateStr, "delete");
|
||||
}
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedDates.value.has(clickedDateStr)) {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
const type = halfDayType.value
|
||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
||||
: "700103";
|
||||
selectedDates.value.set(clickedDateStr, type);
|
||||
halfDayType.value = null;
|
||||
updateCalendarEvents();
|
||||
}
|
||||
|
||||
function toggleHalfDay(type) {
|
||||
halfDayType.value = halfDayType.value === type ? null : type;
|
||||
}
|
||||
@ -392,6 +410,7 @@
|
||||
}
|
||||
|
||||
async function saveVacationChanges() {
|
||||
if (!hasChanges.value) return;
|
||||
const selectedDatesArray = Array.from(selectedDates.value);
|
||||
const vacationsToAdd = selectedDatesArray
|
||||
.filter(([date, type]) => type !== "delete")
|
||||
@ -458,6 +477,46 @@
|
||||
await nextTick();
|
||||
fullCalendarRef.value.getApi().refetchEvents();
|
||||
}
|
||||
/** ✅ 오늘 이후의 날짜만 클릭 가능하도록 설정 */
|
||||
function markClickableDates() {
|
||||
nextTick(() => {
|
||||
const todayStr = new Date().toISOString().split("T")[0]; // 오늘 날짜 YYYY-MM-DD
|
||||
const todayObj = new Date(todayStr);
|
||||
|
||||
document.querySelectorAll(".fc-daygrid-day").forEach((cell) => {
|
||||
const dateStr = cell.getAttribute("data-date");
|
||||
if (!dateStr) return; // 날짜가 없으면 스킵
|
||||
|
||||
const dateObj = new Date(dateStr);
|
||||
|
||||
// 주말 (토요일, 일요일)
|
||||
if (dateObj.getDay() === 0 || dateObj.getDay() === 6 || holidayDates.value.has(dateStr)) {
|
||||
cell.classList.remove("clickable");
|
||||
cell.classList.add("fc-day-sat-sun");
|
||||
}
|
||||
// 과거 날짜 (오늘 이전)
|
||||
else if (dateObj < todayObj) {
|
||||
cell.classList.remove("clickable");
|
||||
cell.classList.add("past"); // 과거 날짜 비활성화
|
||||
}
|
||||
// 오늘 & 미래 날짜 (클릭 가능)
|
||||
else {
|
||||
cell.classList.add("clickable");
|
||||
cell.classList.remove("past", "fc-day-sat-sun");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** ✅ onMounted 및 달력 변경 시 실행 */
|
||||
onMounted(() => {
|
||||
markClickableDates();
|
||||
});
|
||||
|
||||
watch([holidayDates, lastRemainingYear, lastRemainingMonth], () => {
|
||||
markClickableDates();
|
||||
});
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchUserList();
|
||||
@ -471,10 +530,6 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
||||
.fc-toolbar-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 데이트피커 인풋은 Flatpickr에서 동적으로 스타일 적용됨 */
|
||||
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user