
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="flex align-top">
<div class="sch-form-wrap search">
<div class="input-group" style="display: flex;">
<select v-model="searchReqDTO.searchType" id="searchType" class="form-select">
<option value="all">전체</option>
<option value="cm">카드명</option>
<option value="nm">신청자</option>
</select>
<div class="sch-input">
<input type="text" class="form-control" v-model="searchReqDTO.searchText" @keyup.enter="searchCards">
<button class="ico-sch" @click="searchCards">
<SearchOutlined />
</button>
</div>
</div>
<div class="tbl-wrap table-scroll">
<table id="myTable" class="tbl data">
<!-- 동적으로 <th> 생성 -->
<thead>
<tr>
<th>카드목록 </th>
</tr>
</thead>
<!-- 동적으로 <td> 생성 -->
<tbody>
<tr v-if="selectedCards.length === 0">
<td style="text-align: center;">등록된 카드정보가 없습니다.</td>
</tr>
<tr v-for="(item, index) in selectedCards" :key="index" @click="selectCard(item)">
<td>
{{ item.cardNm }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="width: 100%;">
<div class=" sch-form-wrap title-wrap">
<h3><img :src="h3icon" alt="">카드 정보</h3>
<div class="buttons" style="margin: 0;">
<button type="submit" class="btn sm sm tertiary" @click="resetCard">신규</button>
<button type="reset" class="btn sm sm secondary" @click="insertByUpdateCard">
{{ buttonText }}
</button>
<button type="delete" class="btn sm sm btn-red" @click="deleteByUseAtCard">삭제</button>
</div>
</div>
<form class="row g-3 pt-3 needs-validation " @submit.prevent="handleSubmit" style="margin-bottom: 3rem;">
<div class="col-12 ">
<label for="cardNm" class="form-label">
<p>카드명
<p class="require"><img :src="require" alt=""></p>
</p>
</label>
<input type="text" class="form-control " id="reason" v-model="selectedCard.cardNm" />
</div>
<div class="col-12 ">
<label for="chargerId" class="form-label">
<p>담당자
<p class="require"><img :src="require" alt=""></p>
</p>
</label>
<input type="text" class="form-control " id="reason" v-model="selectedCard.chargerId" readonly />
<input type="button" class="form-control " value="검색" @click="showPopup = true" />
<!-- 팝업 -->
<HrPopup v-if="showPopup" @close="showPopup = false" @select="addApproval" />
</div>
<div class="col-12 chuljang ">
<label for="prvonsh" class="form-label">비고</label>
<input type="text" class="form-control textarea" id="reason" v-model="selectedCard.rm" />
</div>
<div class="col-12 border-x input-radio">
<label for="prvonsh" class="form-label">
<p>상태
<p class="require"><img :src="require" alt=""></p>
</p>
</label>
<select class="form-select" id="sttus" v-model="selectedCard.sttus">
<option value="N">정상</option>
<option value="R">재발급</option>
<option value="D">폐기</option>
</select>
</div>
</form>
<div class=" sch-form-wrap title-wrap">
<h3><img :src="h3icon" alt="">예약현황</h3>
</div>
<div class="tbl-wrap chk-area">
<table id="myTable" class="tbl data">
<thead>
<tr>
<th>부서</th>
<th>신청자</th>
<th>기간</th>
<th>상태</th>
</tr>
</thead>
<!-- 동적으로 <td> 생성 -->
<tbody>
<tr v-for="(item, index) in processedCards" :key="index">
<td>{{ item.deptId }}</td>
<td>{{ item.applcntId }}</td>
<td>{{ item.formattedPeriod }}</td>
<td :class="getStatusClass(item.status)">
{{ item.status }}
</td>
</tr>
</tbody>
</table>
</div>
<Pagination :search="searchReqHisDTO" @onChange="fnChangeCurrentPage" />
</div>
</div>
</div>
</div>
</template>
<script>
import GoogleCalendar from "../../../component/GoogleCalendar.vue"
import HrPopup from "../../../component/Popup/HrPopup.vue";
import { SearchOutlined, CloseCircleFilled } from '@ant-design/icons-vue';
import { saveAsSetCard, findAllAsSetCard, updateAsSetCard, findAllAsSetCardHis } from "../../../../resources/api/asset"; //카드 정보 API
import Pagination from "../../../component/Pagination.vue";
export default {
data() {
return {
showPopup: false,
approvals: [],
require: "/client/resources/img/require.png",
h3icon: "/client/resources/img/h3icon.png",
photoicon: "/client/resources/img/photo_icon.png",
img1: "/client/resources/img/img.png",
icon1: "/client/resources/img/icon.png",
dateicon: "/client/resources/img/date.png",
startbtn: "/client/resources/img/start.png",
stopbtn: "/client/resources/img/stop.png",
moreicon: "/client/resources/img/more.png",
checkCard: false,
cardId: null,
selectedCards: [],
selectedCardsHis: [],
searchReqDTO: {
searchType: "all",
searchText: null,
useAt: null,
useAll: true,
},
searchReqHisDTO: {
searchType: "all",
searchText: null,
useAt: null,
useAll: false,
listType:"all",
currentPage: 1,
recordSize: 4,
pageSize: null,
totalRecordCount: null,
totalPageCount: null,
startPage: null,
endPage: null,
limitStart: null,
existPrevPage: null,
existNextPage: null,
},
selectedCard: {
cardNm: null,
chargerId: null,
rm: null,
sttus: "N",
useAt: "Y"
},
}
},
components: {
SearchOutlined, CloseCircleFilled, HrPopup, Pagination
},
methods: {
// 페이지 이동
fnChangeCurrentPage(currentPage) {
this.searchReqHisDTO.currentPage = Number(currentPage);
console.log(this.searchReqHisDTO);
this.$nextTick(() => {
this.searchCardsHis();
});
},
//카드 정보 전체 조회
async searchCards() {
try {
const response = await findAllAsSetCard(this.searchReqDTO);
if (response.status === 200) {
this.selectedCards = response.data.data.card; // API 응답에서 카테고리 목록을 가져옴
}
} catch (error) {
console.error("검색 중 오류 발생:", error);
}
},
//카드 정보 사용 현황 전체 조회
async searchCardsHis() {
try {
const response = await findAllAsSetCardHis(this.searchReqHisDTO);
if (response.status === 200) {
this.selectedCardsHis = response.data.data.cardHis; // API 응답에서 카테고리 목록을 가져옴
this.searchReqHisDTO = response.data.data.search;
}
} catch (error) {
console.error("검색 중 오류 발생:", error);
}
},
// 카드 정보 등록 수정
async insertByUpdateCard() {
if (!this.validateCheck()) {
return; // 유효성 검사 실패 시 함수 종료
}
if (this.cardId == null && this.cardId == "") {
try {
const response = await saveAsSetCard(this.selectedCard);
if (response.status === 200) { // 성공 여부 체크
alert("등록되었습니다.");
window.location.reload();
}
} catch (error) {
// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "등록이 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchCards();
}
} else {
try {
const response = await updateAsSetCard(this.cardId, this.selectedCard);
if (response.status === 200) {
alert("수정되었습니다.");
window.location.reload();
}
} catch (error) {// HTTP 오류가 발생한 경우
const errorMessage = error.response?.data?.message || "수정이 실패하였습니다.";
alert(errorMessage); // 오류 메시지 표시
this.searchCards();
}
}
},
// 등록 유효성 체크 함수
validateCheck() {
// 1. 카드명 (cardNm) 필수 체크
if (!this.selectedCard.cardNm || this.selectedCard.cardNm.trim() === "") {
alert("카드명은 필수 입력 항목입니다.");
return false;
}
// 2. 담당자 (chargerId) 필수 체크
if (!this.selectedCard.chargerId || this.selectedCard.chargerId.trim() === "") {
alert("담당자는 필수 입력 항목입니다.");
return false;
}
return true; // 모든 유효성 검사 통과
},
// 삭제 버튼을 눌렀을 시 삭제
async deleteByUseAtCard() {
try {
this.selectedCard.useAt = "N";
const response = await updateAsSetCard(this.cardId, this.selectedCard);
if (response.status === 200) {
alert("삭제되었습니다.");
window.location.reload();
}
} catch (error) {
alert("삭제가 실패하였습니다.");
}
},
//선택한 카드의 정보를 오른쪽에 표시
selectCard(item) {
this.checkCard = true;
this.cardId = item.cardId;
this.selectedCard = {
cardNm: item.cardNm,
chargerId: item.chargerId,
rm: item.rm,
sttus: item.sttus,
useAt: item.useAt
};
},
// 신규 버튼을 눌렀을 시
resetCard() {
this.checkCard = false;
this.selectedCard = {
cardNm: null,
chargerId: null,
rm: null,
sttus: "N",
useAt: "Y"
};
},
addApproval(selectedUser) {
this.approvals.push({
name: selectedUser.name
});
this.selectedCard.chargerId = selectedUser.name; // 입력창에 표시
this.showPopup = false;
},
getStatusClass(status) {
if (status === '예약') return 'status-pending';
if (status === '사용 중') return 'status-pending';
if (status === '반납') return 'status-approved';
return ''; // 기본값
},
},
watch: {
},
computed: {
buttonText() {
return this.checkCard ? "수정" : "등록";
},
// selectedCardsHis 데이터를 가공하여 화면에 표시할 데이터를 만듭니다.
processedCards() {
const now = new Date(); // 현재 시간
// 날짜와 시간 문자열을 조합하여 Date 객체를 생성하는 헬퍼 함수
const createDateTime = (dateStr, hourStr, minStr) => {
// dateStr이 "YYYY-MM-DD HH:MM:SS.ms" 형태라고 가정하고 "YYYY-MM-DD" 부분만 추출
const datePart = dateStr.split(' ')[0];
const year = parseInt(datePart.substring(0, 4), 10);
const month = parseInt(datePart.substring(5, 7), 10) - 1; // 월은 0부터 시작 (0=1월)
const day = parseInt(datePart.substring(8, 10), 10);
const hour = parseInt(hourStr, 10);
const minute = parseInt(minStr, 10);
return new Date(year, month, day, hour, minute, 0);
};
// Date 객체를 'YYYY-MM-DD HH:MI' 형식으로 포맷하는 헬퍼 함수
const formatDateTime = (dateObj) => {
const year = dateObj.getFullYear();
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
const day = String(dateObj.getDate()).padStart(2, '0');
const hour = String(dateObj.getHours()).padStart(2, '0');
const minute = String(dateObj.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`;
};
return this.selectedCardsHis.map(item => {
const startDateTime = createDateTime(item.bgnde, item.beginHour, item.beginMnt);
const endDateTime = createDateTime(item.endde, item.endHour, item.endMnt);
let status = '';
if (now >= startDateTime && now <= endDateTime) {
status = '사용 중'; // 현재 시간이 기간 안에 포함
} else if (now < startDateTime) {
status = '예약'; // 현재 시간이 시작일시보다 이전
} else { // now > endDateTime
status = '반납'; // 현재 시간이 종료일시보다 이후
}
return {
...item, // 원본 아이템의 모든 속성 유지
formattedPeriod: `${formatDateTime(startDateTime)} ~ ${formatDateTime(endDateTime)}`, // 포맷된 기간 문자열
status: status // 계산된 상태
};
});
}
},
mounted() {
console.log('main mounted');
this.searchCards();
this.searchCardsHis();
}
}
</script>
<style scoped>
tr {
cursor: pointer;
}
</style>