Merge branch 'main' into style
This commit is contained in:
commit
61f9fc51fd
@ -157,7 +157,7 @@
|
|||||||
.fc-toolbar-title {
|
.fc-toolbar-title {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
/* 클릭 가능한 날짜 (오늘 + 미래) */
|
/* 클릭 가능한 날짜 */
|
||||||
.fc-daygrid-day.clickable {
|
.fc-daygrid-day.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s ease-in-out;
|
transition: background-color 0.2s ease-in-out;
|
||||||
@ -362,6 +362,28 @@
|
|||||||
background-color: #0b5ed7 !important;
|
background-color: #0b5ed7 !important;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
/* 풀 연차 버튼 스타일 */
|
||||||
|
.vac-btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #28a745; /* 녹색 */
|
||||||
|
border-color: #28a745;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem 0 rgba(40, 167, 69, 0.4);
|
||||||
|
font-size: 28px;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
/* 풀 연차 버튼 활성화 스타일 */
|
||||||
|
.vac-btn-primary.active {
|
||||||
|
background-color: #218838 !important;
|
||||||
|
color: #fff;
|
||||||
|
border: 3px solid #91d091 !important;
|
||||||
|
box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.3);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
/* 풀 연차 버튼이 눌렸을 때 효과 */
|
||||||
|
.vac-btn-primary:active {
|
||||||
|
transform: scale(0.9);
|
||||||
|
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
/* 버튼 기본 */
|
/* 버튼 기본 */
|
||||||
.vac-btn-success {
|
.vac-btn-success {
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
:unknown="comment.author === '익명'"
|
:unknown="comment.author === '익명'"
|
||||||
:isCommentAuthor="isCommentAuthor"
|
:isCommentAuthor="isCommentAuthor"
|
||||||
:boardId="comment.boardId"
|
:boardId="comment.boardId"
|
||||||
:profileName="comment.author"
|
:profileName="comment.nickname ? comment.nickname : comment.author"
|
||||||
:date="comment.createdAt"
|
:date="comment.createdAt"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
:profileImg="comment.profileImg"
|
:profileImg="comment.profileImg"
|
||||||
@ -17,7 +17,7 @@
|
|||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
/>
|
/>
|
||||||
<!-- 댓글 비밀번호 입력창 (익명일 경우) -->
|
<!-- 댓글 비밀번호 입력창 (익명일 경우) -->
|
||||||
<div v-if="currentPasswordCommentId === comment.commentId && unknown && comment.author == '익명'" class="mt-3 w-20 ms-auto">
|
<div v-if="currentPasswordCommentId === comment.commentId && unknown && comment.author == '익명'" class="mt-3 w-px-200 ms-auto">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
|
|||||||
@ -3,69 +3,71 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<!-- 댓글 입력 섹션 -->
|
<!-- 댓글 입력 섹션 -->
|
||||||
<div class="d-flex justify-content-start align-items-top">
|
<div class="d-flex justify-content-start align-items-top">
|
||||||
<!-- 프로필섹션 -->
|
|
||||||
<!-- <div class="avatar-wrapper">
|
|
||||||
<div v-if="!unknown" class="avatar me-4">
|
|
||||||
<img src="/img/avatars/11.png" alt="Avatar" class="rounded-circle">
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
<!-- 텍스트박스 -->
|
|
||||||
<div class="w-100">
|
<div class="w-100">
|
||||||
<textarea
|
<textarea
|
||||||
class="form-control mb-2"
|
class="form-control mb-1"
|
||||||
placeholder="댓글 달기"
|
placeholder="댓글 달기"
|
||||||
rows="3"
|
rows="3"
|
||||||
:maxlength="maxLength"
|
:maxlength="maxLength"
|
||||||
v-model="comment"
|
v-model="comment"
|
||||||
@input="alertTextHandler"
|
@input="clearAlert('comment')"
|
||||||
></textarea>
|
></textarea>
|
||||||
<span v-if="commentAlert" class="invalid-feedback d-inline text-start ms-2 mb-2">{{ commentAlert }}</span>
|
<span v-if="commentAlert" class="invalid-feedback d-inline text-start ms-2 mb-2">{{ commentAlert }}</span>
|
||||||
<span v-else class="invalid-feedback d-inline text-start ms-2">{{ textAlert }}</span>
|
<span v-else class="invalid-feedback d-inline">{{ textAlert }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 옵션 및 버튼 섹션 -->
|
<!-- 옵션 및 버튼 섹션 -->
|
||||||
<div class="d-flex justify-content-between mt-1">
|
<div class="d-flex justify-content-between align-items-center mt-1 pb-4">
|
||||||
<div class="row g-2">
|
<!-- 왼쪽: 익명 체크박스 -->
|
||||||
<div class="d-flex flex-wrap align-items-center mb-2">
|
<div v-if="unknown" class="form-check form-check-inline mb-0 me-2">
|
||||||
<!-- 익명 체크박스 (익명게시판일 경우에만)-->
|
<input
|
||||||
<div v-if="unknown" class="form-check form-check-inline mb-0 me-4 d-flex align-items-center">
|
class="form-check-input"
|
||||||
<input
|
type="checkbox"
|
||||||
class="form-check-input me-2"
|
:id="`checkboxAnnonymous${commnetId}`"
|
||||||
type="checkbox"
|
v-model="isCheck"
|
||||||
:id="`checkboxAnnonymous${commnetId}`"
|
@change="pwd2AlertHandler"
|
||||||
v-model="isCheck"
|
/>
|
||||||
@change="pwd2AlertHandler"
|
<label class="form-check-label text-nowrap" :for="`checkboxAnnonymous${commnetId}`">익명</label>
|
||||||
/>
|
</div>
|
||||||
<label class="form-check-label" :for="`checkboxAnnonymous${commnetId}`">익명</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 비밀번호 입력 필드 (익명이 선택된 경우에만 표시) -->
|
<!-- 중앙: 닉네임 & 비밀번호 입력 필드 (가로 정렬) -->
|
||||||
<template v-if="isCheck">
|
<div v-if="isCheck" class="d-flex flex-grow-1 gap-2">
|
||||||
<div class="d-flex align-items-center col">
|
<!-- 닉네임 입력 영역 -->
|
||||||
<input
|
<div class="position-relative">
|
||||||
type="password"
|
<input
|
||||||
id="basic-default-password"
|
type="text"
|
||||||
class="form-control w-80"
|
class="form-control mb-1"
|
||||||
autocomplete="new-password"
|
v-model="nickname"
|
||||||
v-model="password"
|
placeholder="닉네임"
|
||||||
placeholder="비밀번호 입력"
|
@input="clearAlert('nickname')"
|
||||||
@input="passwordAlertTextHandler"
|
/>
|
||||||
/>
|
<!-- 닉네임 경고 메시지 -->
|
||||||
</div>
|
<div v-if="nicknameAlert" class="position-absolute text-danger small top-100 start-0" >
|
||||||
</template>
|
{{ nicknameAlert }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div style="width: 70px"></div>
|
<!-- 비밀번호 입력 영역 -->
|
||||||
<div class="col">
|
<div class="position-relative">
|
||||||
<span v-if="passwordAlert" class="invalid-feedback d-inline">{{ passwordAlert }}</span>
|
<input
|
||||||
<span v-else class="invalid-feedback d-inline">{{ passwordAlert2 }}</span>
|
type="password"
|
||||||
|
id="basic-default-password"
|
||||||
|
class="form-control mb-1"
|
||||||
|
autocomplete="new-password"
|
||||||
|
v-model="password"
|
||||||
|
placeholder="비밀번호"
|
||||||
|
@input="clearAlert('password')"
|
||||||
|
/>
|
||||||
|
<!-- 비밀번호 경고 메시지 -->
|
||||||
|
<div v-if="passwordAlert2" class="position-absolute text-danger small top-100 start-0">
|
||||||
|
{{ passwordAlert2 }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 답변 쓰기 버튼 -->
|
<!-- 오른쪽: 답변 쓰기 버튼 -->
|
||||||
<div class="ms-auto mt-3 mt-md-0">
|
<div class="ms-auto">
|
||||||
<SaveBtn class="btn btn-primary" @click="handleCommentSubmit"></SaveBtn>
|
<SaveBtn class="btn btn-primary" @click="handleCommentSubmit"></SaveBtn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -108,37 +110,54 @@
|
|||||||
const password = ref('');
|
const password = ref('');
|
||||||
const isCheck = ref(false);
|
const isCheck = ref(false);
|
||||||
const textAlert = ref('');
|
const textAlert = ref('');
|
||||||
|
const nicknameAlert = ref('');
|
||||||
const passwordAlert2 = ref('');
|
const passwordAlert2 = ref('');
|
||||||
|
const nickname = ref('');
|
||||||
|
|
||||||
const emit = defineEmits(['submitComment']);
|
const emit = defineEmits(['submitComment']);
|
||||||
|
|
||||||
const alertTextHandler = () => {
|
// 입력 필드별 경고 메시지 초기화
|
||||||
textAlert.value = '';
|
const clearAlert = field => {
|
||||||
};
|
if (field === 'comment') textAlert.value = '';
|
||||||
|
if (field === 'nickname') nicknameAlert.value = '';
|
||||||
const passwordAlertTextHandler = event => {
|
if (field === 'password') passwordAlert2.value = '';
|
||||||
event.target.value = event.target.value.replace(/\s/g, '');
|
|
||||||
passwordAlert2.value = '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCommentSubmit = () => {
|
const handleCommentSubmit = () => {
|
||||||
|
let isValid = true;
|
||||||
|
|
||||||
|
// 댓글 공백 체크
|
||||||
if (!$common.isNotEmpty(comment.value)) {
|
if (!$common.isNotEmpty(comment.value)) {
|
||||||
textAlert.value = '댓글을 입력하세요';
|
textAlert.value = '댓글을 입력해주세요.';
|
||||||
return false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
textAlert.value = '';
|
textAlert.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCheck.value && !$common.isNotEmpty(password.value)) {
|
// 익명 선택 시 닉네임 & 비밀번호 체크
|
||||||
passwordAlert2.value = '비밀번호를 입력하세요';
|
if (isCheck.value) {
|
||||||
return false;
|
if (!$common.isNotEmpty(nickname.value)) {
|
||||||
} else {
|
nicknameAlert.value = '닉네임을 입력해주세요.';
|
||||||
passwordAlert2.value = '';
|
isValid = false;
|
||||||
|
} else {
|
||||||
|
nicknameAlert.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$common.isNotEmpty(password.value)) {
|
||||||
|
passwordAlert2.value = '비밀번호를 입력해주세요.';
|
||||||
|
isValid = false;
|
||||||
|
} else {
|
||||||
|
passwordAlert2.value = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 모든 입력값이 유효할 경우만 제출
|
||||||
|
if (!isValid) return;
|
||||||
|
|
||||||
// 댓글 제출
|
// 댓글 제출
|
||||||
emit('submitComment', {
|
emit('submitComment', {
|
||||||
comment: comment.value,
|
comment: comment.value,
|
||||||
|
nickname: isCheck.value ? nickname.value : '',
|
||||||
password: isCheck.value ? password.value : '',
|
password: isCheck.value ? password.value : '',
|
||||||
isCheck: isCheck.value,
|
isCheck: isCheck.value,
|
||||||
LOCBRDTYP: isCheck.value ? '300102' : null, // 익명일 경우 '300102' 설정
|
LOCBRDTYP: isCheck.value ? '300102' : null, // 익명일 경우 '300102' 설정
|
||||||
@ -148,15 +167,19 @@
|
|||||||
resetCommentForm();
|
resetCommentForm();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 비밀번호 경고 초기화
|
// 비밀번호 & 닉네임 경고 초기화
|
||||||
const pwd2AlertHandler = () => {
|
const pwd2AlertHandler = () => {
|
||||||
if (isCheck.value === false) passwordAlert2.value = '';
|
if (!isCheck.value) {
|
||||||
|
passwordAlert2.value = '';
|
||||||
|
nicknameAlert.value = '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 입력 필드 리셋 함수 추가
|
// 입력 필드 리셋 함수 추가
|
||||||
const resetCommentForm = () => {
|
const resetCommentForm = () => {
|
||||||
comment.value = '';
|
comment.value = '';
|
||||||
password.value = '';
|
password.value = '';
|
||||||
|
nickname.value = '';
|
||||||
isCheck.value = false;
|
isCheck.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,67 +1,72 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row gx-2 mb-4">
|
<div class="row gx-2 mb-4">
|
||||||
<div class="col-4">
|
<div class="col-3">
|
||||||
<div class="ratio ratio-1x1">
|
<div class="ratio ratio-1x1">
|
||||||
<!-- 오전 반차 버튼 -->
|
<!-- 오전 반차 버튼 -->
|
||||||
<button class="vac-btn vac-btn-warning rounded-circle d-flex align-items-center justify-content-center" :class="{ active: halfDayType === 'AM' }"
|
<button class="vac-btn vac-btn-warning rounded-circle d-flex align-items-center justify-content-center"
|
||||||
@click="toggleHalfDay('AM')">
|
:class="{ active: halfDayType === 'AM' }"
|
||||||
<i class="bi bi-sun"></i>
|
@click="toggleHalfDay('AM')">
|
||||||
</button>
|
<i class="bi bi-sun"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-3">
|
||||||
<div class="ratio ratio-1x1">
|
<div class="ratio ratio-1x1">
|
||||||
<!-- 오후 반차 버튼 -->
|
<!-- 오후 반차 버튼 -->
|
||||||
<button class="vac-btn vac-btn-info rounded-circle d-flex align-items-center justify-content-center" :class="{ active: halfDayType === 'PM' }"
|
<button class="vac-btn vac-btn-info rounded-circle d-flex align-items-center justify-content-center"
|
||||||
@click="toggleHalfDay('PM')">
|
:class="{ active: halfDayType === 'PM' }"
|
||||||
<i class="bi bi-moon"></i>
|
@click="toggleHalfDay('PM')">
|
||||||
</button>
|
<i class="bi bi-moon"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-3">
|
||||||
<div class="ratio ratio-1x1">
|
<div class="ratio ratio-1x1">
|
||||||
<button class="vac-btn-success rounded-circle d-flex align-items-center justify-content-center" @click="addVacationRequests"
|
<!-- 풀 연차 버튼 -->
|
||||||
:class="{ active: !isDisabled, disabled: isDisabled }">
|
<button class="vac-btn vac-btn-primary rounded-circle d-flex align-items-center justify-content-center"
|
||||||
✔
|
:class="{ active: halfDayType === 'FULL' }"
|
||||||
</button>
|
@click="toggleHalfDay('FULL')">
|
||||||
|
<i class="bi bi-calendar"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<div class="ratio ratio-1x1">
|
||||||
|
<!-- 저장 버튼 -->
|
||||||
|
<button class="vac-btn-success rounded-circle d-flex align-items-center justify-content-center"
|
||||||
|
@click="addVacationRequests"
|
||||||
|
:class="{ active: !isDisabled, disabled: isDisabled }">
|
||||||
|
✔
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineEmits, ref, defineProps, watch } from "vue";
|
import { defineEmits, ref, defineProps } from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isDisabled: Boolean,
|
isDisabled: Boolean
|
||||||
selectedDate: String // 날짜 선택 값을 props로 받음
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["toggleHalfDay", "addVacationRequests", "resetHalfDay"]);
|
const emit = defineEmits(["toggleHalfDay", "addVacationRequests", "resetHalfDay"]);
|
||||||
const halfDayType = ref(null);
|
const halfDayType = ref(null);
|
||||||
|
|
||||||
const toggleHalfDay = (type) => {
|
const toggleHalfDay = (type) => {
|
||||||
halfDayType.value = halfDayType.value === type ? null : type;
|
halfDayType.value = halfDayType.value === type ? null : type;
|
||||||
emit("toggleHalfDay", halfDayType.value);
|
emit("toggleHalfDay", halfDayType.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// `selectedDate`가 변경되면 반차 선택 초기화
|
// 날짜 클릭 후 버튼 상태 자동 초기화
|
||||||
watch(() => props.selectedDate, (newDate) => {
|
|
||||||
if (newDate) {
|
|
||||||
resetHalfDay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 날짜 선택 후 반차 버튼 상태 초기화
|
|
||||||
const resetHalfDay = () => {
|
const resetHalfDay = () => {
|
||||||
halfDayType.value = null;
|
halfDayType.value = null;
|
||||||
emit("resetHalfDay");
|
emit("resetHalfDay");
|
||||||
};
|
};
|
||||||
|
|
||||||
const addVacationRequests = () => {
|
const addVacationRequests = () => {
|
||||||
emit("addVacationRequests");
|
emit("addVacationRequests");
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ resetHalfDay });
|
defineExpose({ resetHalfDay });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -5,35 +5,33 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="btn"
|
class="btn"
|
||||||
:class="{
|
:class="{
|
||||||
'btn-outline-primary': selectedCategory !== 'all',
|
'btn-outline-primary': selectedCategory !== 'all',
|
||||||
'btn-primary': selectedCategory === 'all'
|
'btn-primary': selectedCategory === 'all'
|
||||||
}"
|
}"
|
||||||
@click="selectCategory('all')"
|
@click="selectCategory('all')"
|
||||||
>
|
>
|
||||||
All
|
All
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li v-for="category in lists" :key="category.value" class="mt-2 me-2">
|
<li v-for="category in lists" :key="category.value" class="mt-2 me-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn"
|
class="btn"
|
||||||
:class="{
|
:class="{
|
||||||
'btn-outline-primary': category.value !== selectedCategory,
|
'btn-outline-primary': category.value.toString() !== selectedCategory?.toString(),
|
||||||
'btn-primary': category.value === selectedCategory
|
'btn-primary': category.value.toString() === selectedCategory?.toString()
|
||||||
}"
|
}"
|
||||||
@click="selectCategory(category.value)"
|
@click="selectCategory(category.value)"
|
||||||
>
|
>
|
||||||
{{ category.label }}
|
{{ category.label }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, ref, watch } from 'vue';
|
import { defineProps, defineEmits, ref, watch } from 'vue';
|
||||||
|
|
||||||
// lists prop 정의
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
lists: {
|
lists: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -44,7 +42,7 @@ const props = defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
selectedCategory: {
|
selectedCategory: {
|
||||||
type: [String, Number],
|
type: [String,Number],
|
||||||
default: null,
|
default: null,
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
@ -63,4 +61,5 @@ watch(() => props.selectedCategory, (newVal) => {
|
|||||||
selectedCategory.value = newVal;
|
selectedCategory.value = newVal;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="isOpen" class="vac-modal-dialog" @click.self="closeModal">
|
<div v-if="isOpen" class="vac-modal-dialog" @click.self="closeModal">
|
||||||
<div class="vac-modal-content p-5 modal-scroll">
|
<div class="vac-modal-content p-5 modal-scroll">
|
||||||
<h5 class="vac-modal-title">📅 내 연차 내역</h5>
|
<h5 class="vac-modal-title">📅 내 연차 (누적 개수)</h5>
|
||||||
<button class="close-btn" @click="closeModal">✖</button>
|
<button class="close-btn" @click="closeModal">✖</button>
|
||||||
<!-- 연차 목록 -->
|
<!-- 연차 목록 -->
|
||||||
<div class="vac-modal-body" v-if="mergedVacations.length > 0">
|
<div class="vac-modal-body" v-if="mergedVacations.length > 0">
|
||||||
@ -11,9 +11,6 @@
|
|||||||
:key="vac._expandIndex"
|
:key="vac._expandIndex"
|
||||||
class="vacation-item"
|
class="vacation-item"
|
||||||
>
|
>
|
||||||
<span v-if="vac.category === 'used'" class="fw-bold text-dark me-2">
|
|
||||||
{{ usedVacationIndexMap[vac._expandIndex] }})
|
|
||||||
</span>
|
|
||||||
<span :class="vac.category === 'used' ? 'fw-bold text-danger me-2' : 'fw-bold text-primary me-2'">
|
<span :class="vac.category === 'used' ? 'fw-bold text-danger me-2' : 'fw-bold text-primary me-2'">
|
||||||
{{ vac.category === 'used' ? '-' : '+' }}
|
{{ vac.category === 'used' ? '-' : '+' }}
|
||||||
</span>
|
</span>
|
||||||
@ -22,6 +19,9 @@
|
|||||||
>
|
>
|
||||||
{{ formatDate(vac.date) }}
|
{{ formatDate(vac.date) }}
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="vac.category === 'used'" class="fw-bold text-dark ms-1">
|
||||||
|
( {{ usedVacationIndexMap[vac._expandIndex] }} )
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,16 +9,9 @@
|
|||||||
:formValue="item.WRDDICCAT"
|
:formValue="item.WRDDICCAT"
|
||||||
:titleValue="item.WRDDICTTL"
|
:titleValue="item.WRDDICTTL"
|
||||||
:contentValue="item.WRDDICCON"
|
:contentValue="item.WRDDICCON"
|
||||||
:isDisabled="userStore.user.role !== 'ROLE_ADMIN'"
|
:isDisabled="true"
|
||||||
/>
|
/>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<input
|
|
||||||
v-if="userStore.user.role == 'ROLE_ADMIN'"
|
|
||||||
type="checkbox"
|
|
||||||
class="form-check-input admin-chk"
|
|
||||||
:name="item.WRDDICSEQ"
|
|
||||||
@change="toggleCheck($event)"
|
|
||||||
>
|
|
||||||
<div class="d-flex align-ite-center">
|
<div class="d-flex align-ite-center">
|
||||||
<div class="w-100 d-flex align-items-center">
|
<div class="w-100 d-flex align-items-center">
|
||||||
<span class="btn btn-primary pe-none">{{ item.category }}</span>
|
<span class="btn btn-primary pe-none">{{ item.category }}</span>
|
||||||
@ -26,41 +19,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-5 dict-content-wrap" v-html="$common.contentToHtml(item.WRDDICCON)"></p>
|
<p class="mt-5 dict-content-wrap" v-html="$common.contentToHtml(item.WRDDICCON)"></p>
|
||||||
<div class="d-flex justify-content-between flex-wrap gap-2 mb-2">
|
<div class="d-flex align-items-start">
|
||||||
<div class="d-flex flex-wrap align-items-center mb-50">
|
<!-- 최초 작성자 -->
|
||||||
|
<div class="d-flex flex-wrap align-items-center me-4">
|
||||||
<div class="avatar avatar-sm me-2">
|
<div class="avatar avatar-sm me-2">
|
||||||
<img
|
<img
|
||||||
class="rounded-circle user-avatar"
|
class="rounded-circle user-avatar"
|
||||||
:src="getProfileImage(item.author.profileImage)"
|
:src="getProfileImage(item.author.profileImage)"
|
||||||
alt="최초 작성자"
|
alt="최초 작성자"
|
||||||
:style="{ borderColor: item.author.color}"
|
:style="{ borderColor: item.author.color }"
|
||||||
@error="setDefaultImage"
|
@error="setDefaultImage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.author.createdAt) }}</p>
|
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.author.createdAt) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div
|
<!-- 최근 작성자 (조건부) -->
|
||||||
v-if="item.author.createdAt !== item.lastEditor.updatedAt"
|
<div
|
||||||
class="d-flex justify-content-between flex-wrap gap-2 mb-2"
|
v-if="item.author.createdAt !== item.lastEditor.updatedAt"
|
||||||
>
|
class="d-flex flex-wrap align-items-center"
|
||||||
<div class="d-flex flex-wrap align-items-center mb-50">
|
>
|
||||||
<div class="avatar avatar-sm me-2">
|
<div class="avatar avatar-sm me-2">
|
||||||
<img
|
<img
|
||||||
class="rounded-circle user-avatar"
|
class="rounded-circle user-avatar"
|
||||||
:src="getProfileImage(item.lastEditor.profileImage)"
|
:src="getProfileImage(item.lastEditor.profileImage)"
|
||||||
alt="최근 작성자"
|
alt="최근 작성자"
|
||||||
:style="{ borderColor: item.lastEditor.color}"
|
:style="{ borderColor: item.lastEditor.color }"
|
||||||
@error="setDefaultImage"
|
@error="setDefaultImage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.lastEditor.updatedAt) }}</p>
|
<p class="mb-0 small fw-medium">{{ $common.dateFormatter(item.lastEditor.updatedAt) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-btn">
|
<div class="edit-btn">
|
||||||
@ -129,7 +124,7 @@ const editWord = (data) => {
|
|||||||
if (writeButton.value) {
|
if (writeButton.value) {
|
||||||
writeButton.value.resetButton();
|
writeButton.value.resetButton();
|
||||||
}
|
}
|
||||||
emit('refreshWordList');
|
emit('refreshWordList',data.category);
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ 서버 응답이 예상과 다릅니다:', res.data);
|
console.warn('⚠️ 서버 응답이 예상과 다릅니다:', res.data);
|
||||||
toastStore.onToast('용어 수정이 정상적으로 처리되지 않았습니다.', 'e');
|
toastStore.onToast('용어 수정이 정상적으로 처리되지 않았습니다.', 'e');
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="dataList.length > 0">
|
||||||
<FormSelect class="me-5"
|
<FormSelect
|
||||||
|
class="me-5"
|
||||||
name="cate"
|
name="cate"
|
||||||
title="카테고리"
|
title="카테고리"
|
||||||
:data="dataList"
|
:data="dataList"
|
||||||
@ -14,17 +15,19 @@
|
|||||||
<PlusBtn @click="toggleInput"/>
|
<PlusBtn @click="toggleInput"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="dataList.length === 0 || showInput">
|
||||||
|
<FormInput
|
||||||
|
class="me-5 parent-class "
|
||||||
|
ref="categoryInputRef"
|
||||||
|
title="새 카테고리"
|
||||||
|
:isLabel="dataList.length === 0 ?true : false"
|
||||||
|
name="새 카테고리"
|
||||||
|
@update:modelValue="addCategory = $event"
|
||||||
|
:is-cate-alert="addCategoryAlert"
|
||||||
|
@focusout="handleCategoryFocusout(addCategory)"
|
||||||
|
|
||||||
<div v-if="showInput">
|
/>
|
||||||
<FormInput class="me-5"
|
</div>
|
||||||
ref="categoryInputRef"
|
|
||||||
title="새 카테고리"
|
|
||||||
name="새 카테고리"
|
|
||||||
@update:modelValue="addCategory = $event"
|
|
||||||
:is-cate-alert="addCategoryAlert"
|
|
||||||
@focusout="handleCategoryFocusout(addCategory)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<FormInput class="me-5"
|
<FormInput class="me-5"
|
||||||
title="용어"
|
title="용어"
|
||||||
type="text"
|
type="text"
|
||||||
@ -217,4 +220,7 @@ const handleCategoryFocusout = (value) => {
|
|||||||
right: 0.7rem;
|
right: 0.7rem;
|
||||||
top: 1.2rem;
|
top: 1.2rem;
|
||||||
}
|
}
|
||||||
|
.parent-class {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import { useAuthStore } from '@s/useAuthStore';
|
import { useAuthStore } from '@s/useAuthStore';
|
||||||
import { useUserInfoStore } from '@s/useUserInfoStore';
|
import { useUserInfoStore } from '@s/useUserInfoStore';
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ import { useUserInfoStore } from '@s/useUserInfoStore';
|
|||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: "Home",
|
name: 'Home',
|
||||||
component: () => import('@v/MainView.vue'),
|
component: () => import('@v/MainView.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true }
|
||||||
},
|
},
|
||||||
@ -18,23 +18,23 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'BoardList',
|
name: 'BoardList',
|
||||||
component: () => import('@v/board/BoardList.vue')
|
component: () => import('@v/board/BoardList.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'write',
|
path: 'write',
|
||||||
component: () => import('@v/board/BoardWrite.vue')
|
component: () => import('@v/board/BoardWrite.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
name: 'BoardDetail',
|
name: 'BoardDetail',
|
||||||
component: () => import('@v/board/BoardView.vue')
|
component: () => import('@v/board/BoardView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'edit/:id',
|
path: 'edit/:id',
|
||||||
name: 'BoardEdit',
|
name: 'BoardEdit',
|
||||||
component: () => import('@v/board/BoardEdit.vue')
|
component: () => import('@v/board/BoardEdit.vue'),
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/wordDict',
|
path: '/wordDict',
|
||||||
@ -71,14 +71,13 @@ const routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: () => import('@v/voteboard/voteBoardList.vue')
|
component: () => import('@v/voteboard/voteBoardList.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'write',
|
path: 'write',
|
||||||
component: () => import('@v/voteboard/voteboardWrite.vue')
|
component: () => import('@v/voteboard/voteboardWrite.vue'),
|
||||||
},
|
},
|
||||||
|
],
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/projectlist',
|
path: '/projectlist',
|
||||||
@ -93,25 +92,37 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/authorization',
|
path: '/authorization',
|
||||||
component: () => import('@v/admin/TheAuthorization.vue'),
|
component: () => import('@v/admin/TheAuthorization.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{ path: "/error/400", name: "Error400", component: () => import('@v/error/Error400.vue'), meta: {layout: 'NoLayout'} },
|
|
||||||
{ path: "/error/500", name: "Error500", component: () => import('@v/error/Error500.vue'), meta: {layout: 'NoLayout'} },
|
|
||||||
{
|
{
|
||||||
path: "/:anything(.*)",
|
path: '/error/400',
|
||||||
name: "Error404", component: () => import('@v/error/Error404.vue'), meta: {layout: 'NoLayout'}
|
name: 'Error400',
|
||||||
|
component: () => import('@v/error/Error400.vue'),
|
||||||
|
meta: { layout: 'NoLayout' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/error/500',
|
||||||
|
name: 'Error500',
|
||||||
|
component: () => import('@v/error/Error500.vue'),
|
||||||
|
meta: { layout: 'NoLayout' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:anything(.*)',
|
||||||
|
name: 'Error404',
|
||||||
|
component: () => import('@v/error/Error404.vue'),
|
||||||
|
meta: { layout: 'NoLayout' },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: routes,
|
routes: routes,
|
||||||
})
|
});
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
await authStore.checkAuthStatus(); // 로그인 상태 확인
|
await authStore.checkAuthStatus(); // 로그인 상태 확인
|
||||||
const allowedUserId = 1; // 특정 ID (변경필요!!)
|
const allowedUserId = 1; // 특정 ID (변경필요!!)
|
||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
const userId = userStore.user?.id ?? null;
|
const userId = userStore.user?.id ?? null;
|
||||||
|
|
||||||
@ -120,9 +131,9 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
return next({ name: 'Login', query: { redirect: to.fullPath } });
|
return next({ name: 'Login', query: { redirect: to.fullPath } });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorization 페이지는 ID가 1이 아니면 접근 차단
|
// Authorization 페이지는 ID가 26이 아니면 접근 차단
|
||||||
if (to.path === "/authorization" && userId !== allowedUserId) {
|
if (to.path === '/authorization' && userId !== allowedUserId) {
|
||||||
return next("/");
|
return next('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 비로그인 사용자만 접근 가능한 페이지인데 로그인된 경우 → 홈으로 이동
|
// 비로그인 사용자만 접근 가능한 페이지인데 로그인된 경우 → 홈으로 이동
|
||||||
@ -148,7 +159,7 @@ axios.interceptors.response.use(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export default router
|
export default router;
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
<h5>{{ user.name }}</h5>
|
<h5>{{ user.name }}</h5>
|
||||||
</div>
|
</div>
|
||||||
<!-- 권한 토글 버튼 -->
|
<!-- 권한 토글 버튼 -->
|
||||||
<label class="switch">
|
<label class="switch me-0">
|
||||||
<input type="checkbox" :checked="user.isAdmin" @change="toggleAdmin(user)" />
|
<input type="checkbox" :checked="user.isAdmin" @change="toggleAdmin(user)" />
|
||||||
<span class="slider round"></span>
|
<span class="slider round"></span>
|
||||||
</label>
|
</label>
|
||||||
@ -32,7 +32,7 @@ const users = ref([]);
|
|||||||
const toastStore = useToastStore();
|
const toastStore = useToastStore();
|
||||||
const baseUrl = axios.defaults.baseURL.replace(/api\/$/, "");
|
const baseUrl = axios.defaults.baseURL.replace(/api\/$/, "");
|
||||||
const defaultProfile = "/img/icons/icon.png";
|
const defaultProfile = "/img/icons/icon.png";
|
||||||
|
const allowedUserId = 1; // 특정 ID (변경필요!!)
|
||||||
// 사용자 목록 가져오기
|
// 사용자 목록 가져오기
|
||||||
async function fetchUsers() {
|
async function fetchUsers() {
|
||||||
try {
|
try {
|
||||||
@ -43,14 +43,17 @@ async function fetchUsers() {
|
|||||||
throw new Error("올바른 데이터 형식이 아닙니다.");
|
throw new Error("올바른 데이터 형식이 아닙니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 데이터 매핑 (올바른 형식으로 변환)
|
// MEMBERSEQ가 1이 아닌 회원만 필터링하여 데이터 매핑
|
||||||
users.value = response.data.data.map(user => ({
|
users.value = response.data.data
|
||||||
id: user.MEMBERSEQ,
|
.filter(user => user.MEMBERSEQ !== allowedUserId) // MEMBERSEQ가 1이면 제외
|
||||||
name: user.MEMBERNAM,
|
.map(user => ({
|
||||||
photo: user.MEMBERPRF ? `${baseUrl}upload/img/profile/${user.MEMBERPRF}` : defaultProfile,
|
id: user.MEMBERSEQ,
|
||||||
color: user.MEMBERCOL,
|
name: user.MEMBERNAM,
|
||||||
isAdmin: user.MEMBERROL === 'ROLE_ADMIN',
|
photo: user.MEMBERPRF ? `${baseUrl}upload/img/profile/${user.MEMBERPRF}` : defaultProfile,
|
||||||
}));
|
color: user.MEMBERCOL,
|
||||||
|
isAdmin: user.MEMBERROL === 'ROLE_ADMIN',
|
||||||
|
}));
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toastStore.onToast('사용자 목록을 불러오지 못했습니다.', 'e');
|
toastStore.onToast('사용자 목록을 불러오지 못했습니다.', 'e');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -232,12 +232,12 @@
|
|||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 공지사항 데이터 로드
|
// 공지사항 데이터 로드
|
||||||
const fetchNoticePosts = async () => {
|
const fetchNoticePosts = async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get('board/notices', {
|
const { data } = await axios.get("board/notices", {
|
||||||
params: { searchKeyword: searchText.value },
|
params: { searchKeyword: searchText.value }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (data?.data) {
|
if (data?.data) {
|
||||||
noticeList.value = data.data.map(post => ({
|
noticeList.value = data.data.map(post => ({
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 비밀번호 입력창 (익명일 경우) -->
|
<!-- 비밀번호 입력창 (익명일 경우) -->
|
||||||
<div v-if="isPassword && unknown" class="mt-3 w-25 ms-auto">
|
<div v-if="isPassword && unknown" class="mt-3 w-px-200 ms-auto">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
@ -322,6 +322,7 @@
|
|||||||
likeCount: comment.likeCount || 0,
|
likeCount: comment.likeCount || 0,
|
||||||
dislikeCount: comment.dislikeCount || 0,
|
dislikeCount: comment.dislikeCount || 0,
|
||||||
profileImg: comment.profileImg || '',
|
profileImg: comment.profileImg || '',
|
||||||
|
nickname: comment.LOCCMTNIC,
|
||||||
likeClicked: comment.likeClicked || false,
|
likeClicked: comment.likeClicked || false,
|
||||||
dislikeClicked: comment.dislikeClicked || false,
|
dislikeClicked: comment.dislikeClicked || false,
|
||||||
createdAtRaw: comment.LOCCMTRDT, // 작성일
|
createdAtRaw: comment.LOCCMTRDT, // 작성일
|
||||||
@ -351,6 +352,7 @@
|
|||||||
parentId: reply.LOCCMTPNT, // 부모 댓글 ID
|
parentId: reply.LOCCMTPNT, // 부모 댓글 ID
|
||||||
content: reply.LOCCMTRPY || '내용 없음',
|
content: reply.LOCCMTRPY || '내용 없음',
|
||||||
createdAtRaw: reply.LOCCMTRDT,
|
createdAtRaw: reply.LOCCMTRDT,
|
||||||
|
nickname: reply.LOCCMTNIC,
|
||||||
// createdAt: formattedDate(reply.LOCCMTRDT),
|
// createdAt: formattedDate(reply.LOCCMTRDT),
|
||||||
//createdAtRaw: new Date(reply.LOCCMTUDT),
|
//createdAtRaw: new Date(reply.LOCCMTUDT),
|
||||||
createdAt: formattedDate(reply.LOCCMTUDT) + (reply.LOCCMTUDT !== reply.LOCCMTRDT ? ' (수정됨)' : ''),
|
createdAt: formattedDate(reply.LOCCMTUDT) + (reply.LOCCMTUDT !== reply.LOCCMTRDT ? ' (수정됨)' : ''),
|
||||||
@ -413,6 +415,7 @@
|
|||||||
LOCCMTRPY: comment,
|
LOCCMTRPY: comment,
|
||||||
LOCCMTPWD: isCheck ? password : '',
|
LOCCMTPWD: isCheck ? password : '',
|
||||||
LOCCMTPNT: 1,
|
LOCCMTPNT: 1,
|
||||||
|
LOCCMTNIC: data.isCheck ? data.nickname : null,
|
||||||
LOCBRDTYP: isCheck ? '300102' : null,
|
LOCBRDTYP: isCheck ? '300102' : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -432,6 +435,7 @@
|
|||||||
LOCCMTRPY: reply.comment,
|
LOCCMTRPY: reply.comment,
|
||||||
LOCCMTPWD: reply.password || null,
|
LOCCMTPWD: reply.password || null,
|
||||||
LOCCMTPNT: reply.parentId,
|
LOCCMTPNT: reply.parentId,
|
||||||
|
LOCCMTNIC: data.isCheck ? data.nickname : null,
|
||||||
LOCBRDTYP: reply.isCheck ? '300102' : null,
|
LOCBRDTYP: reply.isCheck ? '300102' : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -106,6 +106,7 @@ const isGrantModalOpen = ref(false);
|
|||||||
const fullCalendarRef = ref(null);
|
const fullCalendarRef = ref(null);
|
||||||
const calendarEvents = ref([]);
|
const calendarEvents = ref([]);
|
||||||
const selectedDates = ref(new Map());
|
const selectedDates = ref(new Map());
|
||||||
|
|
||||||
const halfDayType = ref(null);
|
const halfDayType = ref(null);
|
||||||
const vacationCodeMap = ref({});
|
const vacationCodeMap = ref({});
|
||||||
const holidayDates = ref(new Set());
|
const holidayDates = ref(new Set());
|
||||||
@ -118,7 +119,6 @@ const lastRemainingMonth = ref(String(new Date().getMonth() + 1).padStart(2, "0"
|
|||||||
// 데이트피커 인풋 ref
|
// 데이트피커 인풋 ref
|
||||||
const calendarDatepicker = ref(null);
|
const calendarDatepicker = ref(null);
|
||||||
let fpInstance = null;
|
let fpInstance = null;
|
||||||
|
|
||||||
/* 변경사항 여부 확인 */
|
/* 변경사항 여부 확인 */
|
||||||
const hasChanges = computed(() => {
|
const hasChanges = computed(() => {
|
||||||
return (
|
return (
|
||||||
@ -173,40 +173,53 @@ function handleDateClick(info) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMyVacation = myVacations.value.some(vac => {
|
// 기존 값 확인
|
||||||
const vacDate = vac.date ? vac.date.substring(0, 10) : "";
|
const currentValue = selectedDates.value.get(clickedDateStr);
|
||||||
return vacDate === clickedDateStr && !vac.receiverId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isMyVacation) {
|
const isMyVacation = myVacations.value.some(vac => vac.date.substring(0, 10) === clickedDateStr && !vac.receiverId);
|
||||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
|
||||||
selectedDates.value.delete(clickedDateStr);
|
// 이미 활성화된 날짜를 한 번 더 클릭하면 비활성화
|
||||||
|
if (currentValue && currentValue !== "delete") {
|
||||||
|
console.log("🛑 활성화된 날짜 비활성화:", clickedDateStr);
|
||||||
|
selectedDates.value.delete(clickedDateStr);
|
||||||
|
updateCalendarEvents();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 버튼을 누르지 않았을 때 - 삭제 모드
|
||||||
|
if (!halfDayType.value) {
|
||||||
|
if (isMyVacation) {
|
||||||
|
if (currentValue === "delete") {
|
||||||
|
selectedDates.value.delete(clickedDateStr);
|
||||||
|
} else {
|
||||||
|
selectedDates.value.set(clickedDateStr, "delete");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedDates.value.set(clickedDateStr, "delete");
|
selectedDates.value.set(clickedDateStr, "700103");
|
||||||
}
|
}
|
||||||
updateCalendarEvents();
|
updateCalendarEvents();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedDates.value.has(clickedDateStr)) {
|
// 버튼을 눌렀을 때 - 기존 휴가 삭제 후 새로운 값 추가
|
||||||
selectedDates.value.delete(clickedDateStr);
|
if (isMyVacation) {
|
||||||
updateCalendarEvents();
|
console.log("🗑 기존 휴가 삭제 후 새로운 상태 추가:", clickedDateStr);
|
||||||
return;
|
selectedDates.value.set(clickedDateStr, "delete");
|
||||||
}
|
}
|
||||||
const type = halfDayType.value
|
|
||||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
const type = halfDayType.value === "AM" ? "700101" :
|
||||||
: "700103";
|
halfDayType.value === "PM" ? "700102" :
|
||||||
|
"700103"; // 풀연차
|
||||||
|
|
||||||
selectedDates.value.set(clickedDateStr, type);
|
selectedDates.value.set(clickedDateStr, type);
|
||||||
|
|
||||||
if (halfDayType.value) {
|
// 버튼을 한 번 사용 후 자동 해제 (일회성)
|
||||||
halfDayType.value = null;
|
halfDayType.value = null;
|
||||||
}
|
|
||||||
updateCalendarEvents();
|
|
||||||
|
|
||||||
if (halfDayButtonsRef.value) {
|
if (halfDayButtonsRef.value) {
|
||||||
halfDayButtonsRef.value.resetHalfDay();
|
halfDayButtonsRef.value.resetHalfDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCalendarEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
function markClickableDates() {
|
function markClickableDates() {
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
<!-- 단어 목록 -->
|
<!-- 단어 목록 -->
|
||||||
<ul v-if="total > 0" class="ms-3 list-unstyled">
|
<ul v-if="total > 0" class="ms-3 list-unstyled">
|
||||||
<DictCard
|
<DictCard
|
||||||
|
class="DictCard"
|
||||||
v-for="item in wordList"
|
v-for="item in wordList"
|
||||||
:key="item.WRDDICSEQ"
|
:key="item.WRDDICSEQ"
|
||||||
:item="item"
|
:item="item"
|
||||||
@ -112,7 +113,8 @@
|
|||||||
writeStore.closeAll();
|
writeStore.closeAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshWordList = () => {
|
const refreshWordList = (category) => {
|
||||||
|
selectedCategory.value = category;
|
||||||
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,6 +195,7 @@
|
|||||||
sendWordRequest(category, wordData, newCodName);
|
sendWordRequest(category, wordData, newCodName);
|
||||||
};
|
};
|
||||||
const sendWordRequest = (category, wordData, data) => {
|
const sendWordRequest = (category, wordData, data) => {
|
||||||
|
console.log(category,'category')
|
||||||
const payload = {
|
const payload = {
|
||||||
WRDDICCAT: category,
|
WRDDICCAT: category,
|
||||||
WRDDICTTL: wordData.title,
|
WRDDICTTL: wordData.title,
|
||||||
@ -206,9 +209,9 @@
|
|||||||
if (writeButton.value) {
|
if (writeButton.value) {
|
||||||
writeButton.value.resetButton();
|
writeButton.value.resetButton();
|
||||||
}
|
}
|
||||||
getwordList();
|
selectedCategory.value = category;
|
||||||
|
getwordList(searchText.value, selectedAlphabet.value, selectedCategory.value);
|
||||||
getIndex();
|
getIndex();
|
||||||
selectedCategory.value = 'all';
|
|
||||||
if(res.data.data == '2'){
|
if(res.data.data == '2'){
|
||||||
const newCategory = { label: data, value: category };
|
const newCategory = { label: data, value: category };
|
||||||
cateList.value = [...cateList.value,newCategory];
|
cateList.value = [...cateList.value,newCategory];
|
||||||
@ -280,4 +283,9 @@
|
|||||||
margin-bottom: 0.5rem !important;
|
margin-bottom: 0.5rem !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.DictCard {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user