@@ -56,6 +58,13 @@ import QEditor from '@/components/editor/QEditor.vue';
import FormInput from '@/components/input/FormInput.vue';
import FormSelect from '@/components/input/FormSelect.vue';
import PlusBtn from '../button/PlusBtn.vue';
+import { useUserInfoStore } from '@s/useUserInfoStore';
+
+// 유저 구분
+const userStore = useUserInfoStore();
+
+// 유저 상태에 따른 disabled
+const isDisabled = computed(() => userStore.user.role !== 'ROLE_ADMIN');
const emit = defineEmits(['close','addCategory','addWord']);
@@ -73,6 +82,11 @@ const addCategoryAlert = ref(false);
//선택 카테고리
const selectCategory = ref('');
+// 제목 상태
+const computedTitle = computed(() =>
+ wordTitle.value === '' ? props.titleValue : wordTitle.value
+);
+
// 카테고리 상태
const selectedCategory = computed(() =>
selectCategory.value === '' ? props.formValue : selectCategory.value
@@ -104,15 +118,18 @@ const toggleInput = () => {
showInput.value = !showInput.value;
};
+
// 카테고리 저장
const saveInput = () => {
if(addCategory.value == ''){
addCategoryAlert.value = true;
return;
+ }else {
+ addCategoryAlert.value = false;
}
// console.log('입력값 저장됨!',addCategory.value);
emit('addCategory', addCategory.value);
- showInput.value = false;
+ // showInput.value = false;
};
const onChange = (newValue) => {
@@ -122,9 +139,9 @@ const onChange = (newValue) => {
//용어 등록
const saveWord = () => {
//validation
-
+
// 용어 체크
- if(wordTitle.value == ''){
+ if(computedTitle.value == '' || computedTitle.length == 0){
wordTitleAlert.value = true;
return;
}
@@ -137,7 +154,7 @@ const saveWord = () => {
const wordData = {
id: props.NumValue || null,
- title: wordTitle.value,
+ title: computedTitle.value,
category: selectedCategory.value,
content: content.value,
};
diff --git a/src/views/board/BoardList.vue b/src/views/board/BoardList.vue
index 34740d2..523356f 100644
--- a/src/views/board/BoardList.vue
+++ b/src/views/board/BoardList.vue
@@ -1,102 +1,104 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- | 번호 |
- 제목 |
- 작성자 |
- 작성일 |
- 조회수 |
-
-
-
-
-
-
- | 공지 |
-
- 📌 {{ notice.title }}
-
-
- N
- |
- {{ notice.author }} |
- {{ notice.date }} |
- {{ notice.views }} |
-
-
-
-
- | {{ post.id }} |
-
- {{ post.title }}
-
-
- N
- |
- {{ post.author }} |
- {{ post.date }} |
- {{ post.views }} |
-
-
-
-
+
+
-
-
+
+
+
+
+
+ | 번호 |
+ 제목 |
+ 작성자 |
+ 작성일 |
+ 조회수 |
+
+
+
+
+
+
+ | 공지 |
+
+ 📌 {{ notice.title }}
+
+
+ N
+ |
+ {{ notice.author }} |
+ {{ notice.date }} |
+ {{ notice.views }} |
+
+
+
+
+ | {{ post.id }} |
+
+ {{ post.title }}
+
+
+ N
+ |
+ {{ post.author }} |
+ {{ post.date }} |
+ {{ post.views }} |
+
+
+
+
+
+
@@ -262,4 +264,9 @@ onMounted(() => {
diff --git a/src/views/board/BoardView.vue b/src/views/board/BoardView.vue
index f4114ce..898b39d 100644
--- a/src/views/board/BoardView.vue
+++ b/src/views/board/BoardView.vue
@@ -98,6 +98,7 @@
>>>>>> origin/main
/>
{
}
lastClickedButton.value = null;
} else {
- passwordAlert.value = "비밀번호가 일치하지 않습니다.";
+ passwordAlert.value = "비밀번호가 일치하지 않습니다.????";
}
} catch (error) {
// console.log("📌 전체 오류:", error);
diff --git a/src/views/vacation/VacationManagement.vue b/src/views/vacation/VacationManagement.vue
index bfb72c6..1d6eda5 100644
--- a/src/views/vacation/VacationManagement.vue
+++ b/src/views/vacation/VacationManagement.vue
@@ -9,16 +9,16 @@
@profileClick="handleProfileClick"
:remainingVacationData="remainingVacationData"
/>
-
@@ -99,7 +99,6 @@ const handleProfileClick = async (user) => {
if (user.MEMBERSEQ === userStore.user.id) {
// 내 프로필을 클릭한 경우
const response = await axios.get(`vacation/history`);
- console.log(response)
if (response.status === 200 && response.data) {
myVacations.value = response.data.data.usedVacations || [];
@@ -188,23 +187,29 @@ const getVacationType = (typeCode) => {
return vacationCodeMap.value[typeCode] || "기타";
};
-/**
- * API 이벤트(fetchedEvents)와 사용자가 선택한 날짜(selectedDates)를 병합하여
- * calendarEvents를 업데이트하는 함수
- * - 선택 이벤트는 display: "background" 옵션을 사용하여 배경으로 표시
- * - 선택된 타입에 따라 클래스(selected-am, selected-pm, selected-full)를 부여함
- */
+
function updateCalendarEvents() {
-const selectedEvents = Array.from(selectedDates.value).map(([date, type]) => {
- return {
- title: getVacationType(type),
- start: date,
- backgroundColor: "rgba(0, 128, 0, 0.3)",
- display: "background",
- classNames: [getVacationTypeClass(type)],
- };
-});
-calendarEvents.value = [...fetchedEvents.value, ...selectedEvents];
+ // 신규 선택한 연차(추가 대상): type이 "delete"가 아닌 항목
+ const selectedEvents = Array.from(selectedDates.value)
+ .filter(([date, type]) => type !== "delete")
+ .map(([date, type]) => ({
+ title: getVacationType(type),
+ start: date,
+ backgroundColor: "rgb(113 212 243 / 76%)",
+ textColor: "#fff", // 흰색 텍스트
+ display: "background",
+ classNames: [getVacationTypeClass(type), "selected-event"]
+ }));
+
+ // 기존 백엔드에서 불러온 저장된 연차 이벤트 중,
+ // 해당 날짜가 삭제 대상으로 표시되어 있으면 제거
+ const filteredFetchedEvents = fetchedEvents.value.filter(event => {
+ if (event.saved) { // saved 플래그가 있는 이벤트는 저장된 연차
+ return selectedDates.value.get(event.start) !== "delete";
+ }
+ return true;
+ });
+ calendarEvents.value = [...filteredFetchedEvents, ...selectedEvents];
}
/**
@@ -221,30 +226,46 @@ calendarEvents.value = [...fetchedEvents.value, ...selectedEvents];
* - 주말(토, 일)과 공휴일은 클릭되지 않음
* - 클릭 시 해당 날짜를 selectedDates에 추가 또는 제거한 후 updateCalendarEvents() 호출
*/
-function handleDateClick(info) {
-const clickedDateStr = info.dateStr;
-const clickedDate = info.date;
+ function handleDateClick(info) {
+ const clickedDateStr = info.dateStr; // "YYYY-MM-DD" 형식
+ const clickedDate = info.date;
+ const todayStr = new Date().toISOString().split("T")[0];
-// 주말 (토:6, 일:0)은 클릭 무시
-if (clickedDate.getDay() === 0 || clickedDate.getDay() === 6) {
+ // 주말, 공휴일, 오늘 이전 날짜는 클릭 불가
+ if (
+ clickedDate.getDay() === 0 ||
+ clickedDate.getDay() === 6 ||
+ holidayDates.value.has(clickedDateStr) ||
+ clickedDateStr < todayStr
+ ) {
return;
-}
-// 공휴일이면 클릭 무시
-if (holidayDates.value.has(clickedDateStr)) {
- return;
-}
-if (!selectedDates.value.has(clickedDateStr)) {
- const type = halfDayType.value
- ? halfDayType.value === "AM"
- ? "700101"
- : "700102"
- : "700103";
- selectedDates.value.set(clickedDateStr, type);
-} else {
+ }
+
+ // 토글: 이미 선택된 날짜라면 해제
+ if (selectedDates.value.has(clickedDateStr)) {
selectedDates.value.delete(clickedDateStr);
-}
-halfDayType.value = null;
-updateCalendarEvents();
+ updateCalendarEvents();
+ return;
+ }
+
+ // 저장된(보낸사람 없는) 연차가 있는지 확인
+ const unsentVacation = myVacations.value.find(
+ (vac) => vac.LOCVACUDT && vac.LOCVACUDT.startsWith(clickedDateStr) && !vac.LOCVACRMM
+ );
+
+ if (unsentVacation) {
+ // 기존 저장된 연차가 있다면, 클릭 시 "delete" 플래그 지정 (즉, 숨김 처리)
+ selectedDates.value.set(clickedDateStr, "delete");
+ } else {
+ // 그렇지 않으면 신규 연차 추가: halfDayType 값에 따라 결정
+ const type = halfDayType.value
+ ? (halfDayType.value === "AM" ? "700101" : "700102")
+ : "700103";
+ selectedDates.value.set(clickedDateStr, type);
+ }
+
+ halfDayType.value = null;
+ updateCalendarEvents();
}
/**
@@ -257,66 +278,89 @@ halfDayType.value = halfDayType.value === type ? null : type;
/**
* 백엔드에서 휴가 데이터를 가져와 이벤트로 변환
*/
-async function fetchVacationData(year, month) {
-try {
+ async function fetchVacationData(year, month) {
+ try {
const response = await axios.get(`vacation/list/${year}/${month}`);
- if (response.status == 200) {
- const vacationList = response.data;
- const events = vacationList
+ if (response.status === 200) {
+ const vacationList = response.data;
+ // 내 연차 데이터 업데이트 (사용자 본인의 연차만)
+ myVacations.value = vacationList.filter(
+ (vac) => vac.MEMBERSEQ === userStore.user.id
+ );
+ // 기존 저장된 연차 이벤트에 saved 플래그 추가
+ const events = vacationList
+ .filter((vac) => !vac.LOCVACRMM) // 보낸사람이 없는(저장된) 연차
.map((vac) => {
- let dateStr = vac.LOCVACUDT.split("T")[0];
- let className = "fc-daygrid-event";
- let backgroundColor = userColors.value[vac.MEMBERSEQ] || "#FFFFFF";
- return {
+ let dateStr = vac.LOCVACUDT.split("T")[0];
+ let backgroundColor = userColors.value[vac.MEMBERSEQ] || "#FFFFFF";
+ return {
title: getVacationType(vac.LOCVACTYP),
start: dateStr,
backgroundColor,
classNames: [getVacationTypeClass(vac.LOCVACTYP)],
- };
+ saved: true, // saved 플래그 추가
+ };
})
.filter((event) => event !== null);
- return events;
+ return events;
} else {
- console.warn("📌 휴가 데이터를 불러오지 못함");
- return [];
+ console.warn("📌 휴가 데이터를 불러오지 못함");
+ return [];
}
-} catch (error) {
+ } catch (error) {
console.error("Error fetching vacation data:", error);
return [];
-}
+ }
}
/**
* 휴가 요청 추가 (선택된 날짜를 백엔드로 전송)
*/
-async function addVacationRequests() {
-if (selectedDates.value.size === 0) {
- alert("휴가를 선택해주세요.");
- return;
-}
-const vacationRequests = Array.from(selectedDates.value).map(([date, type]) => ({
- date,
- type,
-}));
-try {
- const response = await axios.post("vacation", vacationRequests);
+ async function saveVacationChanges() {
+ // 추가할 연차: selectedDates 항목 중 type이 "delete"가 아닌 경우
+ const selectedDatesArray = Array.from(selectedDates.value);
+ const vacationsToAdd = selectedDatesArray
+ .filter(([date, type]) => type !== "delete")
+ .filter(([date, type]) =>
+ // 기존 데이터에 없거나, 기존 데이터에 있더라도 보낸사람(LOCVACRMM)이 있는 경우 추가
+ !myVacations.value.some(vac => vac.LOCVACUDT.startsWith(date)) ||
+ myVacations.value.some(vac => vac.LOCVACUDT.startsWith(date) && vac.LOCVACRMM)
+ )
+ .map(([date, type]) => ({ date, type }));
+
+ // 삭제할 연차: 기존 데이터 중 보낸사람이 없는 항목에서,
+ // 해당 날짜가 "delete"로 지정되었거나 선택되지 않은 경우
+ const vacationsToDelete = myVacations.value
+ .filter(vac => {
+ const date = vac.LOCVACUDT.split("T")[0];
+ // 오직 해당 날짜가 "delete"로 선택된 경우만 삭제 대상으로 처리
+ return selectedDates.value.get(date) === "delete" && !vac.LOCVACRMM;
+ })
+ .map(vac => {
+ const id = vac.LOCVACSEQ ;
+ return typeof id === "number" ? Number(id) : id;
+ });
+
+ try {
+ const response = await axios.post("vacation/batchUpdate", {
+ add: vacationsToAdd,
+ delete: vacationsToDelete
+ });
if (response.data && response.data.status === "OK") {
- alert("휴가가 저장되었습니다.");
- await fetchRemainingVacation();
- // 저장 후 현재 달 데이터 다시 불러오기
- const currentDate = fullCalendarRef.value.getApi().getDate();
- const year = currentDate.getFullYear();
- const month = String(currentDate.getMonth() + 1).padStart(2, "0");
- loadCalendarData(year, month);
- selectedDates.value.clear();
- updateCalendarEvents();
+ alert("✅ 휴가 변경 사항이 저장되었습니다.");
+ await fetchRemainingVacation();
+ const currentDate = fullCalendarRef.value.getApi().getDate();
+ await loadCalendarData(currentDate.getFullYear(), currentDate.getMonth() + 1);
+ // 초기화: 선택한 날짜 해제
+ selectedDates.value.clear();
+ updateCalendarEvents();
} else {
- alert("휴가 저장 중 오류가 발생했습니다.");
+ alert("❌ 휴가 저장 중 오류가 발생했습니다.");
}
-} catch (error) {
- console.error(error);
- alert("휴가 저장에 실패했습니다.");
-}
+ } catch (error) {
+ console.error("🚨 휴가 변경 저장 실패:", error);
+ alert("❌ 휴가 저장 요청에 실패했습니다.");
+ }
}
/**
@@ -377,5 +421,7 @@ await loadCalendarData(year, month);
diff --git a/src/views/wordDict/wordDict.vue b/src/views/wordDict/wordDict.vue
index 68a060b..d027485 100644
--- a/src/views/wordDict/wordDict.vue
+++ b/src/views/wordDict/wordDict.vue
@@ -1,6 +1,6 @@
-
+
-
-
-
-
로딩 중...
+
+
+
+
로딩 중...
-
-
{{ error }}
+
+
{{ error }}
-
-
+
+
-
-
용어집의 용어가 없습니다.
+
+
용어집의 용어가 없습니다.
-
+
+
+