휴가관리 수정
This commit is contained in:
parent
e07593c13b
commit
ac71a9aa1f
@ -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%);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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, {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user