휴가 수정정
This commit is contained in:
parent
f71651729e
commit
bb1715c71b
@ -44,6 +44,30 @@
|
|||||||
.flatpickr-calendar:after {
|
.flatpickr-calendar:after {
|
||||||
display: none !important;
|
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 {
|
.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 {
|
.grayscaleImg {
|
||||||
filter: grayscale(100%);
|
filter: grayscale(100%);
|
||||||
|
|||||||
@ -2,21 +2,21 @@
|
|||||||
<div class="menu gap-4 justify-content-center mt-5">
|
<div class="menu gap-4 justify-content-center mt-5">
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="btn btn-info"
|
class="btn btn-warning"
|
||||||
:class="{ active: halfDayType === 'AM' }"
|
:class="{ active: halfDayType === 'AM' }"
|
||||||
@click="toggleHalfDay('AM')"
|
@click="toggleHalfDay('AM')"
|
||||||
>
|
>
|
||||||
<i class="bi bi-sun"></i>
|
<i class="bi bi-sun"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-warning"
|
class="btn btn-info"
|
||||||
:class="{ active: halfDayType === 'PM' }"
|
:class="{ active: halfDayType === 'PM' }"
|
||||||
@click="toggleHalfDay('PM')"
|
@click="toggleHalfDay('PM')"
|
||||||
>
|
>
|
||||||
<i class="bi bi-moon"></i>
|
<i class="bi bi-moon"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="save-button-container">
|
<div class="save-button-container">
|
||||||
<button class="btn btn-success" @click="addVacationRequests">
|
<button class="btn btn-success" @click="addVacationRequests" :disabled="isDisabled">
|
||||||
✔
|
✔
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -26,6 +26,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { defineEmits, ref } from "vue";
|
import { defineEmits, ref } from "vue";
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
isDisabled: Boolean
|
||||||
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["toggleHalfDay", "addVacationRequests"]);
|
const emit = defineEmits(["toggleHalfDay", "addVacationRequests"]);
|
||||||
const halfDayType = ref(null);
|
const halfDayType = ref(null);
|
||||||
|
|
||||||
@ -40,5 +44,72 @@ const addVacationRequests = () => {
|
|||||||
</script>
|
</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>
|
</style>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>선물할 연차 개수를 선택하세요.</p>
|
<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>
|
<button @click="decreaseCount" :disabled="grantCount < 2" class="count-btn">-</button>
|
||||||
<span class="text-dark fw-bold fs-4">{{ grantCount }}</span>
|
<span class="text-dark fw-bold fs-4">{{ grantCount }}</span>
|
||||||
<button @click="increaseCount" :disabled="grantCount >= availableQuota" class="count-btn">+</button>
|
<button @click="increaseCount" :disabled="grantCount >= availableQuota" class="count-btn">+</button>
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 연차 데이터 없음 -->
|
<!-- 연차 데이터 없음 -->
|
||||||
<p v-else class="text-sm-center mt-5 text-gray">
|
<p v-else class="text-sm-center mt-10 text-gray">
|
||||||
🚫 사용한 연차가 없습니다.
|
🚫 사용한 연차가 없습니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
<HalfDayButtons
|
<HalfDayButtons
|
||||||
@toggleHalfDay="toggleHalfDay"
|
@toggleHalfDay="toggleHalfDay"
|
||||||
@addVacationRequests="saveVacationChanges"
|
@addVacationRequests="saveVacationChanges"
|
||||||
|
:isDisabled="!hasChanges"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ProfileList
|
<ProfileList
|
||||||
@ -106,6 +107,64 @@
|
|||||||
const calendarDatepicker = ref(null);
|
const calendarDatepicker = ref(null);
|
||||||
let fpInstance = 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({
|
const calendarOptions = reactive({
|
||||||
plugins: [dayGridPlugin, interactionPlugin],
|
plugins: [dayGridPlugin, interactionPlugin],
|
||||||
initialView: "dayGridMonth",
|
initialView: "dayGridMonth",
|
||||||
@ -309,47 +368,6 @@
|
|||||||
return "full-day";
|
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) {
|
function toggleHalfDay(type) {
|
||||||
halfDayType.value = halfDayType.value === type ? null : type;
|
halfDayType.value = halfDayType.value === type ? null : type;
|
||||||
}
|
}
|
||||||
@ -392,6 +410,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function saveVacationChanges() {
|
async function saveVacationChanges() {
|
||||||
|
if (!hasChanges.value) return;
|
||||||
const selectedDatesArray = Array.from(selectedDates.value);
|
const selectedDatesArray = Array.from(selectedDates.value);
|
||||||
const vacationsToAdd = selectedDatesArray
|
const vacationsToAdd = selectedDatesArray
|
||||||
.filter(([date, type]) => type !== "delete")
|
.filter(([date, type]) => type !== "delete")
|
||||||
@ -458,6 +477,46 @@
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
fullCalendarRef.value.getApi().refetchEvents();
|
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 () => {
|
onMounted(async () => {
|
||||||
await fetchUserList();
|
await fetchUserList();
|
||||||
@ -471,10 +530,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
|
||||||
.fc-toolbar-title {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 데이트피커 인풋은 Flatpickr에서 동적으로 스타일 적용됨 */
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user