휴가관리 수정

This commit is contained in:
dyhj625 2025-02-28 13:03:52 +09:00
parent e07593c13b
commit ac71a9aa1f
4 changed files with 112 additions and 59 deletions

View File

@ -3,22 +3,33 @@
/* 휴가 */
.fc-daygrid-day-events {
max-height: 100px !important;
overflow-y: auto !important;
}
/* 이벤트 선 없게 */
.fc-event {
border: none;
}
/* 오전전반차 그래프 */
/* 오전 반차 그래프 (왼쪽 절반) */
.fc-daygrid-event.half-day-am {
width: calc(50% - 4px) !important;
width: 50% !important;
height: 8px !important;
border-radius: 2px !important;
font-size: 0px !important;
}
/* 오후반차 그래프프 */
/* 오후 반차 그래프 (오른쪽 절반) */
.fc-daygrid-event.half-day-pm {
width: calc(50% - 4px) !important;
margin-left: auto !important
width: 50% !important;
height: 8px !important;
margin-left: auto !important;
border-radius: 2px !important;
font-size: 0px !important;
}
/* 연차 그래프 (풀풀) */
.fc-daygrid-event.full-day {
width: 100% !important;
height: 8px !important;
margin-left: auto !important;
border-radius: 2px !important;
font-size: 0px !important;
}
/* 공휴일,일요일 색상 */
.fc-day-sun .fc-daygrid-day-number,
@ -39,8 +50,8 @@
.flatpickr-calendar:after {
display: none !important;
}
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
.fc-toolbar-title {
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
.fc-toolbar-title {
cursor: pointer;
}
/* 클릭 가능한 날짜 (오늘 + 미래) */
@ -84,7 +95,6 @@ opacity: 0.6; /* 흐려 보이게 */
/* 본인 모달 */
/* 닫기 버튼 */
.close-btn {
position: absolute;
@ -109,7 +119,6 @@ opacity: 0.6; /* 흐려 보이게 */
/* 선물하기 모달 */
/* 연차 개수 버튼 */
.count-btn {
font-size: 18px;
@ -127,7 +136,6 @@ opacity: 0.6; /* 흐려 보이게 */
background: #cccccc;
cursor: not-allowed;
}
/* 버튼 컨테이너 (우측 정렬) */
.custom-button-container {
display: flex;
@ -141,18 +149,17 @@ opacity: 0.6; /* 흐려 보이게 */
padding: 10px; /* 크기 조정 */
cursor: pointer; /* 클릭 가능하도록 변경 */
}
/* 아이콘 색상 변경 (기본) */
.custom-button i {
color: #282538; /* 기본 아이콘 색상 */
font-size: 25px; /* 아이콘 크기 */
}
/* 버튼 호버 효과 */
.custom-button:hover i {
color: #ff0800; /* 호버 시 아이콘 색상 변경 */
}
.grayscaleImg {
filter: grayscale(100%);
}

View File

@ -28,10 +28,11 @@
</template>
<script setup>
import { defineEmits, ref, defineProps } from "vue";
import { defineEmits, ref, defineProps, watch } from "vue";
const props = defineProps({
isDisabled: Boolean
isDisabled: Boolean,
selectedDate: String // props
});
const emit = defineEmits(["toggleHalfDay", "addVacationRequests", "resetHalfDay"]);
@ -39,15 +40,16 @@ const halfDayType = ref(null);
const toggleHalfDay = (type) => {
halfDayType.value = type;
emit("toggleHalfDay", halfDayType.value);
// 1
setTimeout(() => {
halfDayType.value = null;
}, 1000);
};
// `selectedDate`
watch(() => props.selectedDate, (newDate) => {
if (newDate) {
resetHalfDay();
}
});
//
const resetHalfDay = () => {
halfDayType.value = null;
@ -89,20 +91,20 @@ defineExpose({ resetHalfDay });
/* 선택된 (눌린) 버튼 */
.btn.active {
border: 3px solid #fff; /* 흰색 테두리 강조 */
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; /* 진한 노란색 */
background-color: #ffca2c !important;
color: black;
}
/* PM 버튼 (선택된 상태) */
.btn-info.active {
background-color: #0b5ed7 !important; /* 진한 파란색 */
background-color: #0b5ed7 !important;
color: white;
}

View File

@ -1,11 +1,12 @@
<template>
<div class="mb-4 row">
<label :for="name" class="col-md-2 col-form-label">{{ title }}</label>
<label :for="inputId" class="col-md-2 col-form-label">{{ title }}</label>
<div class="col-md-10">
<input
class="form-control"
type="file"
:id="name"
:id="inputId"
ref="fileInput"
@change="changeHandler"
multiple
/>
@ -21,7 +22,7 @@ import { ref ,computed} from 'vue';
import { fileMsg } from '@/common/msgEnum';
// Props
const prop = defineProps({
const props = defineProps({
title: {
type: String,
default: '라벨',
@ -29,7 +30,7 @@ const prop = defineProps({
},
name: {
type: String,
default: 'nameplz',
default: 'fileInput',
required: true,
},
isAlert: {
@ -38,12 +39,13 @@ const prop = defineProps({
required: false,
},
});
const inputId = computed(() => props.name || 'defaultFileInput');
const emits = defineEmits(['update:data', 'update:isValid']);
const MAX_TOTAL_SIZE = 5 * 1024 * 1024; // 5MB
const MAX_FILE_COUNT = 5; //
const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'application/pdf']; //
const ALLOWED_FILE_TYPES = []; //
const showError = ref(false);
const fileMsgKey = ref(''); //
@ -51,9 +53,12 @@ const fileMsgKey = ref(''); // 에러 메시지 키
const changeHandler = (event) => {
const files = Array.from(event.target.files);
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
const invalidFiles = files.filter(file => !ALLOWED_FILE_TYPES.includes(file.type));
//
// ALLOWED_FILE_TYPES
const invalidFiles = ALLOWED_FILE_TYPES.length > 0
? files.filter(file => !ALLOWED_FILE_TYPES.includes(file.type))
: [];
if (totalSize > MAX_TOTAL_SIZE) {
showError.value = true;
fileMsgKey.value = 'FileMaxSizeMsg';

View File

@ -7,9 +7,11 @@
<div class="sidebar-content">
<div class="sidebar-actions text-center my-3">
<HalfDayButtons
ref="halfDayButtonsRef"
@toggleHalfDay="toggleHalfDay"
@addVacationRequests="saveVacationChanges"
:isDisabled="!hasChanges"
:selectedDate="selectedDate"
/>
</div>
<ProfileList
@ -58,28 +60,31 @@
</div>
</template>
<script setup>
import { reactive, ref, onMounted, nextTick, computed, watch } from "vue";
import axios from "@api";
import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction";
// Flatpickr MonthSelect
import flatpickr from "flatpickr";
import monthSelectPlugin from "flatpickr/dist/plugins/monthSelect/index";
import "flatpickr/dist/flatpickr.min.css";
import "flatpickr/dist/plugins/monthSelect/style.css";
<script setup>
import { reactive, ref, onMounted, nextTick, computed, watch, onBeforeUnmount } from "vue";
import axios from "@api";
import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction";
// Flatpickr MonthSelect
import flatpickr from "flatpickr";
import monthSelectPlugin from "flatpickr/dist/plugins/monthSelect/index";
import "flatpickr/dist/flatpickr.min.css";
import "flatpickr/dist/plugins/monthSelect/style.css";
import "@/assets/css/app-calendar.css";
import "bootstrap-icons/font/bootstrap-icons.css";
import HalfDayButtons from "@c/button/HalfDayButtons.vue";
import ProfileList from "@c/vacation/ProfileList.vue";
import VacationModal from "@c/modal/VacationModal.vue";
import VacationGrantModal from "@c/modal/VacationGrantModal.vue";
import { useUserStore } from "@s/userList";
import { useUserInfoStore } from "@s/useUserInfoStore";
import { fetchHolidays } from "@c/calendar/holiday.js";
import { useToastStore } from '@s/toastStore';
import "@/assets/css/app-calendar.css";
import "bootstrap-icons/font/bootstrap-icons.css";
import HalfDayButtons from "@c/button/HalfDayButtons.vue";
import ProfileList from "@c/vacation/ProfileList.vue";
import VacationModal from "@c/modal/VacationModal.vue";
import VacationGrantModal from "@c/modal/VacationGrantModal.vue";
import { useUserStore } from "@s/userList";
import { useUserInfoStore } from "@s/useUserInfoStore";
import { fetchHolidays } from "@c/calendar/holiday.js";
import { useToastStore } from '@s/toastStore';
import { useRouter } from "vue-router";
const router = useRouter();
const toastStore = useToastStore();
const userStore = useUserInfoStore();
@ -90,7 +95,7 @@
const receivedVacations = ref([]);
const isModalOpen = ref(false);
const remainingVacationData = ref({});
const selectedDate = ref(null);
const lastRemainingYear = ref(new Date().getFullYear());
const lastRemainingMonth = ref(String(new Date().getMonth() + 1).padStart(2, "0"));
const isGrantModalOpen = ref(false);
@ -106,6 +111,39 @@
const fetchedEvents = ref([]);
const halfDayButtonsRef = ref(null);
//
router.beforeEach((to, from, next) => {
if (hasChanges.value) {
const answer = window.confirm("저장하지 않은 변경 사항이 있습니다. 이동하시겠습니까?");
if (!answer) {
return next(false); //
}
}
next();
});
onBeforeUnmount(() => {
window.removeEventListener("beforeunload", preventUnsavedChanges);
});
function preventUnsavedChanges(event) {
if (hasChanges.value) {
event.preventDefault();
event.returnValue = ""; //
}
}
// `selectedDates`
watch(
() => Array.from(selectedDates.value.keys()), //
(newKeys) => {
if (halfDayButtonsRef.value) {
halfDayButtonsRef.value.resetHalfDay();
}
},
{ deep: true }
);
// ref
const calendarDatepicker = ref(null);
let fpInstance = null;
@ -192,6 +230,7 @@ function handleDateClick(info) {
await fetchRemainingVacation();
const currentYear = new Date().getFullYear();
await fetchVacationHistory(currentYear);
window.addEventListener("beforeunload", preventUnsavedChanges);
// Flatpickr ( )
fpInstance = flatpickr(calendarDatepicker.value, {