localhost-front/src/components/modal/VacationModal.vue

123 lines
3.7 KiB
Vue

<template>
<div v-if="isOpen" class="vac-modal-dialog" @click.self="closeModal">
<div class="vac-modal-content p-5 modal-scroll">
<h5 class="vac-modal-title">📅 내 연차 상세 내역</h5>
<button class="close-btn" @click="closeModal">✖</button>
<!-- 연차 목록 -->
<div class="vac-modal-body" v-if="mergedVacations.length > 0">
<ol class="list-group-numbered px-0 mt-4">
<li
v-for="(vac, index) in mergedVacations"
:key="vac._expandIndex"
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'">
{{ vac.category === 'used' ? '-' : '+' }}
</span>
<span
:style="{ color: userColors[vac.senderId || vac.receiverId] || '#000' }"
>
{{ formatDate(vac.date) }}
</span>
</li>
</ol>
</div>
<!-- 연차 데이터 없음 -->
<p v-else class="text-sm-center mt-10 text-gray vac-modal-title">
🚫 연차 내역이 없습니다.
</p>
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits, computed } from "vue";
import { formatDate } from '@/common/formattedDate.js';
const props = defineProps({
isOpen: Boolean,
myVacations: {
type: Array,
default: () => [],
},
receivedVacations: {
type: Array,
default: () => [],
},
userColors: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(["close"]);
// 사용한 휴가(선물,연차사용)
let globalCounter = 0;
const usedVacations = computed(() => {
const result = [];
props.myVacations.forEach((v) => {
const count = v.used_quota || 1;
for (let i = 0; i < count; i++) {
result.push({
...v,
category: "used",
code: v.LOCVACTYP,
_expandIndex: globalCounter++,
});
}
});
return result;
});
// 받은 휴가
const receivedVacations = computed(() =>
props.receivedVacations.map((v) => ({
...v,
category: "received",
}))
);
// 필터링
const sortedUsedVacationsAsc = computed(() => {
return [...usedVacations.value].sort((a, b) => {
return new Date(a.date) - new Date(b.date) || (a._expandIndex - b._expandIndex);
});
});
// 누적 인덱스 계산 type === "700103"이면 +1 그 외이면 +0.5
const usedVacationIndexMap = computed(() => {
let cumulative = 0;
const map = {};
sortedUsedVacationsAsc.value.forEach((item) => {
const increment = item.type === "700103" ? 1 : 0.5;
cumulative += increment;
map[item._expandIndex] = cumulative;
});
return map;
});
// 최종 표시할 merged 리스트 (Used + Received) 날짜 내림차순 정렬 (최신 → 과거)
const mergedVacations = computed(() => {
const all = [...usedVacations.value, ...receivedVacations.value];
// 날짜 내림차순 + 확장 인덱스 내림차순
all.sort((a, b) => {
const dateDiff = new Date(b.date) - new Date(a.date);
if (dateDiff !== 0) return dateDiff;
return b._expandIndex - a._expandIndex;
});
return all;
});
// 모달 닫기
const closeModal = () => {
emit("close");
};
</script>
<style scoped>
</style>