사원리스트 모달추가
This commit is contained in:
parent
fbc578c307
commit
5a4b770fa1
@ -1,49 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="isOpen" class="modal-dialog" @click.self="closeModal">
|
<div v-if="isOpen" class="modal-dialog" @click.self="closeModal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<h5 class="modal-title">📅 {{ targetUser.name }}님의 연차 부여</h5>
|
<h5 class="modal-title">To. {{ targetUser.MEMBERNAM }} 🎁</h5>
|
||||||
<button class="close-btn" @click="closeModal">✖</button>
|
<button class="close-btn" @click="closeModal">✖</button>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>해당 직원에게 부여할 연차 개수를 선택하세요. (최대 2개)</p>
|
<p>해당 직원에게 부여할 연차 개수를 선택하세요. (남은 개수: {{ availableQuota }}개)</p>
|
||||||
|
|
||||||
<div class="vacation-item">
|
<div class="vacation-control">
|
||||||
<button @click="decreaseCount" :disabled="grantCount <= 0">-</button>
|
<button @click="decreaseCount" :disabled="grantCount <= 0" class="count-btn">-</button>
|
||||||
<span>{{ grantCount }}</span>
|
<span class="grant-count">{{ grantCount }}</span>
|
||||||
<button @click="increaseCount" :disabled="grantCount >= maxQuota">+</button>
|
<button @click="increaseCount" :disabled="grantCount >= availableQuota" class="count-btn">+</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="">현재 보유 연차: <strong>{{ remainingQuota }}</strong></p>
|
<button class="gift-btn" @click="saveVacationGrant" :disabled="grantCount === 0">
|
||||||
</div>
|
<i class="bx bx-gift"></i> <!-- 선물상자 아이콘 -->
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<button class="save-btn" @click="saveVacationGrant" :disabled="grantCount === 0">
|
|
||||||
✅ 저장
|
|
||||||
</button>
|
</button>
|
||||||
<button class="cancel-btn" @click="closeModal">취소</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch, onMounted } from "vue";
|
||||||
import axios from "@api";
|
import axios from "@api";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isOpen: Boolean, // 모달 상태
|
isOpen: Boolean, // 모달 상태
|
||||||
targetUser: Object, // 선택한 사용자 정보
|
targetUser: Object, // 선택한 사용자 정보
|
||||||
remainingQuota: Number, // 현재 부여된 연차 개수
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["close", "updateVacation"]);
|
const emit = defineEmits(["close", "updateVacation"]);
|
||||||
|
|
||||||
const grantCount = ref(0);
|
const grantCount = ref(0);
|
||||||
const maxQuota = 2; // 최대 부여 가능 개수
|
const maxQuota = 2; // 1년에 보낼 수 있는 최대 개수
|
||||||
|
const sentCount = ref(0); // 현재까지 보낸 개수
|
||||||
|
const availableQuota = ref(2); // 남은 개수
|
||||||
|
|
||||||
|
// ✅ 해당 사용자에게 이미 보낸 연차 개수 조회
|
||||||
|
const fetchSentVacationCount = async () => {
|
||||||
|
try {
|
||||||
|
const payload = { receiverId: props.targetUser.MEMBERSEQ };
|
||||||
|
|
||||||
|
const response = await axios.get(`vacation/sent`,{ params: payload });
|
||||||
|
console.log(response.data.data[0].count)
|
||||||
|
sentCount.value = response.data.data[0].count || 0; // 이미 보낸 개수
|
||||||
|
availableQuota.value = Math.max(maxQuota - sentCount.value, 0); // 남은 개수 (0 이하 방지)
|
||||||
|
console.log(`✅ 보낸 개수: ${sentCount.value}, 남은 개수: ${availableQuota.value}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("🚨 연차 전송 기록 조회 실패:", error);
|
||||||
|
availableQuota.value = maxQuota;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// ✅ 연차 개수 증가
|
// ✅ 연차 개수 증가
|
||||||
const increaseCount = () => {
|
const increaseCount = () => {
|
||||||
if (grantCount.value < maxQuota) {
|
if (grantCount.value < availableQuota.value) {
|
||||||
grantCount.value++;
|
grantCount.value++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -55,18 +66,24 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ✅ 연차 부여 저장 요청
|
// ✅ 연차 부여 저장 요청 (saveVacations API 호출)
|
||||||
const saveVacationGrant = async () => {
|
const saveVacationGrant = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post("vacation/grant", {
|
const payload = [
|
||||||
senderId: props.targetUser.senderId, // 로그인한 사용자 ID
|
{
|
||||||
receiverId: props.targetUser.MEMBERSEQ, // 대상 사용자 ID
|
date: new Date().toISOString().split("T")[0], // 오늘 날짜
|
||||||
type: "700103", // 연차 (반차 없음)
|
type: "700103", // 연차 코드
|
||||||
count: grantCount.value, // 선택한 개수
|
senderId: props.targetUser.senderId, // 보내는 사람 ID
|
||||||
});
|
receiverId: props.targetUser.MEMBERSEQ, // 받는 사람 ID
|
||||||
|
count: grantCount.value, // 부여 개수
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const response = await axios.post("vacation/save", payload);
|
||||||
|
|
||||||
if (response.data && response.data.status === "OK") {
|
if (response.data && response.data.status === "OK") {
|
||||||
alert("✅ 연차가 부여되었습니다.");
|
alert("✅ 연차가 부여되었습니다.");
|
||||||
|
await fetchSentVacationCount(); // ✅ 보낸 개수 업데이트
|
||||||
emit("updateVacation"); // ✅ 연차 정보 갱신 요청
|
emit("updateVacation"); // ✅ 연차 정보 갱신 요청
|
||||||
closeModal();
|
closeModal();
|
||||||
} else {
|
} else {
|
||||||
@ -83,13 +100,115 @@
|
|||||||
emit("close");
|
emit("close");
|
||||||
};
|
};
|
||||||
|
|
||||||
// ✅ 모달이 열릴 때 초기 값 설정
|
// ✅ 모달이 열릴 때 초기 값 설정 및 보낸 개수 조회
|
||||||
watch(() => props.isOpen, (newVal) => {
|
watch(
|
||||||
if (newVal) {
|
() => props.isOpen,
|
||||||
|
async (newVal) => {
|
||||||
|
if (newVal && props.targetUser && props.targetUser.MEMBERSEQ) {
|
||||||
|
console.log("🟢 모달이 열렸습니다. 데이터를 로드합니다.");
|
||||||
grantCount.value = 0; // 초기화
|
grantCount.value = 0; // 초기화
|
||||||
|
await fetchSentVacationCount(); // 보낸 개수 불러오기
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// ✅ targetUser가 변경될 때도 fetchSentVacationCount 호출
|
||||||
|
watch(
|
||||||
|
() => props.targetUser,
|
||||||
|
async (newUser) => {
|
||||||
|
if (newUser && newUser.MEMBERSEQ) {
|
||||||
|
console.log(`🔄 새로운 대상(${newUser.name})이 선택되었습니다.`);
|
||||||
|
await fetchSentVacationCount();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// ✅ 컴포넌트가 마운트될 때도 보낸 개수 불러오기
|
||||||
|
onMounted(async () => {
|
||||||
|
if (props.isOpen && props.targetUser && props.targetUser.MEMBERSEQ) {
|
||||||
|
await fetchSentVacationCount();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
|
/* 모달 본문 */
|
||||||
|
.modal-content {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 400px;
|
||||||
|
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 닫기 버튼 */
|
||||||
|
.close-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 연차 개수 조정 버튼 */
|
||||||
|
.vacation-control {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count-btn {
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: none;
|
||||||
|
background: #007bff;
|
||||||
|
color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count-btn:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 개수 표시 */
|
||||||
|
.grant-count {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 선물 아이콘 버튼 */
|
||||||
|
.gift-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 20px;
|
||||||
|
background: #28a745;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-top: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift-btn:hover {
|
||||||
|
background: #218838;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift-btn:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card-body d-flex justify-content-center">
|
<div class="card-body d-flex justify-content-center">
|
||||||
<ul class="list-unstyled d-flex align-items-center gap-7 mb-0 mt-2">
|
<ul class="list-unstyled d-flex align-items-center gap-3 mb-0 mt-2">
|
||||||
<li
|
<li
|
||||||
v-for="(user, index) in sortedUserList"
|
v-for="(user, index) in sortedUserList"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|||||||
@ -83,7 +83,6 @@ const fetchRemainingVacation = async () => {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get("vacation/remaining");
|
const response = await axios.get("vacation/remaining");
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log("✅ 남은 연차 데이터:", response.data);
|
|
||||||
remainingVacationData.value = response.data.data.reduce((acc, vacation) => {
|
remainingVacationData.value = response.data.data.reduce((acc, vacation) => {
|
||||||
acc[vacation.employeeId] = vacation.remainingQuota;
|
acc[vacation.employeeId] = vacation.remainingQuota;
|
||||||
return acc;
|
return acc;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user