
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="content">
<div class="sub-title-area mb-30">
<h2>영상 기록물</h2>
<div class="breadcrumb-list">
<ul>
<li>
<img :src="homeicon" alt="Home Icon">
<p>기록물</p>
</li>
<li><img :src="righticon" alt=""></li>
<li>영상 기록물</li>
</ul>
</div>
</div>
<!-- 검색 폼 컴포넌트 사용 -->
<SearchFormComponent :initialData="searchReqDTO" pageType="video" @search="handleSearch" @reset="handleReset" />
<div class="search-result">
<div class="tabs">
<div class="flex-sp-bw mb-20 align-center">
<div class="resultext ">
<img :src="resulticon" alt="">
<p>총 <b>{{ searchReqDTO.totalRecordCount }}개</b>의 영상 기록물이 검색되었습니다. </p>
</div>
<div class="flex">
<div v-if="searchResult.length > 0">
<button type="button" @click="fnDownload">다운로드</button>
</div>
<ul class="tab-box mb-20">
<li v-for="(tab, idx) in tabs" :key="idx" class="tab-title" :class="{ active: selectedTabId === tab.id }"
@click="selectTab(tab.id)">
<img :src="selectedTabId === tab.id ? tab.activeImage : tab.inactiveImage" :alt="tab.title"
class="tab-icon" />
<p><b>{{ tab.title }}</b></p>
</li>
</ul>
<div class="select-box">
<select v-model="searchReqDTO.recordSize" @change="fnChnageReqDTO">
<option :value="24">24개</option>
<option :value="36">36개</option>
<option :value="100">100개</option>
</select>
</div>
</div>
</div>
<div class="tab-content">
<div v-if="searchResult.length > 0">
<CardStyleComponent v-if="selectedTabId === 'CARD'" :name="'V'" :list="searchResult" />
<ListStyleComponent v-if="selectedTabId === 'LIST'" :name="'V'" :list="searchResult" />
</div>
<div v-else class="no-results">
<img :src="nosearch" alt="">
<p>검색 결과가 없습니다.</p>
<p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> 검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> 일반적으로 많이 사용하는 검색어로 다시 검색해
주시기 바랍니다.</p>
</div>
</div>
</div>
<div class="btn-group flex-end mt-40"><button type="button" class="register" @click="fnMoveTo('edit')">등록</button>
</div>
<DefaultPagination class="mt-40" :search="searchReqDTO" @onChange="fnChangeCurrentPage" />
</div>
</div>
<div v-if="loading" class="loading-overlay">
<div class="loading-spinner"></div>
<div>
<p>검색 중입니다</p>
<p>잠시만 기다려주세요</p>
</div>
</div>
</template>
<script>
// COMPONENT
import SearchFormComponent from '@/views/component/SearchFormComponent.vue';
import CardStyleComponent from '@/views/component/listLayout/CardStyleComponent.vue';
import ListStyleComponent from '@/views/component/listLayout/ListStyleComponent.vue';
import DefaultPagination from '@/views/component/DefaultPagination.vue';
// API
import { findDcrysProc } from "@/resources/api/dcry";
import { excelDownloadProc } from '@/resources/api/file';
import uploadProgressStore from '@/resources/js/uploadProgressStore';
export default {
components: {
SearchFormComponent,
DefaultPagination,
CardStyleComponent,
ListStyleComponent,
},
data() {
return {
// ICON
resulticon: "client/resources/images/icon/r-check.png",
nosearch: "client/resources/images/no_search.png",
homeicon: 'client/resources/images/icon/home.png',
righticon: 'client/resources/images/icon/right.png',
// 검색용 객체 초기값
searchDefault: {
useSj: true,
useCn: true,
useAdres: true,
searchText: null,
startYear: null,
endYear: null,
searchTy: "V", // 영상 기록물 고정
searchCtgries: [],
order: "rgsde",
// 페이지네이션
currentPage: 1, // 현재 페이지
recordSize: 24, // 한 페이지에 표시할 데이터 개수
},
// URL 파라미터로부터 가져온 초기 검색 조건
urlParamsDefault: null,
searchReqDTO: {}, // 실제 검색에 사용되는 객체
searchResult: [], // 검색결과
// 목록 레이아웃
selectedTabId: null,
tabs: [
{
id: "CARD",
title: "카드형",
activeImage: "client/resources/images/list_icon01_on.png", // Active tab image
inactiveImage: "client/resources/images/list_icon01_off.png",
},
{
id: "LIST",
title: "리스트형",
activeImage: "client/resources/images/list_icon02_on.png", // Active tab image
inactiveImage: "client/resources/images/list_icon02_off.png",
},
],
isInitialLoad: true, // 초기 로드 여부
loading: false, // 로딩 상태 추가
};
},
created() {
// 초기화
this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault));
this.selectedTabId = this.tabs[0].id; // 기본 탭 설정
// URL 파라미터에서 검색 조건 가져오기
this.queryParamsToSearch();
},
mounted() {
this.fnSearch(); // 초기 검색 실행
},
methods: {
// URL 파라미터로부터 검색 조건 설정
queryParamsToSearch() {
let query = this.$route.query;
if (!this.$isEmpty(query)) {
// 기본 검색 조건 복사
let urlParams = JSON.parse(JSON.stringify(this.searchDefault));
const typeConverters = {
useSj: val => val === 'true',
useCn: val => val === 'true',
useAdres: val => val === 'true',
searchCtgries: val => Array.isArray(val) ? val : (val ? val.split(',') : [])
};
// URL 파라미터 값 적용
Object.entries(query).forEach(([key, value]) => {
if (key in urlParams) {
urlParams[key] = key in typeConverters ? typeConverters[key](value) : value;
}
});
// URL 파라미터 기반 초기값 저장
this.urlParamsDefault = urlParams;
// 현재 검색 조건에 적용
this.searchReqDTO = JSON.parse(JSON.stringify(urlParams));
}
},
// 페이지 이동
fnChangeCurrentPage(currentPage) {
this.searchReqDTO.currentPage = Number(currentPage);
this.$nextTick(() => {
this.fnSearch();
});
},
// 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드
handleSearch(formData) {
// searchTy는 항상 "V"로 유지
formData.searchTy = "V";
// 페이지 초기화
formData.currentPage = 1;
this.searchReqDTO = formData;
this.fnSearch();
},
// 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드
handleReset() {
// URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용
if (this.urlParamsDefault) {
this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault));
} else {
this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault));
}
this.searchResult = []; // 검색결과 초기화
this.fnSearch(); // 초기화 후 검색 실행
},
// 검색 조건이 변경된 경우
fnChnageReqDTO() {
this.searchReqDTO.currentPage = 1;
this.$nextTick(() => {
this.fnSearch();
});
},
// 통합검색
async fnSearch() {
this.loading = true; // 로딩 시작
try {
const params = JSON.parse(JSON.stringify(this.searchReqDTO));
// 카테고리 목록 처리
if (this.searchReqDTO.searchCtgries && this.searchReqDTO.searchCtgries.length > 0) {
params.searchCtgries = this.searchReqDTO.searchCtgries.join(',');
} else {
delete params.searchCtgries;
}
// API 호출
const response = await findDcrysProc(params);
this.searchResult = response.data.data.dcrys;
this.searchReqDTO = response.data.data.search;
window.scrollTo({ top: 0, behavior: 'smooth' });
} catch (error) {
this.searchResult = []; // 검색결과 초기화
if (error.response) {
alert(error.response.data.message);
}
console.error(error.message);
} finally {
this.loading = false; // 로딩 종료
}
},
selectTab(tabId) {
this.selectedTabId = tabId;
},
// 페이지 이동
fnMoveTo(type, id) {
const routes = {
'list': { name: 'VideoHistorySearch' },
'view': { name: 'VideoHistoryDetail', query: { id } },
'edit': { name: 'VideoHistoryInsert', query: this.$isEmpty(id) ? {} : { id } },
};
if (routes[type]) {
this.$router.push(routes[type]);
} else {
alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
this.$router.push(routes['list']);
}
},
// 영상상 기록물 엑셀 다운로드
async fnDownload() {
try {
const params = JSON.parse(JSON.stringify(this.searchReqDTO));
if (this.searchReqDTO.searchCtgries && this.searchReqDTO.searchCtgries.length > 0) {
params.searchCtgries = this.searchReqDTO.searchCtgries.join(',');
} else {
delete params.searchCtgries;
}
let today = new Date().toISOString().substring(2, 10);
today = today.replace(/[^0-9]/g, "");
const fileName = `[영상 기록물]기록물_${today}.xlsx`;
params.useVideo = true;
const response = await excelDownloadProc(params, fileName);
const url = window.URL.createObjectURL(
new Blob([response.data], {
type: response.headers["content-type"],
})
);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
} catch (error) {
console.error("엑셀 다운로드 에러:", error);
if (error.response) {
// Blob 응답이 아닐 경우 에러 메시지 처리가 다를 수 있음.
// 여기서는 간단히 HTTP 상태 코드만 표시.
alert(`엑셀 다운로드 중 에러 발생: ${error.response.status} ${error.response.statusText}`);
} else {
alert("엑셀 다운로드 중 네트워크 에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
} finally {
uploadProgressStore.closeModal();
}
},
},
};
</script>