
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h2 class="card-title">휴가 현황</h2>
<div class="form-group">
<div class="form-conts">
<div class="form-conts datepicker-conts">
<div class="datepicker-input">
<input type="date" class="form-control datepicker cal" v-model="searchParams.bgnde" style="max-width: 200px;" @change="handleSearchChange" />
<mark>~</mark>
<input type="date" class="form-control datepicker cal" v-model="searchParams.endde" style="max-width: 200px;" @change="handleSearchChange" />
</div>
</div>
</div>
</div>
<div class="boxs">
<div class="color-boxs">
<div class="box" @click="handleFilterChange()">
<h3>전체</h3>
<div>
<span>{{ totalDays }}</span>
<small>({{ carriedOverDays }})</small>
</div>
</div>
<div class="box" @click="handleFilterChange(usedLeaveItem.code)">
<h3>사용</h3>
<div>{{ usedLeaveItem.userSpendCnt }}</div>
</div>
<div class="box">
<h3>미사용</h3>
<div>{{ remainingDays }}</div>
</div>
<div class="box" v-for="(item, idx) of otherItems" :key="idx" @click="handleFilterChange(item.code)">
<h3>{{ item.codeNm }}</h3>
<div>{{ item.userSpendCnt }}</div>
</div>
</div>
</div>
<div class="tbl-wrap">
<table id="myTable" class="tbl data">
<colgroup>
<col style="width: 15%;">
<col style="width: 40%;">
<col style="width: 30%;">
<col style="width: 15%;">
</colgroup>
<thead>
<tr>
<th>구분</th>
<th>기간</th>
<th>신청일</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<template v-if="hasVacations">
<tr v-for="(item, idx) in vacationList" :key="`${item.vcatnId}-${idx}`" @click="handleItemClick(item.vcatnId)">
<td>{{ item.vcatnKndNm }}</td>
<td>{{ $formattedDates(item) }}</td>
<td>{{ item.rgsde }}</td>
<td>{{ item.confmAtNm }}</td>
</tr>
</template>
<tr v-else>
<td colspan="4">해당 기간 내 등록된 휴가가 없습니다.</td>
</tr>
</tbody>
</table>
</div>
<Pagination :search="searchParams" @onChange="handlePageChange" />
</div>
</div>
</div>
</template>
<script>
// API
import { findVcatnSummaryProc, findVcatnsProc } from '../../../../resources/api/vcatn';
export default {
name: 'VacationList',
data() {
return {
searchParams: {
bgnde: null,
endde: null,
vcatnKnd: null,
currentUserId: this.$store.state.userInfo.userId,
},
vacationList: [],
totalDays: 0,
carriedOverDays: 0,
usedLeaveItem: {},
remainingDays: 0,
otherItems: [],
};
},
computed: {
// 휴가 목록 유무
hasVacations() {
return this.vacationList.length > 0;
},
},
async mounted() {
await this.fetchVacationSummary(); // 휴가 현황 조회
await this.fetchVacationList(); // 휴가 목록 조회
},
methods: {
// 휴가 현황 조회
async fetchVacationSummary() {
try {
const response = await findVcatnSummaryProc(this.searchParams);
const result = response.data.data;
this.searchParams.bgnde = result.userYrycVO.bgnde;
this.searchParams.endde = new Date().toISOString().split('T')[0];
this.totalDays = result.totalDays;
this.carriedOverDays = result.carriedOverDays;
this.usedLeaveItem = result.usedLeaveItem;
this.remainingDays = result.remainingDays;
this.otherItems = result.otherItems;
} catch (error) {
this.handleError(error);
}
},
// 휴가 목록 조회
async fetchVacationList() {
try {
delete this.searchParams.vcatnKndList;
const response = await findVcatnsProc(this.searchParams);
const result = response.data.data;
this.vacationList = result.lists;
this.searchParams = result.search;
} catch (error) {
this.handleError(error);
}
},
// 검색 핸들러 (검색 시 현재 페이지를 1로 변경 후 조회)
async handleSearchChange() {
if (!this.searchParams.bgnde || !this.searchParams.endde) {
return;
}
const startDate = new Date(this.searchParams.bgnde);
const endDate = new Date(this.searchParams.endde);
if (endDate < startDate) {
alert('종료일은 시작일보다 이전일 수 없습니다.');
this.searchParams.endde = this.searchParams.bgnde;
return;
}
await this.handlePageChange(1);
},
// 필터 변경 핸들러
async handleFilterChange(vcatnKnd) {
this.searchParams.vcatnKnd = vcatnKnd;
await this.handlePageChange(1);
},
// 페이지 변경 핸들러
async handlePageChange(currentPage) {
this.searchParams.currentPage = Number(currentPage);
await this.$nextTick();
await this.fetchVacationList();
},
// 상세 페이지 이동 핸들러
handleItemClick(id) {
this.handleNavigation('view', id);
},
// 페이지 이동 핸들러
handleNavigation(type, id) {
const routeMap = {
'list': { name: 'VcatnListPage' },
'view': { name: 'VcatnViewPage', query: { id } },
'insert': { name: 'VcatnInsertPage', query: this.$isEmpty(id) ? {} : { id } },
'reapply': { name: 'VcatnInsertPage', query: { id, type: 'reapply' } },
};
const route = routeMap[type];
if (route) {
this.$router.push(route);
} else {
alert("올바르지 않은 경로입니다.");
this.$router.push(routeMap['list']);
}
},
// 에러 핸들러
handleError(error) {
const message = error.response?.data?.message || "에러가 발생했습니다.";
alert(message);
},
},
};
</script>
<style scoped>
tr {
cursor: pointer;
}
/* 미사용만 커서 미적용 (필터 조회 안됨) */
.box:not(:nth-child(3)) {
cursor: pointer;
}
.box:nth-child(2) {
color: #1D75E1 !important;
}
.box:nth-child(3) {
color: #E92727 !important;
}
.box:nth-child(4) {
color: #3C97AB !important;
}
.box:nth-child(5) {
color: #A36CD4 !important;
}
.box:nth-child(6) {
color: #F7941C !important;
}
</style>