
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="card">
<div class="card-body">
<h2 class="card-title">휴가 현황</h2>
<div class="form-card">
<h1>휴가신청서</h1>
<SanctnViewList v-if="vacationInfo.sanctnList.length > 0" :sanctns="vacationInfo.sanctnList" />
<div class="tbl-wrap">
<table class="tbl data">
<tbody>
<tr>
<th>유형</th>
<td>{{ vacationInfo.vcatnKndNm }}</td>
<th>신청자</th>
<td>{{ vacationInfo.userNm }}</td>
</tr>
<tr>
<th>부서</th>
<td>{{ vacationInfo.deptNm }}</td>
<th>직급</th>
<td>{{ vacationInfo.clsfNm }}</td>
</tr>
<tr>
<th>기간</th>
<td colspan="3">{{ $formattedDates(vacationInfo) }}</td>
</tr>
<tr>
<th>세부사항</th>
<td colspan="3">
<ViewerComponent :content="vacationInfo.detailCn" />
</td>
</tr>
<tr>
<th>신청일</th>
<td colspan="3">{{ vacationInfo.rgsde }}</td>
</tr>
<tr>
<th>상태</th>
<td colspan="3">{{ vacationInfo.confmAtNm }}</td>
</tr>
<tr v-if="approvalStatus === 'rejected'">
<th>반려사유</th>
<td colspan="3">{{ getRejectionReason(vacationInfo.sanctnList) }}</td>
</tr>
<!-- 붉은 색 등 하여간 눈에 띄게 표기해야 함!! -->
<tr>
<td colspan="4">금년도 연차 소진으로 내년도 연차를 선 사용하는 휴가 신청건입니다.</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="buttons">
<template v-if="isConsultationApprover">
<button type="button" class="btn sm primary" @click="handleApproval('A')">승인</button>
<button type="button" class="btn sm btn-red" @click="showConsultationPopup = true">반려</button>
</template>
<template v-else-if="isApplicant">
<template v-if="approvalStatus === 'waiting'">
<button type="button" class="btn sm btn-red" @click="handleDelete">신청취소</button>
<button type="button" class="btn sm secondary" @click="handleNavigation('insert', pageId)">수정</button>
</template>
<template v-if="approvalStatus === 'rejected'">
<button type="button" class="btn sm secondary" @click="handleNavigation('reapply', pageId)">재신청</button>
</template>
</template>
<button type="button" class="btn sm tertiary" @click="handleNavigation('list')">목록</button>
</div>
</div>
</div>
<ReturnPopup v-if="showConsultationPopup" @close="showConsultationPopup = false" @confirm="handleRejection" />
</template>
<script>
import ReturnPopup from '../../../component/Popup/ReturnPopup.vue';
import ViewerComponent from '../../../component/editor/ViewerComponent.vue';
import SanctnViewList from '../../../component/Sanctn/SanctnViewList.vue';
// API
import { findVcatnProc, deleteVcatnProc } from '../../../../resources/api/vcatn';
import { updateConfmAtProc } from '../../../../resources/api/sanctns';
export default {
name: 'VacationView',
components: {
ReturnPopup,
ViewerComponent,
SanctnViewList,
},
data() {
return {
pageId: null,
pageMode: null,
showConsultationPopup: false,
vacationInfo: {
userId: null,
userNm: null,
vcatnKndNm: null,
deptNm: null,
clsfNm: null,
bgnde: null,
beginHour: null,
beginMnt: null,
endde: null,
endHour: null,
endMnt: null,
detailCn: null,
confmAtNm: null,
rgsde: null,
sanctnList: []
},
returnResn: null,
};
},
computed: {
// 결재 상태
approvalStatus() {
const sanctnList = this.vacationInfo.sanctnList;
if (sanctnList.length === 0) return 'none';
// 하나라도 반려된 경우 > 반려
if (sanctnList.some(item => item.confmAt === 'R')) {
return 'rejected';
}
// 전부 승인된 경우 > 승인
if (sanctnList.every(item => item.confmAt === 'A')) {
return 'approved';
}
// 그 외 > 대기
return 'waiting';
},
// 작성자 여부
isApplicant() {
return this.vacationInfo.userId === this.$store.state.userInfo.userId;
},
// 결재자 여부
isConsultationApprover() {
const sanctnList = this.vacationInfo.sanctnList;
const mySanctn = sanctnList.find(
item => item.confmerId == this.$store.state.userInfo.userId
);
return mySanctn && mySanctn.confmAt === 'W' && this.pageMode === 'sanctns';
},
},
async created() {
this.pageId = this.$route.query.id;
this.pageMode = this.$route.query.type;
if (this.$isEmpty(this.pageId)) {
alert("게시물이 존재하지 않습니다.");
this.handleNavigation('list');
}
},
mounted() {
this.fetchData(); // 휴가 정보 조회
},
methods: {
// 휴가 정보 조회
async fetchData() {
try {
const response = await findVcatnProc(this.pageId);
const result = response.data.data;
this.vacationInfo = result;
} catch (error) {
this.handleError(error);
this.handleNavigation('list');
}
},
// 결재 승인/반려 처리
async handleApproval(value) {
try {
const sanctnList = this.vacationInfo.sanctnList;
const sanctn = sanctnList.find(item => item.confmerId == this.$store.state.userInfo.userId);
if (!sanctn) {
alert('결재 권한이 없습니다.');
return;
}
const data = {
sanctnOrdr: sanctn.sanctnOrdr,
sanctnIem: sanctn.sanctnIem,
sanctnMbyId: this.pageId,
confmAt: value,
returnResn: this.returnResn,
};
await updateConfmAtProc(sanctn.sanctnId, data);
alert("승인했습니다.");
this.fetchData();
} catch (error) {
this.handleError(error);
}
},
// 반려 결재 핸들러
async handleRejection(reason) {
this.returnResn = reason;
await this.handleApproval('R');
this.showConsultationPopup = false;
},
// 휴가 취소 (완전 삭제)
async handleDelete() {
const isCheck = confirm("휴가 신청을 취소하시겠습니까?");
if (!isCheck) return;
try {
await deleteVcatnProc(this.pageId);
alert("휴가 신청이 취소되었습니다.");
this.handleNavigation('list');
} catch (error) {
this.handleError(error);
}
},
// 페이지 이동 핸들러
handleNavigation(type, id) {
const routeMap = {
'list': { name: this.pageMode === 'sanctns' ? 'PendingApprovalListPage' : '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);
},
// 반려 사유 유틸리티
getRejectionReason(sanctnList) {
const rejectedItem = sanctnList.find(item => item.confmAt === 'R');
return rejectedItem?.returnResn || '-';
},
}
};
</script>