
+++ client/views/component/SearchFormComponent.vue
... | ... | @@ -0,0 +1,313 @@ |
1 | +<template> | |
2 | + <div class="search-form form"> | |
3 | + <dl> | |
4 | + <!-- 통합검색에서만 보이는 기록유형 선택 --> | |
5 | + <dd class="mb-15" v-if="pageType === 'all'"> | |
6 | + <p>기록유형</p> | |
7 | + <ul> | |
8 | + <li> | |
9 | + <input type="checkbox" id="allRecord" v-model="isChkAllRecord" @change="fnChkAllOptions('record')" /> | |
10 | + <label for="allRecord">전체</label> | |
11 | + </li> | |
12 | + <li> | |
13 | + <input type="checkbox" id="photoRecord" v-model="formData.usePhoto" @change="fnChkOption('record')" /> | |
14 | + <label for="photoRecord">사진</label> | |
15 | + </li> | |
16 | + <li> | |
17 | + <input type="checkbox" id="videoRecord" v-model="formData.useVideo" @change="fnChkOption('record')" /> | |
18 | + <label for="videoRecord">영상</label> | |
19 | + </li> | |
20 | + <li> | |
21 | + <input type="checkbox" id="mediaVideo" v-model="formData.useMedia" @change="fnChkOption('record')" /> | |
22 | + <label for="mediaVideo">미디어영상</label> | |
23 | + </li> | |
24 | + <li> | |
25 | + <input type="checkbox" id="newsData" v-model="formData.useNews" @change="fnChkOption('record')" /> | |
26 | + <label for="newsData">보도자료</label> | |
27 | + </li> | |
28 | + </ul> | |
29 | + </dd> | |
30 | + <dd class="mb-15"> | |
31 | + <p>검색범위</p> | |
32 | + <ul> | |
33 | + <li> | |
34 | + <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions('scope')" /> | |
35 | + <label for="allScope">전체</label> | |
36 | + </li> | |
37 | + <li> | |
38 | + <input type="checkbox" id="searchSj" v-model="formData.useSj" @change="fnChkOption('scope')" /> | |
39 | + <label for="searchSj">제목</label> | |
40 | + </li> | |
41 | + <li> | |
42 | + <input type="checkbox" id="searchCn" v-model="formData.useCn" @change="fnChkOption('scope')" /> | |
43 | + <label for="searchCn">내용</label> | |
44 | + </li> | |
45 | + <li v-if="pageType !== 'media' && pageType !== 'bodo'"> | |
46 | + <input type="checkbox" id="searchAdres" v-model="formData.useAdres" @change="fnChkOption('scope')" /> | |
47 | + <label for="searchAdres">주소</label> | |
48 | + </li> | |
49 | + </ul> | |
50 | + </dd> | |
51 | + <dd class="mb-15"> | |
52 | + <p>검색어</p> | |
53 | + <div class="wfull"><input type="text" v-model="formData.searchText" v-on:keyup.enter="fnSearch"></div> | |
54 | + </dd> | |
55 | + <dd class="mb-15"> | |
56 | + <p>생산연도</p> | |
57 | + <input type="text" v-model="formData.startYear" pattern="[0-9]{4}" maxlength="4" @input="onlyNumberInput('startYear')"> | |
58 | + <p class="mark">~</p> | |
59 | + <input type="text" v-model="formData.endYear" pattern="[0-9]{4}" maxlength="4" @input="onlyNumberInput('endYear')"> | |
60 | + </dd> | |
61 | + <dd class="mb-20 category-dd" v-if="categoryList.length > 0"> | |
62 | + <p>카테고리</p> | |
63 | + <ul> | |
64 | + <li v-for="(category, idx) of categoryList" :key="idx"> | |
65 | + <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="formData.searchCtgries" /> | |
66 | + <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> | |
67 | + </li> | |
68 | + </ul> | |
69 | + </dd> | |
70 | + <dd class="mb-15"> | |
71 | + <p>정렬</p> | |
72 | + <ul> | |
73 | + <li v-for="(order, idx) of orders" :key="idx"> | |
74 | + <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="formData.order" /> | |
75 | + <label :for="order.key">{{ order.value }}</label> | |
76 | + </li> | |
77 | + </ul> | |
78 | + </dd> | |
79 | + <div class="btn-group"> | |
80 | + <button type="button" class="reset" @click="fnReset"> | |
81 | + <img :src="reseticon" alt=""> | |
82 | + <p>초기화</p> | |
83 | + </button> | |
84 | + <button type="button" class="search" @click="fnSearch"> | |
85 | + <img :src="searchicon" alt=""> | |
86 | + <p>검색</p> | |
87 | + </button> | |
88 | + </div> | |
89 | + </dl> | |
90 | + </div> | |
91 | +</template> | |
92 | +<script> | |
93 | +// API | |
94 | +import { findAllByNullProc } from "@/resources/api/category"; // 카테고리 목록 검색 | |
95 | + | |
96 | +export default { | |
97 | + name: "SearchFormComponent", | |
98 | + props: { | |
99 | + // 부모 컴포넌트에서 전달받을 데이터 | |
100 | + initialData: { | |
101 | + type: Object, | |
102 | + default: () => ({ | |
103 | + usePhoto: true, | |
104 | + useVideo: true, | |
105 | + useMedia: true, | |
106 | + useNews: true, | |
107 | + useSj: true, | |
108 | + useCn: true, | |
109 | + useAdres: true, | |
110 | + searchText: null, | |
111 | + startYear: null, | |
112 | + endYear: null, | |
113 | + searchCtgries: [], | |
114 | + order: "rgsde", | |
115 | + // 페이지네이션 관련 속성 | |
116 | + currentPage: 1, | |
117 | + recordSize: 24, | |
118 | + }), | |
119 | + }, | |
120 | + // 페이지 타입 (통합검색: 'all', 사진: 'pic', 영상: 'video', 미디어: 'media', 보도자료: 'bodo') | |
121 | + pageType: { | |
122 | + type: String, | |
123 | + default: 'all' | |
124 | + } | |
125 | + }, | |
126 | + data() { | |
127 | + return { | |
128 | + // 아이콘 | |
129 | + searchicon: 'client/resources/images/icon/search.png', | |
130 | + reseticon: 'client/resources/images/icon/reset.png', | |
131 | + | |
132 | + isChkAllRecord: true, // 기록유형 전체 체크 여부 | |
133 | + isChkAllScope: true, // 검색범위 전체 체크 여부 | |
134 | + | |
135 | + // 검색 폼 데이터 | |
136 | + formData: {}, | |
137 | + | |
138 | + // 카테고리 목록 | |
139 | + categoryList: [], | |
140 | + | |
141 | + // 정렬 목록 | |
142 | + orders: [ | |
143 | + { key: "rgsde", value: "최신" }, | |
144 | + { key: "rdcnt", value: "인기" }, | |
145 | + ], | |
146 | + }; | |
147 | + }, | |
148 | + created() { | |
149 | + // 초기 데이터 설정 | |
150 | + this.initFormData(); | |
151 | + | |
152 | + // 카테고리 목록 조회 | |
153 | + this.fnFindCategorys(); | |
154 | + }, | |
155 | + watch: { | |
156 | + // initialData가 변경되면 formData를 업데이트 | |
157 | + initialData: { | |
158 | + handler() { | |
159 | + this.initFormData(); | |
160 | + }, | |
161 | + deep: true | |
162 | + } | |
163 | + }, | |
164 | + methods: { | |
165 | + // 폼 데이터 초기화 | |
166 | + initFormData() { | |
167 | + // 초기 데이터 복사 | |
168 | + this.formData = JSON.parse(JSON.stringify(this.initialData)); | |
169 | + | |
170 | + // 페이지 타입에 따라 검색 타입 설정 | |
171 | + if (this.pageType !== 'all') { | |
172 | + // 페이지 타입에 맞는 searchTy 설정 | |
173 | + switch (this.pageType) { | |
174 | + case 'pic': | |
175 | + this.formData.searchTy = "P"; | |
176 | + break; | |
177 | + case 'video': | |
178 | + this.formData.searchTy = "V"; | |
179 | + break; | |
180 | + case 'media': | |
181 | + this.formData.searchTy = "M"; | |
182 | + // 미디어 영상에서는 주소 검색 비활성화 | |
183 | + this.formData.useAdres = false; | |
184 | + break; | |
185 | + case 'bodo': | |
186 | + this.formData.searchTy = "N"; | |
187 | + // 보도자료에서는 주소 검색 비활성화 | |
188 | + this.formData.useAdres = false; | |
189 | + break; | |
190 | + } | |
191 | + } | |
192 | + | |
193 | + // 전체 체크박스 상태 동기화 | |
194 | + this.isChkAllRecord = this.formData.usePhoto && this.formData.useVideo && this.formData.useMedia && this.formData.useNews; | |
195 | + | |
196 | + // 검색범위 전체 체크박스 상태 계산 | |
197 | + if (this.pageType === 'media' || this.pageType === 'bodo') { | |
198 | + // 미디어 영상과 보도자료는 제목과 내용만 검색 가능 | |
199 | + this.isChkAllScope = this.formData.useSj && this.formData.useCn; | |
200 | + } else { | |
201 | + // 기타 타입은 주소 포함 세 가지 모두 검색 가능 | |
202 | + this.isChkAllScope = this.formData.useSj && this.formData.useCn && this.formData.useAdres; | |
203 | + } | |
204 | + }, | |
205 | + | |
206 | + // 카테고리 목록 조회 | |
207 | + async fnFindCategorys() { | |
208 | + try { | |
209 | + const response = await findAllByNullProc(); | |
210 | + if (response.data && response.data.data && response.data.data.ctgry) { | |
211 | + this.categoryList = response.data.data.ctgry; | |
212 | + console.log("카테고리 조회 성공:", this.categoryList); | |
213 | + } else { | |
214 | + console.error("카테고리 데이터 형식이 잘못되었습니다:", response.data); | |
215 | + this.categoryList = []; | |
216 | + } | |
217 | + } catch (error) { | |
218 | + this.categoryList = []; // 카테고리 목록 초기화 | |
219 | + console.error("카테고리 조회 실패:", error); | |
220 | + | |
221 | + if (error.response) { | |
222 | + alert(error.response.data.message); | |
223 | + } | |
224 | + console.error(error.message); | |
225 | + } | |
226 | + }, | |
227 | + | |
228 | + // 초기화 버튼 클릭 | |
229 | + fnReset() { | |
230 | + if (confirm('검색 조건을 초기화하시겠습니까?')) { | |
231 | + this.initFormData(); | |
232 | + | |
233 | + // 부모 컴포넌트에 이벤트 발생 | |
234 | + this.$emit('reset'); | |
235 | + } | |
236 | + }, | |
237 | + | |
238 | + // 검색 실행 | |
239 | + fnSearch() { | |
240 | + // 유효성 검사 (통합검색일 경우 검색 유형 체크) | |
241 | + if (this.pageType === 'all' && !this.formData.usePhoto && !this.formData.useVideo && !this.formData.useMedia && !this.formData.useNews) { | |
242 | + alert('검색 유형은 최소 한 개 이상 선택해주세요.'); | |
243 | + return; | |
244 | + } | |
245 | + | |
246 | + // 검색 범위 유효성 검사 | |
247 | + if (this.pageType === 'media' || this.pageType === 'bodo') { | |
248 | + // 미디어 영상과 보도자료는 제목, 내용만 체크 | |
249 | + if (!this.formData.useSj && !this.formData.useCn) { | |
250 | + alert('검색 범위는 최소 한 개 이상 선택해주세요.'); | |
251 | + return; | |
252 | + } | |
253 | + } else { | |
254 | + // 다른 타입은 제목, 내용, 주소 체크 | |
255 | + if (!this.formData.useSj && !this.formData.useCn && !this.formData.useAdres) { | |
256 | + alert('검색 범위는 최소 한 개 이상 선택해주세요.'); | |
257 | + return; | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + // 부모 컴포넌트에 이벤트 발생 (데이터 전달) | |
262 | + this.$emit('search', JSON.parse(JSON.stringify(this.formData))); | |
263 | + }, | |
264 | + | |
265 | + // 전체 선택/해제 | |
266 | + fnChkAllOptions(type) { | |
267 | + switch (type) { | |
268 | + case 'record': | |
269 | + this.formData.usePhoto = this.isChkAllRecord; | |
270 | + this.formData.useVideo = this.isChkAllRecord; | |
271 | + this.formData.useMedia = this.isChkAllRecord; | |
272 | + this.formData.useNews = this.isChkAllRecord; | |
273 | + break; | |
274 | + case 'scope': | |
275 | + this.formData.useSj = this.isChkAllScope; | |
276 | + this.formData.useCn = this.isChkAllScope; | |
277 | + // media 또는 bodo 타입이 아닌 경우에만 주소 검색 옵션 설정 | |
278 | + if (this.pageType !== 'media' && this.pageType !== 'bodo') { | |
279 | + this.formData.useAdres = this.isChkAllScope; | |
280 | + } | |
281 | + break; | |
282 | + } | |
283 | + }, | |
284 | + | |
285 | + // 개별 체크박스 선택시 전체 체크박스 상태 업데이트 | |
286 | + fnChkOption(type) { | |
287 | + switch (type) { | |
288 | + case 'record': | |
289 | + this.isChkAllRecord = this.formData.usePhoto && this.formData.useVideo && this.formData.useMedia && this.formData.useNews; | |
290 | + break; | |
291 | + case 'scope': | |
292 | + if (this.pageType === 'media' || this.pageType === 'bodo') { | |
293 | + // 미디어 영상과 보도자료는 제목과 내용만 체크 | |
294 | + this.isChkAllScope = this.formData.useSj && this.formData.useCn; | |
295 | + } else { | |
296 | + // 다른 타입은 주소 포함 체크 | |
297 | + this.isChkAllScope = this.formData.useSj && this.formData.useCn && this.formData.useAdres; | |
298 | + } | |
299 | + break; | |
300 | + } | |
301 | + }, | |
302 | + | |
303 | + // 생산연도 입력 제한 | |
304 | + onlyNumberInput(type) { | |
305 | + if (type === 'startYear') { | |
306 | + this.formData.startYear = this.formData.startYear.replace(/[^0-9]/g, ''); | |
307 | + } else if (type === 'endYear') { | |
308 | + this.formData.endYear = this.formData.endYear.replace(/[^0-9]/g, ''); | |
309 | + } | |
310 | + } | |
311 | + }, | |
312 | +}; | |
313 | +</script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/component/listLayout/CardViewList.vue
+++ client/views/component/listLayout/CardViewList.vue
... | ... | @@ -11,7 +11,9 @@ |
11 | 11 |
<CardStyleComponent :name="name" :list="list" /> |
12 | 12 |
</div> |
13 | 13 |
<div v-else class="no-results"> |
14 |
- <p>등록된 게시물이 없습니다.</p> |
|
14 |
+ <img :src="nosearch" alt=""> |
|
15 |
+ <p>검색 결과가 없습니다.</p> |
|
16 |
+ <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> 검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> 일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
15 | 17 |
</div> |
16 | 18 |
</div> |
17 | 19 |
</template> |
... | ... | @@ -46,6 +48,8 @@ |
46 | 48 |
|
47 | 49 |
data() { |
48 | 50 |
return { |
51 |
+ // ICON |
|
52 |
+ nosearch: "client/resources/images/no_search.png", |
|
49 | 53 |
}; |
50 | 54 |
}, |
51 | 55 |
|
--- client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
... | ... | @@ -68,35 +68,35 @@ |
68 | 68 |
<div v-if="requestDTO.files.length === 0 && multipartFiles.length === 0">선택된 파일이 없습니다.</div> |
69 | 69 |
<!-- 기존 등록된 파일 목록 --> |
70 | 70 |
<div v-for="(file, idx) of requestDTO.files" :key="idx" class="mb-5"> |
71 |
- <div class="flex align-center" style="gap: 10px;"> |
|
71 |
+ <div class="flex align-center" style="gap: 10px;"> |
|
72 | 72 |
<input type="radio" name="thumbAt" :id="'oldFile_' + file.fileOrdr" v-model="selectedThumb" :value="file.fileNm"> |
73 | 73 |
<label :for="'oldFile_' + file.fileOrdr"> |
74 |
- <p>대표사진 지정</p></label> |
|
75 |
- </div > |
|
76 |
- <div class="flex-sp-bw file-wrap"> |
|
77 |
- <div class="file-name"> |
|
78 |
- <img src="/client/resources/images/icon/imgicon.png" alt="fileicon"> |
|
79 |
- <p>{{ file.fileNm }}</p> |
|
80 |
- </div> |
|
81 |
- <button type="button" class="cancel" @click="fnDelFile('old', file.fileOrdr)"><b>✕</b></button> |
|
74 |
+ <p>대표사진 지정</p> |
|
75 |
+ </label> |
|
76 |
+ </div> |
|
77 |
+ <div class="flex-sp-bw file-wrap"> |
|
78 |
+ <div class="file-name"> |
|
79 |
+ <img src="/client/resources/images/icon/imgicon.png" alt="fileicon"> |
|
80 |
+ <p>{{ file.fileNm }}</p> |
|
82 | 81 |
</div> |
83 |
- |
|
82 |
+ <button type="button" class="cancel" @click="fnDelFile('old', file.fileOrdr)"><b>✕</b></button> |
|
83 |
+ </div> |
|
84 | 84 |
</div> |
85 | 85 |
<!-- 새로 추가된 파일 목록 --> |
86 | 86 |
<div v-for="(file, idx) of multipartFiles" :key="idx" class="mb-5"> |
87 | 87 |
<div class="flex align-center" style="gap: 10px;"> |
88 | 88 |
<input type="radio" name="thumbAt" :id="'newFile_' + idx" v-model="selectedThumb" :value="file.name"> |
89 | 89 |
<label :for="'newFile_' + idx"> |
90 |
- <p>대표사진 지정</p></label> |
|
91 |
- </div > |
|
92 |
- <div class="flex-sp-bw file-wrap"> |
|
93 |
- <div class="file-name"> |
|
94 |
- <img src="/client/resources/images/icon/imgicon.png" alt="fileicon"> |
|
95 |
- <p>{{ file.name }}</p> |
|
96 |
- </div> |
|
97 |
- <button type="button" class="cancel" @click="fnDelFile('new', idx)"><b>✕</b></button> |
|
90 |
+ <p>대표사진 지정</p> |
|
91 |
+ </label> |
|
92 |
+ </div> |
|
93 |
+ <div class="flex-sp-bw file-wrap"> |
|
94 |
+ <div class="file-name"> |
|
95 |
+ <img src="/client/resources/images/icon/imgicon.png" alt="fileicon"> |
|
96 |
+ <p>{{ file.name }}</p> |
|
98 | 97 |
</div> |
99 |
- |
|
98 |
+ <button type="button" class="cancel" @click="fnDelFile('new', idx)"><b>✕</b></button> |
|
99 |
+ </div> |
|
100 | 100 |
</div> |
101 | 101 |
</div> |
102 | 102 |
</li> |
... | ... | @@ -317,10 +317,33 @@ |
317 | 317 |
} else if (type === 'old') { |
318 | 318 |
this.requestDTO.files = this.requestDTO.files.filter(item => item.fileOrdr !== separator); |
319 | 319 |
} |
320 |
+ this.validateThumbnail(); |
|
321 |
+ }, |
|
320 | 322 |
|
321 |
- // 썸네일 변경 |
|
322 |
- if (this.requestDTO.files.length < 1 && this.multipartFiles.length > 0) { |
|
323 |
- this.selectedThumb = this.multipartFiles[0].name; |
|
323 |
+ // 썸네일 유효성 검증 및 설정 |
|
324 |
+ validateThumbnail() { |
|
325 |
+ // 1. 현재 selectedThumb가 기존 파일(requestDTO.files)에 존재하는지 확인 |
|
326 |
+ if (this.requestDTO.files && this.requestDTO.files.length > 0) { |
|
327 |
+ const existsInCurrentFiles = this.requestDTO.files.some(file => file.fileNm === this.selectedThumb); |
|
328 |
+ |
|
329 |
+ // 기존 파일에 없다면 첫 번째 기존 파일을 썸네일로 설정 |
|
330 |
+ if (!existsInCurrentFiles) { |
|
331 |
+ this.selectedThumb = this.requestDTO.files[0].fileNm; |
|
332 |
+ } |
|
333 |
+ return; |
|
334 |
+ } |
|
335 |
+ |
|
336 |
+ // 2. 여기까지 왔다면 기존 파일이 없는 상태 |
|
337 |
+ // 새 파일(multipartFiles)이 있는지 확인 |
|
338 |
+ if (this.multipartFiles && this.multipartFiles.length > 0) { |
|
339 |
+ const existsInNewFiles = this.multipartFiles.some(file => file.name === this.selectedThumb); |
|
340 |
+ |
|
341 |
+ // 새 파일에 없다면 첫 번째 새 파일을 썸네일로 설정 |
|
342 |
+ if (!existsInNewFiles) { |
|
343 |
+ this.selectedThumb = this.multipartFiles[0].name; |
|
344 |
+ } |
|
345 |
+ } else { |
|
346 |
+ this.selectedThumb = null; |
|
324 | 347 |
} |
325 | 348 |
}, |
326 | 349 |
|
... | ... | @@ -341,6 +364,10 @@ |
341 | 364 |
return; |
342 | 365 |
} |
343 | 366 |
} |
367 |
+ if (this.$isEmpty(this.selectedThumb)) { |
|
368 |
+ alert("썸네일로 사용할 이미지를 선택해주세요."); |
|
369 |
+ return; |
|
370 |
+ } |
|
344 | 371 |
|
345 | 372 |
let count = this.multipartFiles.length |
346 | 373 |
if (!this.$isEmpty(this.pageId)) { |
--- client/views/pages/bbsDcry/photo/PicHistorySearch.vue
+++ client/views/pages/bbsDcry/photo/PicHistorySearch.vue
... | ... | @@ -13,69 +13,8 @@ |
13 | 13 |
</ul> |
14 | 14 |
</div> |
15 | 15 |
</div> |
16 |
- <div class="search-form form"> |
|
17 |
- <dl> |
|
18 |
- <dd class="mb-15"> |
|
19 |
- <p>검색범위</p> |
|
20 |
- <ul> |
|
21 |
- <li> |
|
22 |
- <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions" /> |
|
23 |
- <label for="allScope">전체</label> |
|
24 |
- </li> |
|
25 |
- <li> |
|
26 |
- <input type="checkbox" id="searchSj" v-model="searchReqDTO.useSj" @change="fnChkOption" /> |
|
27 |
- <label for="searchSj">제목</label> |
|
28 |
- </li> |
|
29 |
- <li> |
|
30 |
- <input type="checkbox" id="searchCn" v-model="searchReqDTO.useCn" @change="fnChkOption" /> |
|
31 |
- <label for="searchCn">내용</label> |
|
32 |
- </li> |
|
33 |
- <li> |
|
34 |
- <input type="checkbox" id="searchAdres" v-model="searchReqDTO.useAdres" @change="fnChkOption" /> |
|
35 |
- <label for="searchAdres">주소</label> |
|
36 |
- </li> |
|
37 |
- </ul> |
|
38 |
- </dd> |
|
39 |
- <dd class="mb-15"> |
|
40 |
- <p>검색어</p> |
|
41 |
- <div class="wfull"><input type="text" v-model="searchReqDTO.searchText" v-on:keyup.enter="fnChnageReqDTO"></div> |
|
42 |
- </dd> |
|
43 |
- <dd class="mb-15"> |
|
44 |
- <p>생산연도</p> |
|
45 |
- <input type="date" v-model="searchReqDTO.startYear"> |
|
46 |
- <p class="mark">~</p> |
|
47 |
- <input type="date" v-model="searchReqDTO.endYear"> |
|
48 |
- </dd> |
|
49 |
- <dd class="mb-20 category-dd"> |
|
50 |
- <p>카테고리</p> |
|
51 |
- <ul> |
|
52 |
- <li v-for="(category, idx) of categorys" :key="idx"> |
|
53 |
- <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="searchReqDTO.searchCtgries" /> |
|
54 |
- <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> |
|
55 |
- </li> |
|
56 |
- </ul> |
|
57 |
- </dd> |
|
58 |
- <dd class="mb-15"> |
|
59 |
- <p>정렬</p> |
|
60 |
- <ul> |
|
61 |
- <li v-for="(order, idx) of orders" :key="idx"> |
|
62 |
- <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="searchReqDTO.order" /> |
|
63 |
- <label :for="order.key">{{ order.value }}</label> |
|
64 |
- </li> |
|
65 |
- </ul> |
|
66 |
- </dd> |
|
67 |
- <div class="btn-group"> |
|
68 |
- <button type="button" class="reset" @click="init"> |
|
69 |
- <img :src="reseticon" alt=""> |
|
70 |
- <p>초기화</p> |
|
71 |
- </button> |
|
72 |
- <button type="button" class="search" @click="fnChnageReqDTO"> |
|
73 |
- <img :src="searchicon" alt=""> |
|
74 |
- <p>검색</p> |
|
75 |
- </button> |
|
76 |
- </div> |
|
77 |
- </dl> |
|
78 |
- </div> |
|
16 |
+ <!-- 검색 폼 컴포넌트 사용 --> |
|
17 |
+ <SearchFormComponent :initialData="searchReqDTO" pageType="pic" @search="handleSearch" @reset="handleReset" /> |
|
79 | 18 |
<div class="search-result"> |
80 | 19 |
<div class="tabs"> |
81 | 20 |
<div class="flex-sp-bw mb-20 align-center"> |
... | ... | @@ -107,9 +46,7 @@ |
107 | 46 |
<div v-else class="no-results"> |
108 | 47 |
<img :src="nosearch" alt=""> |
109 | 48 |
<p>검색 결과가 없습니다.</p> |
110 |
- <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> |
|
111 |
-검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> |
|
112 |
-일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
49 |
+ <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> 검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> 일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
113 | 50 |
</div> |
114 | 51 |
</div> |
115 | 52 |
</div> |
... | ... | @@ -117,18 +54,26 @@ |
117 | 54 |
<DefaultPagination class="mt-40" :search="searchReqDTO" @onChange="fnChangeCurrentPage" /> |
118 | 55 |
</div> |
119 | 56 |
</div> |
57 |
+ <div v-if="loading" class="loading-overlay"> |
|
58 |
+ <div class="loading-spinner"></div> |
|
59 |
+ <div> |
|
60 |
+ <p>검색 중입니다</p> |
|
61 |
+ <p>잠시만 기다려주세요</p> |
|
62 |
+ </div> |
|
63 |
+ </div> |
|
120 | 64 |
</template> |
121 | 65 |
<script> |
122 | 66 |
// COMPONENT |
67 |
+import SearchFormComponent from '@/views/component/SearchFormComponent.vue'; |
|
123 | 68 |
import CardStyleComponent from '@/views/component/listLayout/CardStyleComponent.vue'; |
124 | 69 |
import ListStyleComponent from '@/views/component/listLayout/ListStyleComponent.vue'; |
125 | 70 |
import DefaultPagination from '@/views/component/listLayout/DefaultPagination.vue'; |
126 | 71 |
// API |
127 |
-import { findAllByNullProc } from "@/resources/api/category"; |
|
128 | 72 |
import { findDcrysProc } from "@/resources/api/dcry"; |
129 | 73 |
|
130 | 74 |
export default { |
131 | 75 |
components: { |
76 |
+ SearchFormComponent, |
|
132 | 77 |
DefaultPagination, |
133 | 78 |
CardStyleComponent, |
134 | 79 |
ListStyleComponent, |
... | ... | @@ -140,22 +85,7 @@ |
140 | 85 |
nosearch: "client/resources/images/no_search.png", |
141 | 86 |
resulticon: "client/resources/images/icon/r-check.png", |
142 | 87 |
homeicon: 'client/resources/images/icon/home.png', |
143 |
- searchicon: 'client/resources/images/icon/search.png', |
|
144 |
- reseticon: 'client/resources/images/icon/reset.png', |
|
145 | 88 |
righticon: 'client/resources/images/icon/right.png', |
146 |
- |
|
147 |
- // 검색용 객체 |
|
148 |
- isChkAllScope: true, // 검색범위 전체 체크 여부 |
|
149 |
- searchType: [ |
|
150 |
- { key: "sj", value: "제목" }, |
|
151 |
- { key: "cn", value: "내용" }, |
|
152 |
- { key: "adres", value: "주소" }, |
|
153 |
- ], // 검색범위 목록 |
|
154 |
- categorys: [], // 카테고리 목록 |
|
155 |
- orders: [ |
|
156 |
- { key: "rgsde", value: "최신" }, |
|
157 |
- { key: "rdcnt", value: "인기" }, |
|
158 |
- ], // 정렬 목록 |
|
159 | 89 |
|
160 | 90 |
// 검색용 객체 초기값 |
161 | 91 |
searchDefault: { |
... | ... | @@ -165,15 +95,18 @@ |
165 | 95 |
searchText: null, |
166 | 96 |
startYear: null, |
167 | 97 |
endYear: null, |
168 |
- searchTy: "P", |
|
98 |
+ searchTy: "P", // 사진 기록물 고정 |
|
169 | 99 |
searchCtgries: [], |
170 | 100 |
order: "rgsde", |
171 | 101 |
// 페이지네이션 |
172 | 102 |
currentPage: 1, // 현재 페이지 |
173 | 103 |
recordSize: 24, // 한 페이지에 표시할 데이터 개수 |
174 | 104 |
}, |
175 |
- searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
176 | 105 |
|
106 |
+ // URL 파라미터로부터 가져온 초기 검색 조건 |
|
107 |
+ urlParamsDefault: null, |
|
108 |
+ |
|
109 |
+ searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
177 | 110 |
searchResult: [], // 검색결과 |
178 | 111 |
|
179 | 112 |
// 목록 레이아웃 |
... | ... | @@ -193,66 +126,52 @@ |
193 | 126 |
}, |
194 | 127 |
], |
195 | 128 |
|
196 |
- isInitialLoad: true // 초기 로드 여부 |
|
129 |
+ isInitialLoad: true, // 초기 로드 여부 |
|
130 |
+ |
|
131 |
+ loading: false, // 로딩 상태 추가 |
|
197 | 132 |
}; |
198 | 133 |
}, |
199 | 134 |
|
200 | 135 |
created() { |
201 |
- this.init(); // 초기화 |
|
202 |
- this.fnFindCategorys(); // 카테고리 목록 조회 (검색조건 없음) |
|
136 |
+ // 초기화 |
|
137 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
138 |
+ this.selectedTabId = this.tabs[0].id; // 기본 탭 설정 |
|
139 |
+ |
|
140 |
+ // URL 파라미터에서 검색 조건 가져오기 |
|
141 |
+ this.queryParamsToSearch(); |
|
142 |
+ }, |
|
143 |
+ |
|
144 |
+ mounted() { |
|
145 |
+ this.fnSearch(); // 초기 검색 실행 |
|
203 | 146 |
}, |
204 | 147 |
|
205 | 148 |
methods: { |
206 |
- // 초기화 |
|
207 |
- init() { |
|
208 |
- if (this.isInitialLoad) { |
|
209 |
- this.isInitialLoad = false; |
|
210 |
- |
|
211 |
- this.queryParamsToSearch(); |
|
212 |
- } else { |
|
213 |
- if (!confirm('검색 조건을 초기화하시겠습니까?')) { |
|
214 |
- return; |
|
215 |
- } |
|
216 |
- } |
|
217 |
- |
|
218 |
- this.searchReqDTO.searchTy = "P"; // 사진 기록물 고정 |
|
219 |
- this.selectedTabId = this.tabs[0].id; |
|
220 |
- |
|
221 |
- this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
222 |
- this.searchResult = []; // 검색결과 초기화 |
|
223 |
- |
|
224 |
- this.fnSearch(); // 통합검색 |
|
225 |
- }, |
|
226 |
- |
|
149 |
+ // URL 파라미터로부터 검색 조건 설정 |
|
227 | 150 |
queryParamsToSearch() { |
228 | 151 |
let query = this.$route.query; |
229 | 152 |
if (!this.$isEmpty(query)) { |
153 |
+ // 기본 검색 조건 복사 |
|
154 |
+ let urlParams = JSON.parse(JSON.stringify(this.searchDefault)); |
|
155 |
+ |
|
230 | 156 |
const typeConverters = { |
231 | 157 |
useSj: val => val === 'true', |
232 | 158 |
useCn: val => val === 'true', |
233 | 159 |
useAdres: val => val === 'true', |
234 | 160 |
searchCtgries: val => Array.isArray(val) ? val : (val ? val.split(',') : []) |
235 | 161 |
}; |
162 |
+ |
|
163 |
+ // URL 파라미터 값 적용 |
|
236 | 164 |
Object.entries(query).forEach(([key, value]) => { |
237 |
- if (key in this.searchDefault) { |
|
238 |
- this.searchDefault[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
165 |
+ if (key in urlParams) { |
|
166 |
+ urlParams[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
239 | 167 |
} |
240 | 168 |
}); |
241 |
- } |
|
242 |
- }, |
|
243 | 169 |
|
244 |
- // 카테고리 목록 조회 |
|
245 |
- async fnFindCategorys() { |
|
246 |
- try { |
|
247 |
- const response = await findAllByNullProc(); |
|
248 |
- this.categorys = response.data.data.ctgry; |
|
249 |
- } catch (error) { |
|
250 |
- this.categorys = []; // 카테고리 목록 초기화 |
|
170 |
+ // URL 파라미터 기반 초기값 저장 |
|
171 |
+ this.urlParamsDefault = urlParams; |
|
251 | 172 |
|
252 |
- if (error.response) { |
|
253 |
- alert(error.response.data.message); |
|
254 |
- } |
|
255 |
- console.error(error.message); |
|
173 |
+ // 현재 검색 조건에 적용 |
|
174 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(urlParams)); |
|
256 | 175 |
} |
257 | 176 |
}, |
258 | 177 |
|
... | ... | @@ -262,6 +181,31 @@ |
262 | 181 |
this.$nextTick(() => { |
263 | 182 |
this.fnSearch(); |
264 | 183 |
}); |
184 |
+ }, |
|
185 |
+ |
|
186 |
+ // 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드 |
|
187 |
+ handleSearch(formData) { |
|
188 |
+ // searchTy는 항상 "P"로 유지 |
|
189 |
+ formData.searchTy = "P"; |
|
190 |
+ |
|
191 |
+ // 페이지 초기화 |
|
192 |
+ formData.currentPage = 1; |
|
193 |
+ |
|
194 |
+ this.searchReqDTO = formData; |
|
195 |
+ this.fnSearch(); |
|
196 |
+ }, |
|
197 |
+ |
|
198 |
+ // 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드 |
|
199 |
+ handleReset() { |
|
200 |
+ // URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용 |
|
201 |
+ if (this.urlParamsDefault) { |
|
202 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault)); |
|
203 |
+ } else { |
|
204 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
205 |
+ } |
|
206 |
+ |
|
207 |
+ this.searchResult = []; // 검색결과 초기화 |
|
208 |
+ this.fnSearch(); // 초기화 후 검색 실행 |
|
265 | 209 |
}, |
266 | 210 |
|
267 | 211 |
// 검색 조건이 변경된 경우 |
... | ... | @@ -274,6 +218,7 @@ |
274 | 218 |
|
275 | 219 |
// 통합검색 |
276 | 220 |
async fnSearch() { |
221 |
+ this.loading = true; // 로딩 시작 |
|
277 | 222 |
try { |
278 | 223 |
const params = JSON.parse(JSON.stringify(this.searchReqDTO)); |
279 | 224 |
|
... | ... | @@ -295,19 +240,9 @@ |
295 | 240 |
alert(error.response.data.message); |
296 | 241 |
} |
297 | 242 |
console.error(error.message); |
243 |
+ } finally { |
|
244 |
+ this.loading = false; // 로딩 종료 |
|
298 | 245 |
} |
299 |
- }, |
|
300 |
- |
|
301 |
- // 기록유형 전체 선택 여부 변경 |
|
302 |
- fnChkAllOptions() { |
|
303 |
- this.searchReqDTO.useSj = this.isChkAllScope; |
|
304 |
- this.searchReqDTO.useCn = this.isChkAllScope; |
|
305 |
- this.searchReqDTO.useAdres = this.isChkAllScope; |
|
306 |
- }, |
|
307 |
- |
|
308 |
- // 기록유형 선택 여부 변경 |
|
309 |
- fnChkOption() { |
|
310 |
- this.isChkAllScope = this.searchReqDTO.useSj && this.searchReqDTO.useCn && this.searchReqDTO.useAdres; |
|
311 | 246 |
}, |
312 | 247 |
|
313 | 248 |
selectTab(tabId) { |
--- client/views/pages/bbsDcry/video/VideoHistorySearch.vue
+++ client/views/pages/bbsDcry/video/VideoHistorySearch.vue
... | ... | @@ -13,69 +13,8 @@ |
13 | 13 |
</ul> |
14 | 14 |
</div> |
15 | 15 |
</div> |
16 |
- <div class="search-form form"> |
|
17 |
- <dl> |
|
18 |
- <dd class="mb-15"> |
|
19 |
- <p>검색범위</p> |
|
20 |
- <ul> |
|
21 |
- <li> |
|
22 |
- <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions" /> |
|
23 |
- <label for="allScope">전체</label> |
|
24 |
- </li> |
|
25 |
- <li> |
|
26 |
- <input type="checkbox" id="searchSj" v-model="searchReqDTO.useSj" @change="fnChkOption" /> |
|
27 |
- <label for="searchSj">제목</label> |
|
28 |
- </li> |
|
29 |
- <li> |
|
30 |
- <input type="checkbox" id="searchCn" v-model="searchReqDTO.useCn" @change="fnChkOption" /> |
|
31 |
- <label for="searchCn">내용</label> |
|
32 |
- </li> |
|
33 |
- <li> |
|
34 |
- <input type="checkbox" id="searchAdres" v-model="searchReqDTO.useAdres" @change="fnChkOption" /> |
|
35 |
- <label for="searchAdres">주소</label> |
|
36 |
- </li> |
|
37 |
- </ul> |
|
38 |
- </dd> |
|
39 |
- <dd class="mb-15"> |
|
40 |
- <p>검색어</p> |
|
41 |
- <div class="wfull"><input type="text" v-model="searchReqDTO.searchText" v-on:keyup.enter="fnChnageReqDTO"></div> |
|
42 |
- </dd> |
|
43 |
- <dd class="mb-15"> |
|
44 |
- <p>생산연도</p> |
|
45 |
- <input type="date" v-model="searchReqDTO.startYear"> |
|
46 |
- <p class="mark">~</p> |
|
47 |
- <input type="date" v-model="searchReqDTO.endYear"> |
|
48 |
- </dd> |
|
49 |
- <dd class="mb-20 category-dd"> |
|
50 |
- <p>카테고리</p> |
|
51 |
- <ul> |
|
52 |
- <li v-for="(category, idx) of categorys" :key="idx"> |
|
53 |
- <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="searchReqDTO.searchCtgries" /> |
|
54 |
- <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> |
|
55 |
- </li> |
|
56 |
- </ul> |
|
57 |
- </dd> |
|
58 |
- <dd class="mb-15"> |
|
59 |
- <p>정렬</p> |
|
60 |
- <ul> |
|
61 |
- <li v-for="(order, idx) of orders" :key="idx"> |
|
62 |
- <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="searchReqDTO.order" /> |
|
63 |
- <label :for="order.key">{{ order.value }}</label> |
|
64 |
- </li> |
|
65 |
- </ul> |
|
66 |
- </dd> |
|
67 |
- <div class="btn-group"> |
|
68 |
- <button type="button" class="reset" @click="init"> |
|
69 |
- <img :src="reseticon" alt=""> |
|
70 |
- <p>초기화</p> |
|
71 |
- </button> |
|
72 |
- <button type="button" class="search" @click="fnChnageReqDTO"> |
|
73 |
- <img :src="searchicon" alt=""> |
|
74 |
- <p>검색</p> |
|
75 |
- </button> |
|
76 |
- </div> |
|
77 |
- </dl> |
|
78 |
- </div> |
|
16 |
+ <!-- 검색 폼 컴포넌트 사용 --> |
|
17 |
+ <SearchFormComponent :initialData="searchReqDTO" pageType="video" @search="handleSearch" @reset="handleReset" /> |
|
79 | 18 |
<div class="search-result"> |
80 | 19 |
<div class="tabs"> |
81 | 20 |
<div class="flex-sp-bw mb-20 align-center"> |
... | ... | @@ -107,9 +46,7 @@ |
107 | 46 |
<div v-else class="no-results"> |
108 | 47 |
<img :src="nosearch" alt=""> |
109 | 48 |
<p>검색 결과가 없습니다.</p> |
110 |
- <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> |
|
111 |
-검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> |
|
112 |
-일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
49 |
+ <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> 검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> 일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
113 | 50 |
</div> |
114 | 51 |
</div> |
115 | 52 |
</div> |
... | ... | @@ -117,18 +54,26 @@ |
117 | 54 |
<DefaultPagination class="mt-40" :search="searchReqDTO" @onChange="fnChangeCurrentPage" /> |
118 | 55 |
</div> |
119 | 56 |
</div> |
57 |
+ <div v-if="loading" class="loading-overlay"> |
|
58 |
+ <div class="loading-spinner"></div> |
|
59 |
+ <div> |
|
60 |
+ <p>검색 중입니다</p> |
|
61 |
+ <p>잠시만 기다려주세요</p> |
|
62 |
+ </div> |
|
63 |
+ </div> |
|
120 | 64 |
</template> |
121 | 65 |
<script> |
122 | 66 |
// COMPONENT |
67 |
+import SearchFormComponent from '@/views/component/SearchFormComponent.vue'; |
|
123 | 68 |
import CardStyleComponent from '@/views/component/listLayout/CardStyleComponent.vue'; |
124 | 69 |
import ListStyleComponent from '@/views/component/listLayout/ListStyleComponent.vue'; |
125 | 70 |
import DefaultPagination from '@/views/component/listLayout/DefaultPagination.vue'; |
126 | 71 |
// API |
127 |
-import { findAllByNullProc } from "@/resources/api/category"; |
|
128 | 72 |
import { findDcrysProc } from "@/resources/api/dcry"; |
129 | 73 |
|
130 | 74 |
export default { |
131 | 75 |
components: { |
76 |
+ SearchFormComponent, |
|
132 | 77 |
DefaultPagination, |
133 | 78 |
CardStyleComponent, |
134 | 79 |
ListStyleComponent, |
... | ... | @@ -140,22 +85,7 @@ |
140 | 85 |
resulticon: "client/resources/images/icon/r-check.png", |
141 | 86 |
nosearch: "client/resources/images/no_search.png", |
142 | 87 |
homeicon: 'client/resources/images/icon/home.png', |
143 |
- searchicon: 'client/resources/images/icon/search.png', |
|
144 |
- reseticon: 'client/resources/images/icon/reset.png', |
|
145 | 88 |
righticon: 'client/resources/images/icon/right.png', |
146 |
- |
|
147 |
- // 검색용 객체 |
|
148 |
- isChkAllScope: true, // 검색범위 전체 체크 여부 |
|
149 |
- searchType: [ |
|
150 |
- { key: "sj", value: "제목" }, |
|
151 |
- { key: "cn", value: "내용" }, |
|
152 |
- { key: "adres", value: "주소" }, |
|
153 |
- ], // 검색범위 목록 |
|
154 |
- categorys: [], // 카테고리 목록 |
|
155 |
- orders: [ |
|
156 |
- { key: "rgsde", value: "최신" }, |
|
157 |
- { key: "rdcnt", value: "인기" }, |
|
158 |
- ], // 정렬 목록 |
|
159 | 89 |
|
160 | 90 |
// 검색용 객체 초기값 |
161 | 91 |
searchDefault: { |
... | ... | @@ -165,15 +95,18 @@ |
165 | 95 |
searchText: null, |
166 | 96 |
startYear: null, |
167 | 97 |
endYear: null, |
168 |
- searchTy: "V", |
|
98 |
+ searchTy: "V", // 영상 기록물 고정 |
|
169 | 99 |
searchCtgries: [], |
170 | 100 |
order: "rgsde", |
171 | 101 |
// 페이지네이션 |
172 | 102 |
currentPage: 1, // 현재 페이지 |
173 | 103 |
recordSize: 24, // 한 페이지에 표시할 데이터 개수 |
174 | 104 |
}, |
175 |
- searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
176 | 105 |
|
106 |
+ // URL 파라미터로부터 가져온 초기 검색 조건 |
|
107 |
+ urlParamsDefault: null, |
|
108 |
+ |
|
109 |
+ searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
177 | 110 |
searchResult: [], // 검색결과 |
178 | 111 |
|
179 | 112 |
// 목록 레이아웃 |
... | ... | @@ -193,66 +126,52 @@ |
193 | 126 |
}, |
194 | 127 |
], |
195 | 128 |
|
196 |
- isInitialLoad: true // 초기 로드 여부 |
|
129 |
+ isInitialLoad: true, // 초기 로드 여부 |
|
130 |
+ |
|
131 |
+ loading: false, // 로딩 상태 추가 |
|
197 | 132 |
}; |
198 | 133 |
}, |
199 | 134 |
|
200 | 135 |
created() { |
201 |
- this.init(); // 초기화 |
|
202 |
- this.fnFindCategorys(); // 카테고리 목록 조회 (검색조건 없음) |
|
136 |
+ // 초기화 |
|
137 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
138 |
+ this.selectedTabId = this.tabs[0].id; // 기본 탭 설정 |
|
139 |
+ |
|
140 |
+ // URL 파라미터에서 검색 조건 가져오기 |
|
141 |
+ this.queryParamsToSearch(); |
|
142 |
+ }, |
|
143 |
+ |
|
144 |
+ mounted() { |
|
145 |
+ this.fnSearch(); // 초기 검색 실행 |
|
203 | 146 |
}, |
204 | 147 |
|
205 | 148 |
methods: { |
206 |
- // 초기화 |
|
207 |
- init() { |
|
208 |
- if (this.isInitialLoad) { |
|
209 |
- this.isInitialLoad = false; |
|
210 |
- |
|
211 |
- this.queryParamsToSearch(); |
|
212 |
- } else { |
|
213 |
- if (!confirm('검색 조건을 초기화하시겠습니까?')) { |
|
214 |
- return; |
|
215 |
- } |
|
216 |
- } |
|
217 |
- |
|
218 |
- this.searchReqDTO.searchTy = "V"; // 영상 기록물 고정 |
|
219 |
- this.selectedTabId = this.tabs[0].id; |
|
220 |
- |
|
221 |
- this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
222 |
- this.searchResult = []; // 검색결과 초기화 |
|
223 |
- |
|
224 |
- this.fnChnageReqDTO(); // 통합검색 |
|
225 |
- }, |
|
226 |
- |
|
149 |
+ // URL 파라미터로부터 검색 조건 설정 |
|
227 | 150 |
queryParamsToSearch() { |
228 | 151 |
let query = this.$route.query; |
229 | 152 |
if (!this.$isEmpty(query)) { |
153 |
+ // 기본 검색 조건 복사 |
|
154 |
+ let urlParams = JSON.parse(JSON.stringify(this.searchDefault)); |
|
155 |
+ |
|
230 | 156 |
const typeConverters = { |
231 | 157 |
useSj: val => val === 'true', |
232 | 158 |
useCn: val => val === 'true', |
233 | 159 |
useAdres: val => val === 'true', |
234 | 160 |
searchCtgries: val => Array.isArray(val) ? val : (val ? val.split(',') : []) |
235 | 161 |
}; |
162 |
+ |
|
163 |
+ // URL 파라미터 값 적용 |
|
236 | 164 |
Object.entries(query).forEach(([key, value]) => { |
237 |
- if (key in this.searchDefault) { |
|
238 |
- this.searchDefault[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
165 |
+ if (key in urlParams) { |
|
166 |
+ urlParams[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
239 | 167 |
} |
240 | 168 |
}); |
241 |
- } |
|
242 |
- }, |
|
243 | 169 |
|
244 |
- // 카테고리 목록 조회 |
|
245 |
- async fnFindCategorys() { |
|
246 |
- try { |
|
247 |
- const response = await findAllByNullProc(); |
|
248 |
- this.categorys = response.data.data.ctgry; |
|
249 |
- } catch (error) { |
|
250 |
- this.categorys = []; // 카테고리 목록 초기화 |
|
170 |
+ // URL 파라미터 기반 초기값 저장 |
|
171 |
+ this.urlParamsDefault = urlParams; |
|
251 | 172 |
|
252 |
- if (error.response) { |
|
253 |
- alert(error.response.data.message); |
|
254 |
- } |
|
255 |
- console.error(error.message); |
|
173 |
+ // 현재 검색 조건에 적용 |
|
174 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(urlParams)); |
|
256 | 175 |
} |
257 | 176 |
}, |
258 | 177 |
|
... | ... | @@ -262,6 +181,31 @@ |
262 | 181 |
this.$nextTick(() => { |
263 | 182 |
this.fnSearch(); |
264 | 183 |
}); |
184 |
+ }, |
|
185 |
+ |
|
186 |
+ // 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드 |
|
187 |
+ handleSearch(formData) { |
|
188 |
+ // searchTy는 항상 "V"로 유지 |
|
189 |
+ formData.searchTy = "V"; |
|
190 |
+ |
|
191 |
+ // 페이지 초기화 |
|
192 |
+ formData.currentPage = 1; |
|
193 |
+ |
|
194 |
+ this.searchReqDTO = formData; |
|
195 |
+ this.fnSearch(); |
|
196 |
+ }, |
|
197 |
+ |
|
198 |
+ // 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드 |
|
199 |
+ handleReset() { |
|
200 |
+ // URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용 |
|
201 |
+ if (this.urlParamsDefault) { |
|
202 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault)); |
|
203 |
+ } else { |
|
204 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
205 |
+ } |
|
206 |
+ |
|
207 |
+ this.searchResult = []; // 검색결과 초기화 |
|
208 |
+ this.fnSearch(); // 초기화 후 검색 실행 |
|
265 | 209 |
}, |
266 | 210 |
|
267 | 211 |
// 검색 조건이 변경된 경우 |
... | ... | @@ -274,6 +218,7 @@ |
274 | 218 |
|
275 | 219 |
// 통합검색 |
276 | 220 |
async fnSearch() { |
221 |
+ this.loading = true; // 로딩 시작 |
|
277 | 222 |
try { |
278 | 223 |
const params = JSON.parse(JSON.stringify(this.searchReqDTO)); |
279 | 224 |
|
... | ... | @@ -295,19 +240,9 @@ |
295 | 240 |
alert(error.response.data.message); |
296 | 241 |
} |
297 | 242 |
console.error(error.message); |
243 |
+ } finally { |
|
244 |
+ this.loading = false; // 로딩 종료 |
|
298 | 245 |
} |
299 |
- }, |
|
300 |
- |
|
301 |
- // 기록유형 전체 선택 여부 변경 |
|
302 |
- fnChkAllOptions() { |
|
303 |
- this.searchReqDTO.useSj = this.isChkAllScope; |
|
304 |
- this.searchReqDTO.useCn = this.isChkAllScope; |
|
305 |
- this.searchReqDTO.useAdres = this.isChkAllScope; |
|
306 |
- }, |
|
307 |
- |
|
308 |
- // 기록유형 선택 여부 변경 |
|
309 |
- fnChkOption() { |
|
310 |
- this.isChkAllScope = this.searchReqDTO.useSj && this.searchReqDTO.useCn && this.searchReqDTO.useAdres; |
|
311 | 246 |
}, |
312 | 247 |
|
313 | 248 |
selectTab(tabId) { |
--- client/views/pages/bbsMediaVido/MediaVideoSearch.vue
+++ client/views/pages/bbsMediaVido/MediaVideoSearch.vue
... | ... | @@ -12,65 +12,8 @@ |
12 | 12 |
</ul> |
13 | 13 |
</div> |
14 | 14 |
</div> |
15 |
- <div class="search-form form"> |
|
16 |
- <dl> |
|
17 |
- <dd class="mb-15"> |
|
18 |
- <p>검색범위</p> |
|
19 |
- <ul> |
|
20 |
- <li> |
|
21 |
- <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions" /> |
|
22 |
- <label for="allScope">전체</label> |
|
23 |
- </li> |
|
24 |
- <li> |
|
25 |
- <input type="checkbox" id="searchSj" v-model="searchReqDTO.useSj" @change="fnChkOption" /> |
|
26 |
- <label for="searchSj">제목</label> |
|
27 |
- </li> |
|
28 |
- <li> |
|
29 |
- <input type="checkbox" id="searchCn" v-model="searchReqDTO.useCn" @change="fnChkOption" /> |
|
30 |
- <label for="searchCn">내용</label> |
|
31 |
- </li> |
|
32 |
- </ul> |
|
33 |
- </dd> |
|
34 |
- <dd class="mb-15"> |
|
35 |
- <p>검색어</p> |
|
36 |
- <div class="wfull"><input type="text" v-model="searchReqDTO.searchText" v-on:keyup.enter="fnChnageReqDTO"></div> |
|
37 |
- </dd> |
|
38 |
- <dd class="mb-15"> |
|
39 |
- <p>생산연도</p> |
|
40 |
- <input type="date" v-model="searchReqDTO.startYear"> |
|
41 |
- <p class="mark">~</p> |
|
42 |
- <input type="date" v-model="searchReqDTO.endYear"> |
|
43 |
- </dd> |
|
44 |
- <dd class="mb-20 category-dd"> |
|
45 |
- <p>카테고리</p> |
|
46 |
- <ul> |
|
47 |
- <li v-for="(category, idx) of categorys" :key="idx"> |
|
48 |
- <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="searchReqDTO.searchCtgries" /> |
|
49 |
- <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> |
|
50 |
- </li> |
|
51 |
- </ul> |
|
52 |
- </dd> |
|
53 |
- <dd class="mb-15"> |
|
54 |
- <p>정렬</p> |
|
55 |
- <ul> |
|
56 |
- <li v-for="(order, idx) of orders" :key="idx"> |
|
57 |
- <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="searchReqDTO.order" /> |
|
58 |
- <label :for="order.key">{{ order.value }}</label> |
|
59 |
- </li> |
|
60 |
- </ul> |
|
61 |
- </dd> |
|
62 |
- <div class="btn-group"> |
|
63 |
- <button type="button" class="reset" @click="init"> |
|
64 |
- <img :src="reseticon" alt=""> |
|
65 |
- <p>초기화</p> |
|
66 |
- </button> |
|
67 |
- <button type="button" class="search" @click="fnChnageReqDTO"> |
|
68 |
- <img :src="searchicon" alt=""> |
|
69 |
- <p>검색</p> |
|
70 |
- </button> |
|
71 |
- </div> |
|
72 |
- </dl> |
|
73 |
- </div> |
|
15 |
+ <!-- 검색 폼 컴포넌트 사용 --> |
|
16 |
+ <SearchFormComponent :initialData="searchReqDTO" pageType="media" @search="handleSearch" @reset="handleReset" /> |
|
74 | 17 |
<div class="search-result"> |
75 | 18 |
<div class="tabs"> |
76 | 19 |
<div class="flex-sp-bw mb-20 align-center"> |
... | ... | @@ -102,9 +45,7 @@ |
102 | 45 |
<div v-else class="no-results"> |
103 | 46 |
<img :src="nosearch" alt=""> |
104 | 47 |
<p>검색 결과가 없습니다.</p> |
105 |
- <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> |
|
106 |
-검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> |
|
107 |
-일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
48 |
+ <p>단어의 철자가 정확한지 확인해 주시기 바랍니다.<br> 검색어의 단어 수를 줄이거나, 다른 검색어(유사어)로 검색해 보시기 바랍니다.<br> 일반적으로 많이 사용하는 검색어로 다시 검색해 주시기 바랍니다.</p> |
|
108 | 49 |
</div> |
109 | 50 |
</div> |
110 | 51 |
</div> |
... | ... | @@ -112,18 +53,26 @@ |
112 | 53 |
<DefaultPagination class="mt-40" :search="searchReqDTO" @onChange="fnChangeCurrentPage" /> |
113 | 54 |
</div> |
114 | 55 |
</div> |
56 |
+ <div v-if="loading" class="loading-overlay"> |
|
57 |
+ <div class="loading-spinner"></div> |
|
58 |
+ <div> |
|
59 |
+ <p>검색 중입니다</p> |
|
60 |
+ <p>잠시만 기다려주세요</p> |
|
61 |
+ </div> |
|
62 |
+ </div> |
|
115 | 63 |
</template> |
116 | 64 |
<script> |
117 | 65 |
// COMPONENT |
66 |
+import SearchFormComponent from '@/views/component/SearchFormComponent.vue'; |
|
118 | 67 |
import CardStyleComponent from '@/views/component/listLayout/CardStyleComponent.vue'; |
119 | 68 |
import ListStyleComponent from '@/views/component/listLayout/ListStyleComponent.vue'; |
120 | 69 |
import DefaultPagination from '@/views/component/listLayout/DefaultPagination.vue'; |
121 | 70 |
// API |
122 |
-import { findAllByNullProc } from "@/resources/api/category"; |
|
123 | 71 |
import { findAllMediaVidosProc } from "@/resources/api/mediaVido"; |
124 | 72 |
|
125 | 73 |
export default { |
126 | 74 |
components: { |
75 |
+ SearchFormComponent, |
|
127 | 76 |
DefaultPagination, |
128 | 77 |
CardStyleComponent, |
129 | 78 |
ListStyleComponent, |
... | ... | @@ -135,22 +84,7 @@ |
135 | 84 |
nosearch: "client/resources/images/no_search.png", |
136 | 85 |
resulticon: "client/resources/images/icon/r-check.png", |
137 | 86 |
homeicon: 'client/resources/images/icon/home.png', |
138 |
- searchicon: 'client/resources/images/icon/search.png', |
|
139 |
- reseticon: 'client/resources/images/icon/reset.png', |
|
140 | 87 |
righticon: 'client/resources/images/icon/right.png', |
141 |
- |
|
142 |
- // 검색용 객체 |
|
143 |
- isChkAllScope: true, // 검색범위 전체 체크 여부 |
|
144 |
- searchType: [ |
|
145 |
- { key: "sj", value: "제목" }, |
|
146 |
- { key: "cn", value: "내용" }, |
|
147 |
- { key: "adres", value: "주소" }, |
|
148 |
- ], // 검색범위 목록 |
|
149 |
- categorys: [], // 카테고리 목록 |
|
150 |
- orders: [ |
|
151 |
- { key: "rgsde", value: "최신" }, |
|
152 |
- { key: "rdcnt", value: "인기" }, |
|
153 |
- ], // 정렬 목록 |
|
154 | 88 |
|
155 | 89 |
// 검색용 객체 초기값 |
156 | 90 |
searchDefault: { |
... | ... | @@ -159,14 +93,18 @@ |
159 | 93 |
searchText: null, |
160 | 94 |
startYear: null, |
161 | 95 |
endYear: null, |
96 |
+ searchTy: "M", // 미디어 영상 고정 |
|
162 | 97 |
searchCtgries: [], |
163 | 98 |
order: "rgsde", |
164 | 99 |
// 페이지네이션 |
165 | 100 |
currentPage: 1, // 현재 페이지 |
166 | 101 |
recordSize: 24, // 한 페이지에 표시할 데이터 개수 |
167 | 102 |
}, |
168 |
- searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
169 | 103 |
|
104 |
+ // URL 파라미터로부터 가져온 초기 검색 조건 |
|
105 |
+ urlParamsDefault: null, |
|
106 |
+ |
|
107 |
+ searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
170 | 108 |
searchResult: [], // 검색결과 |
171 | 109 |
|
172 | 110 |
// 목록 레이아웃 |
... | ... | @@ -186,64 +124,51 @@ |
186 | 124 |
}, |
187 | 125 |
], |
188 | 126 |
|
189 |
- isInitialLoad: true // 초기 로드 여부 |
|
127 |
+ isInitialLoad: true, // 초기 로드 여부 |
|
128 |
+ |
|
129 |
+ loading: false, // 로딩 상태 추가 |
|
190 | 130 |
}; |
191 | 131 |
}, |
192 | 132 |
|
193 | 133 |
created() { |
194 |
- this.init(); // 초기화 |
|
195 |
- this.fnFindCategorys(); // 카테고리 목록 조회 (검색조건 없음) |
|
134 |
+ // 초기화 |
|
135 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
136 |
+ this.selectedTabId = this.tabs[0].id; // 기본 탭 설정 |
|
137 |
+ |
|
138 |
+ // URL 파라미터에서 검색 조건 가져오기 |
|
139 |
+ this.queryParamsToSearch(); |
|
140 |
+ }, |
|
141 |
+ |
|
142 |
+ mounted() { |
|
143 |
+ this.fnSearch(); // 초기 검색 실행 |
|
196 | 144 |
}, |
197 | 145 |
|
198 | 146 |
methods: { |
199 |
- // 초기화 |
|
200 |
- init() { |
|
201 |
- if (this.isInitialLoad) { |
|
202 |
- this.isInitialLoad = false; |
|
203 |
- |
|
204 |
- this.queryParamsToSearch(); |
|
205 |
- } else { |
|
206 |
- if (!confirm('검색 조건을 초기화하시겠습니까?')) { |
|
207 |
- return; |
|
208 |
- } |
|
209 |
- } |
|
210 |
- |
|
211 |
- this.selectedTabId = this.tabs[0].id; |
|
212 |
- |
|
213 |
- this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
214 |
- this.searchResult = []; // 검색결과 초기화 |
|
215 |
- |
|
216 |
- this.fnChnageReqDTO(); // 통합검색 |
|
217 |
- }, |
|
218 |
- |
|
147 |
+ // URL 파라미터로부터 검색 조건 설정 |
|
219 | 148 |
queryParamsToSearch() { |
220 | 149 |
let query = this.$route.query; |
221 | 150 |
if (!this.$isEmpty(query)) { |
151 |
+ // 기본 검색 조건 복사 |
|
152 |
+ let urlParams = JSON.parse(JSON.stringify(this.searchDefault)); |
|
153 |
+ |
|
222 | 154 |
const typeConverters = { |
223 | 155 |
useSj: val => val === 'true', |
224 | 156 |
useCn: val => val === 'true', |
225 | 157 |
searchCtgries: val => Array.isArray(val) ? val : (val ? val.split(',') : []) |
226 | 158 |
}; |
159 |
+ |
|
160 |
+ // URL 파라미터 값 적용 |
|
227 | 161 |
Object.entries(query).forEach(([key, value]) => { |
228 |
- if (key in this.searchDefault) { |
|
229 |
- this.searchDefault[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
162 |
+ if (key in urlParams) { |
|
163 |
+ urlParams[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
230 | 164 |
} |
231 | 165 |
}); |
232 |
- } |
|
233 |
- }, |
|
234 | 166 |
|
235 |
- // 카테고리 목록 조회 |
|
236 |
- async fnFindCategorys() { |
|
237 |
- try { |
|
238 |
- const response = await findAllByNullProc(); |
|
239 |
- this.categorys = response.data.data.ctgry; |
|
240 |
- } catch (error) { |
|
241 |
- this.categorys = []; // 카테고리 목록 초기화 |
|
167 |
+ // URL 파라미터 기반 초기값 저장 |
|
168 |
+ this.urlParamsDefault = urlParams; |
|
242 | 169 |
|
243 |
- if (error.response) { |
|
244 |
- alert(error.response.data.message); |
|
245 |
- } |
|
246 |
- console.error(error.message); |
|
170 |
+ // 현재 검색 조건에 적용 |
|
171 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(urlParams)); |
|
247 | 172 |
} |
248 | 173 |
}, |
249 | 174 |
|
... | ... | @@ -253,6 +178,31 @@ |
253 | 178 |
this.$nextTick(() => { |
254 | 179 |
this.fnSearch(); |
255 | 180 |
}); |
181 |
+ }, |
|
182 |
+ |
|
183 |
+ // 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드 |
|
184 |
+ handleSearch(formData) { |
|
185 |
+ // searchTy는 항상 "M"로 유지 |
|
186 |
+ formData.searchTy = "M"; |
|
187 |
+ |
|
188 |
+ // 페이지 초기화 |
|
189 |
+ formData.currentPage = 1; |
|
190 |
+ |
|
191 |
+ this.searchReqDTO = formData; |
|
192 |
+ this.fnSearch(); |
|
193 |
+ }, |
|
194 |
+ |
|
195 |
+ // 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드 |
|
196 |
+ handleReset() { |
|
197 |
+ // URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용 |
|
198 |
+ if (this.urlParamsDefault) { |
|
199 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault)); |
|
200 |
+ } else { |
|
201 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
202 |
+ } |
|
203 |
+ |
|
204 |
+ this.searchResult = []; // 검색결과 초기화 |
|
205 |
+ this.fnSearch(); // 초기화 후 검색 실행 |
|
256 | 206 |
}, |
257 | 207 |
|
258 | 208 |
// 검색 조건이 변경된 경우 |
... | ... | @@ -265,6 +215,7 @@ |
265 | 215 |
|
266 | 216 |
// 통합검색 |
267 | 217 |
async fnSearch() { |
218 |
+ this.loading = true; // 로딩 시작 |
|
268 | 219 |
try { |
269 | 220 |
const params = JSON.parse(JSON.stringify(this.searchReqDTO)); |
270 | 221 |
|
... | ... | @@ -286,18 +237,9 @@ |
286 | 237 |
alert(error.response.data.message); |
287 | 238 |
} |
288 | 239 |
console.error(error.message); |
240 |
+ } finally { |
|
241 |
+ this.loading = false; // 로딩 종료 |
|
289 | 242 |
} |
290 |
- }, |
|
291 |
- |
|
292 |
- // 검색범위 전체 선택 여부 변경 |
|
293 |
- fnChkAllOptions() { |
|
294 |
- this.searchReqDTO.useSj = this.isChkAllScope; |
|
295 |
- this.searchReqDTO.useCn = this.isChkAllScope; |
|
296 |
- }, |
|
297 |
- |
|
298 |
- // 검색범위 선택 여부 변경 |
|
299 |
- fnChkOption() { |
|
300 |
- this.isChkAllScope = this.searchReqDTO.useSj && this.searchReqDTO.useCn; |
|
301 | 243 |
}, |
302 | 244 |
|
303 | 245 |
selectTab(tabId) { |
--- client/views/pages/bbsNesDta/NewsReleaseSearch.vue
+++ client/views/pages/bbsNesDta/NewsReleaseSearch.vue
... | ... | @@ -13,65 +13,8 @@ |
13 | 13 |
</ul> |
14 | 14 |
</div> |
15 | 15 |
</div> |
16 |
- <div class="search-form form"> |
|
17 |
- <dl> |
|
18 |
- <dd class="mb-15"> |
|
19 |
- <p>검색범위</p> |
|
20 |
- <ul> |
|
21 |
- <li> |
|
22 |
- <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions" /> |
|
23 |
- <label for="allScope">전체</label> |
|
24 |
- </li> |
|
25 |
- <li> |
|
26 |
- <input type="checkbox" id="searchSj" v-model="searchReqDTO.useSj" @change="fnChkOption" /> |
|
27 |
- <label for="searchSj">제목</label> |
|
28 |
- </li> |
|
29 |
- <li> |
|
30 |
- <input type="checkbox" id="searchCn" v-model="searchReqDTO.useCn" @change="fnChkOption" /> |
|
31 |
- <label for="searchCn">내용</label> |
|
32 |
- </li> |
|
33 |
- </ul> |
|
34 |
- </dd> |
|
35 |
- <dd class="mb-15"> |
|
36 |
- <p>검색어</p> |
|
37 |
- <div class="wfull"><input type="text" v-model="searchReqDTO.searchText" v-on:keyup.enter="fnChnageReqDTO"></div> |
|
38 |
- </dd> |
|
39 |
- <dd class="mb-15"> |
|
40 |
- <p>생산연도</p> |
|
41 |
- <input type="date" v-model="searchReqDTO.startYear"> |
|
42 |
- <p class="mark">~</p> |
|
43 |
- <input type="date" v-model="searchReqDTO.endYear"> |
|
44 |
- </dd> |
|
45 |
- <dd class="mb-20 category-dd"> |
|
46 |
- <p>카테고리</p> |
|
47 |
- <ul> |
|
48 |
- <li v-for="(category, idx) of categorys" :key="idx"> |
|
49 |
- <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="searchReqDTO.searchCtgries" /> |
|
50 |
- <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> |
|
51 |
- </li> |
|
52 |
- </ul> |
|
53 |
- </dd> |
|
54 |
- <dd class="mb-15"> |
|
55 |
- <p>정렬</p> |
|
56 |
- <ul> |
|
57 |
- <li v-for="(order, idx) of orders" :key="idx"> |
|
58 |
- <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="searchReqDTO.order" /> |
|
59 |
- <label :for="order.key">{{ order.value }}</label> |
|
60 |
- </li> |
|
61 |
- </ul> |
|
62 |
- </dd> |
|
63 |
- <div class="btn-group"> |
|
64 |
- <button type="button" class="reset" @click="init"> |
|
65 |
- <img :src="reseticon" alt=""> |
|
66 |
- <p>초기화</p> |
|
67 |
- </button> |
|
68 |
- <button type="button" class="search" @click="fnChnageReqDTO"> |
|
69 |
- <img :src="searchicon" alt=""> |
|
70 |
- <p>검색</p> |
|
71 |
- </button> |
|
72 |
- </div> |
|
73 |
- </dl> |
|
74 |
- </div> |
|
16 |
+ <!-- 검색 폼 컴포넌트 사용 --> |
|
17 |
+ <SearchFormComponent :initialData="searchReqDTO" pageType="bodo" @search="handleSearch" @reset="handleReset" /> |
|
75 | 18 |
<div class="search-result"> |
76 | 19 |
<div class="tabs"> |
77 | 20 |
<div class="flex-sp-bw mb-20 align-center"> |
... | ... | @@ -110,19 +53,27 @@ |
110 | 53 |
<div class="btn-group flex-end mt-40"><button type="button" class="register" @click="fnMoveTo('edit')">등록</button></div> |
111 | 54 |
<DefaultPagination class="mt-40" :search="searchReqDTO" @onChange="fnChangeCurrentPage" /> |
112 | 55 |
</div> |
56 |
+ <div v-if="loading" class="loading-overlay"> |
|
57 |
+ <div class="loading-spinner"></div> |
|
58 |
+ <div> |
|
59 |
+ <p>검색 중입니다</p> |
|
60 |
+ <p>잠시만 기다려주세요</p> |
|
61 |
+ </div> |
|
62 |
+ </div> |
|
113 | 63 |
</div> |
114 | 64 |
</template> |
115 | 65 |
<script> |
116 | 66 |
// COMPONENT |
67 |
+import SearchFormComponent from '@/views/component/SearchFormComponent.vue'; |
|
117 | 68 |
import CardStyleComponent from '@/views/component/listLayout/CardStyleComponent.vue'; |
118 | 69 |
import ListStyleComponent from '@/views/component/listLayout/ListStyleComponent.vue'; |
119 | 70 |
import DefaultPagination from '@/views/component/listLayout/DefaultPagination.vue'; |
120 | 71 |
// API |
121 |
-import { findAllByNullProc } from "@/resources/api/category"; |
|
122 | 72 |
import { findAllNesDtasProc } from "@/resources/api/nesDta"; |
123 | 73 |
|
124 | 74 |
export default { |
125 | 75 |
components: { |
76 |
+ SearchFormComponent, |
|
126 | 77 |
DefaultPagination, |
127 | 78 |
CardStyleComponent, |
128 | 79 |
ListStyleComponent, |
... | ... | @@ -134,22 +85,7 @@ |
134 | 85 |
nosearch: "client/resources/images/no_search.png", |
135 | 86 |
resulticon: "client/resources/images/icon/r-check.png", |
136 | 87 |
homeicon: 'client/resources/images/icon/home.png', |
137 |
- searchicon: 'client/resources/images/icon/search.png', |
|
138 |
- reseticon: 'client/resources/images/icon/reset.png', |
|
139 | 88 |
righticon: 'client/resources/images/icon/right.png', |
140 |
- |
|
141 |
- // 검색용 객체 |
|
142 |
- isChkAllScope: true, // 검색범위 전체 체크 여부 |
|
143 |
- searchType: [ |
|
144 |
- { key: "sj", value: "제목" }, |
|
145 |
- { key: "cn", value: "내용" }, |
|
146 |
- { key: "adres", value: "주소" }, |
|
147 |
- ], // 검색범위 목록 |
|
148 |
- categorys: [], // 카테고리 목록 |
|
149 |
- orders: [ |
|
150 |
- { key: "rgsde", value: "최신" }, |
|
151 |
- { key: "rdcnt", value: "인기" }, |
|
152 |
- ], // 정렬 목록 |
|
153 | 89 |
|
154 | 90 |
// 검색용 객체 초기값 |
155 | 91 |
searchDefault: { |
... | ... | @@ -158,14 +94,18 @@ |
158 | 94 |
searchText: null, |
159 | 95 |
startYear: null, |
160 | 96 |
endYear: null, |
97 |
+ searchTy: "N", // 보도자료 고정 |
|
161 | 98 |
searchCtgries: [], |
162 | 99 |
order: "rgsde", |
163 | 100 |
// 페이지네이션 |
164 | 101 |
currentPage: 1, // 현재 페이지 |
165 | 102 |
recordSize: 24, // 한 페이지에 표시할 데이터 개수 |
166 | 103 |
}, |
167 |
- searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
168 | 104 |
|
105 |
+ // URL 파라미터로부터 가져온 초기 검색 조건 |
|
106 |
+ urlParamsDefault: null, |
|
107 |
+ |
|
108 |
+ searchReqDTO: {}, // 실제 검색에 사용되는 객체 |
|
169 | 109 |
searchResult: [], // 검색결과 |
170 | 110 |
|
171 | 111 |
// 목록 레이아웃 |
... | ... | @@ -185,64 +125,51 @@ |
185 | 125 |
}, |
186 | 126 |
], |
187 | 127 |
|
188 |
- isInitialLoad: true // 초기 로드 여부 |
|
128 |
+ isInitialLoad: true, // 초기 로드 여부 |
|
129 |
+ |
|
130 |
+ loading: false, // 로딩 상태 추가 |
|
189 | 131 |
}; |
190 | 132 |
}, |
191 | 133 |
|
192 | 134 |
created() { |
193 |
- this.init(); // 초기화 |
|
194 |
- this.fnFindCategorys(); // 카테고리 목록 조회 (검색조건 없음) |
|
135 |
+ // 초기화 |
|
136 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
137 |
+ this.selectedTabId = this.tabs[0].id; // 기본 탭 설정 |
|
138 |
+ |
|
139 |
+ // URL 파라미터에서 검색 조건 가져오기 |
|
140 |
+ this.queryParamsToSearch(); |
|
141 |
+ }, |
|
142 |
+ |
|
143 |
+ mounted() { |
|
144 |
+ this.fnSearch(); // 초기 검색 실행 |
|
195 | 145 |
}, |
196 | 146 |
|
197 | 147 |
methods: { |
198 |
- // 초기화 |
|
199 |
- init() { |
|
200 |
- if (this.isInitialLoad) { |
|
201 |
- this.isInitialLoad = false; |
|
202 |
- |
|
203 |
- this.queryParamsToSearch(); |
|
204 |
- } else { |
|
205 |
- if (!confirm('검색 조건을 초기화하시겠습니까?')) { |
|
206 |
- return; |
|
207 |
- } |
|
208 |
- } |
|
209 |
- |
|
210 |
- this.selectedTabId = this.tabs[0].id; |
|
211 |
- |
|
212 |
- this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
213 |
- this.searchResult = []; // 검색결과 초기화 |
|
214 |
- |
|
215 |
- this.fnChnageReqDTO(); // 통합검색 |
|
216 |
- }, |
|
217 |
- |
|
148 |
+ // URL 파라미터로부터 검색 조건 설정 |
|
218 | 149 |
queryParamsToSearch() { |
219 | 150 |
let query = this.$route.query; |
220 | 151 |
if (!this.$isEmpty(query)) { |
152 |
+ // 기본 검색 조건 복사 |
|
153 |
+ let urlParams = JSON.parse(JSON.stringify(this.searchDefault)); |
|
154 |
+ |
|
221 | 155 |
const typeConverters = { |
222 | 156 |
useSj: val => val === 'true', |
223 | 157 |
useCn: val => val === 'true', |
224 | 158 |
searchCtgries: val => Array.isArray(val) ? val : (val ? val.split(',') : []) |
225 | 159 |
}; |
160 |
+ |
|
161 |
+ // URL 파라미터 값 적용 |
|
226 | 162 |
Object.entries(query).forEach(([key, value]) => { |
227 |
- if (key in this.searchDefault) { |
|
228 |
- this.searchDefault[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
163 |
+ if (key in urlParams) { |
|
164 |
+ urlParams[key] = key in typeConverters ? typeConverters[key](value) : value; |
|
229 | 165 |
} |
230 | 166 |
}); |
231 |
- } |
|
232 |
- }, |
|
233 | 167 |
|
234 |
- // 카테고리 목록 조회 |
|
235 |
- async fnFindCategorys() { |
|
236 |
- try { |
|
237 |
- const response = await findAllByNullProc(); |
|
238 |
- this.categorys = response.data.data.ctgry; |
|
239 |
- } catch (error) { |
|
240 |
- this.categorys = []; // 카테고리 목록 초기화 |
|
168 |
+ // URL 파라미터 기반 초기값 저장 |
|
169 |
+ this.urlParamsDefault = urlParams; |
|
241 | 170 |
|
242 |
- if (error.response) { |
|
243 |
- alert(error.response.data.message); |
|
244 |
- } |
|
245 |
- console.error(error.message); |
|
171 |
+ // 현재 검색 조건에 적용 |
|
172 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(urlParams)); |
|
246 | 173 |
} |
247 | 174 |
}, |
248 | 175 |
|
... | ... | @@ -252,6 +179,31 @@ |
252 | 179 |
this.$nextTick(() => { |
253 | 180 |
this.fnSearch(); |
254 | 181 |
}); |
182 |
+ }, |
|
183 |
+ |
|
184 |
+ // 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드 |
|
185 |
+ handleSearch(formData) { |
|
186 |
+ // searchTy는 항상 "N"로 유지 |
|
187 |
+ formData.searchTy = "N"; |
|
188 |
+ |
|
189 |
+ // 페이지 초기화 |
|
190 |
+ formData.currentPage = 1; |
|
191 |
+ |
|
192 |
+ this.searchReqDTO = formData; |
|
193 |
+ this.fnSearch(); |
|
194 |
+ }, |
|
195 |
+ |
|
196 |
+ // 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드 |
|
197 |
+ handleReset() { |
|
198 |
+ // URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용 |
|
199 |
+ if (this.urlParamsDefault) { |
|
200 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault)); |
|
201 |
+ } else { |
|
202 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
203 |
+ } |
|
204 |
+ |
|
205 |
+ this.searchResult = []; // 검색결과 초기화 |
|
206 |
+ this.fnSearch(); // 초기화 후 검색 실행 |
|
255 | 207 |
}, |
256 | 208 |
|
257 | 209 |
// 검색 조건이 변경된 경우 |
... | ... | @@ -264,6 +216,7 @@ |
264 | 216 |
|
265 | 217 |
// 통합검색 |
266 | 218 |
async fnSearch() { |
219 |
+ this.loading = true; // 로딩 시작 |
|
267 | 220 |
try { |
268 | 221 |
const params = JSON.parse(JSON.stringify(this.searchReqDTO)); |
269 | 222 |
|
... | ... | @@ -285,18 +238,9 @@ |
285 | 238 |
alert(error.response.data.message); |
286 | 239 |
} |
287 | 240 |
console.error(error.message); |
241 |
+ } finally { |
|
242 |
+ this.loading = false; // 로딩 종료 |
|
288 | 243 |
} |
289 |
- }, |
|
290 |
- |
|
291 |
- // 검색범위 전체 선택 여부 변경 |
|
292 |
- fnChkAllOptions() { |
|
293 |
- this.searchReqDTO.useSj = this.isChkAllScope; |
|
294 |
- this.searchReqDTO.useCn = this.isChkAllScope; |
|
295 |
- }, |
|
296 |
- |
|
297 |
- // 검색범위 선택 여부 변경 |
|
298 |
- fnChkOption() { |
|
299 |
- this.isChkAllScope = this.searchReqDTO.useSj && this.searchReqDTO.useCn; |
|
300 | 244 |
}, |
301 | 245 |
|
302 | 246 |
selectTab(tabId) { |
--- client/views/pages/main/TotalSearch.vue
+++ client/views/pages/main/TotalSearch.vue
... | ... | @@ -13,117 +13,36 @@ |
13 | 13 |
</ul> |
14 | 14 |
</div> |
15 | 15 |
</div> |
16 |
- <div class="search-form form "> |
|
17 |
- <dl> |
|
18 |
- <dd class="mb-15"> |
|
19 |
- <p>기록유형</p> |
|
20 |
- <ul> |
|
21 |
- <li> |
|
22 |
- <input type="checkbox" id="allRecord" v-model="isChkAllRecord" @change="fnChkAllOptions('record')" /> |
|
23 |
- <label for="allRecord">전체</label> |
|
24 |
- </li> |
|
25 |
- <li> |
|
26 |
- <input type="checkbox" id="photoRecord" v-model="searchReqDTO.usePhoto" @change="fnChkOption('record')" /> |
|
27 |
- <label for="photoRecord">사진</label> |
|
28 |
- </li> |
|
29 |
- <li> |
|
30 |
- <input type="checkbox" id="videoRecord" v-model="searchReqDTO.useVideo" @change="fnChkOption('record')" /> |
|
31 |
- <label for="videoRecord">영상</label> |
|
32 |
- </li> |
|
33 |
- <li> |
|
34 |
- <input type="checkbox" id="mediaVideo" v-model="searchReqDTO.useMedia" @change="fnChkOption('record')" /> |
|
35 |
- <label for="mediaVideo">미디어영상</label> |
|
36 |
- </li> |
|
37 |
- <li> |
|
38 |
- <input type="checkbox" id="newsData" v-model="searchReqDTO.useNews" @change="fnChkOption('record')" /> |
|
39 |
- <label for="newsData">보도자료</label> |
|
40 |
- </li> |
|
41 |
- </ul> |
|
42 |
- </dd> |
|
43 |
- <dd class="mb-15"> |
|
44 |
- <p>검색범위</p> |
|
45 |
- <ul> |
|
46 |
- <li> |
|
47 |
- <input type="checkbox" id="allScope" v-model="isChkAllScope" @change="fnChkAllOptions('scope')" /> |
|
48 |
- <label for="allScope">전체</label> |
|
49 |
- </li> |
|
50 |
- <li> |
|
51 |
- <input type="checkbox" id="searchSj" v-model="searchReqDTO.useSj" @change="fnChkOption('scope')" /> |
|
52 |
- <label for="searchSj">제목</label> |
|
53 |
- </li> |
|
54 |
- <li> |
|
55 |
- <input type="checkbox" id="searchCn" v-model="searchReqDTO.useCn" @change="fnChkOption('scope')" /> |
|
56 |
- <label for="searchCn">내용</label> |
|
57 |
- </li> |
|
58 |
- <li> |
|
59 |
- <input type="checkbox" id="searchAdres" v-model="searchReqDTO.useAdres" @change="fnChkOption('scope')" /> |
|
60 |
- <label for="searchAdres">주소</label> |
|
61 |
- </li> |
|
62 |
- </ul> |
|
63 |
- </dd> |
|
64 |
- <dd class="mb-15"> |
|
65 |
- <p>검색어</p> |
|
66 |
- <div class="wfull"><input type="text" v-model="searchReqDTO.searchText" v-on:keyup.enter="fnSearch()"></div> |
|
67 |
- </dd> |
|
68 |
- <dd class="mb-15"> |
|
69 |
- <p>생산연도</p> |
|
70 |
- <input type="date" v-model="searchReqDTO.startYear"> |
|
71 |
- <p class="mark">~</p> |
|
72 |
- <input type="date" v-model="searchReqDTO.endYear"> |
|
73 |
- </dd> |
|
74 |
- <dd class="mb-20 category-dd"> |
|
75 |
- <p>카테고리</p> |
|
76 |
- <ul> |
|
77 |
- <li v-for="(category, idx) of categorys" :key="idx"> |
|
78 |
- <input type="checkbox" :id="'ctgry_' + idx" name="categorys" :value="category.ctgryId" v-model="searchReqDTO.searchCtgries" /> |
|
79 |
- <label :for="'ctgry_' + idx">{{ category.ctgryNm }}</label> |
|
80 |
- </li> |
|
81 |
- </ul> |
|
82 |
- </dd> |
|
83 |
- <dd class="mb-15"> |
|
84 |
- <p>정렬</p> |
|
85 |
- <ul> |
|
86 |
- <li v-for="(order, idx) of orders" :key="idx"> |
|
87 |
- <input type="radio" :id="order.key" name="orders" :value="order.key" v-model="searchReqDTO.order" /> |
|
88 |
- <label :for="order.key">{{ order.value }}</label> |
|
89 |
- </li> |
|
90 |
- </ul> |
|
91 |
- </dd> |
|
92 |
- <div class="btn-group"> |
|
93 |
- <button type="button" class="reset" @click="init"> |
|
94 |
- <img :src="reseticon" alt=""> |
|
95 |
- <p>초기화</p> |
|
96 |
- </button> |
|
97 |
- <button type="button" class="search" @click="fnSearch"> |
|
98 |
- <img :src="searchicon" alt=""> |
|
99 |
- <p>검색</p> |
|
100 |
- </button> |
|
101 |
- </div> |
|
102 |
- </dl> |
|
103 |
- </div> |
|
16 |
+ <!-- 분리된 검색 폼 컴포넌트 사용 --> |
|
17 |
+ <SearchFormComponent :initialData="searchReqDTO" pageType="all" @search="handleSearch" @reset="handleReset" /> |
|
104 | 18 |
<div class="search-result"> |
105 | 19 |
<CardViewList v-for="(item, idx) of searchResult" :key="idx" :name="item.key" :count="item.count" :list="item.list" :params="params" /> |
20 |
+ </div> |
|
21 |
+ </div> |
|
22 |
+ <div v-if="loading" class="loading-overlay"> |
|
23 |
+ <div class="loading-spinner"></div> |
|
24 |
+ <div> |
|
25 |
+ <p>검색 중입니다</p> |
|
26 |
+ <p>잠시만 기다려주세요</p> |
|
106 | 27 |
</div> |
107 | 28 |
</div> |
108 | 29 |
</template> |
109 | 30 |
<script> |
110 | 31 |
// COMPONENT |
32 |
+import SearchFormComponent from '../../component/SearchFormComponent.vue'; |
|
111 | 33 |
import CardViewList from "../../component/listLayout/CardViewList.vue"; |
112 | 34 |
// API |
113 | 35 |
import { findAllDatas } from "../../../resources/api/main"; // 통합 검색 |
114 |
-import { findAllByNullProc } from "../../../resources/api/category"; // 카테고리 목록 검색 |
|
115 | 36 |
|
116 | 37 |
export default { |
117 | 38 |
components: { |
39 |
+ SearchFormComponent, |
|
118 | 40 |
CardViewList |
119 | 41 |
}, |
120 | 42 |
data() { |
121 | 43 |
return { |
122 | 44 |
// icon |
123 |
- resulticon: "client/resources/images/icon/r-check.png", |
|
124 | 45 |
homeicon: 'client/resources/images/icon/home.png', |
125 |
- searchicon: 'client/resources/images/icon/search.png', |
|
126 |
- reseticon: 'client/resources/images/icon/reset.png', |
|
127 | 46 |
righticon: 'client/resources/images/icon/right.png', |
128 | 47 |
|
129 | 48 |
// 검색용 객체 초기값 |
... | ... | @@ -141,131 +60,112 @@ |
141 | 60 |
searchCtgries: [], |
142 | 61 |
order: "rgsde", |
143 | 62 |
}, |
144 |
- searchReqDTO: {}, |
|
145 | 63 |
|
146 |
- isChkAllRecord: true, // 기록유형 전체 체크 여부 |
|
147 |
- searchRecord: [ |
|
148 |
- { key: "P", value: "사진" }, |
|
149 |
- { key: "V", value: "영상" }, |
|
150 |
- { key: "M", value: "미디어영상" }, |
|
151 |
- { key: "N", value: "보도자료" }, |
|
152 |
- ], // 기록유형 목록 |
|
153 |
- isChkAllScope: true, // 검색범위 전체 체크 여부 |
|
154 |
- searchType: [ |
|
155 |
- { key: "sj", value: "제목" }, |
|
156 |
- { key: "cn", value: "내용" }, |
|
157 |
- { key: "adres", value: "주소" }, |
|
158 |
- ], // 검색범위 목록 |
|
159 |
- categorys: [], // 카테고리 목록 |
|
160 |
- orders: [ |
|
161 |
- { key: "rgsde", value: "최신" }, |
|
162 |
- { key: "rdcnt", value: "인기" }, |
|
163 |
- ], // 정렬 목록 |
|
64 |
+ // URL 파라미터로부터 가져온 초기 검색 조건 |
|
65 |
+ urlParamsDefault: null, |
|
164 | 66 |
|
67 |
+ searchReqDTO: {}, // 현재 검색 조건 |
|
165 | 68 |
searchResult: [], // 검색결과 |
69 |
+ params: {}, // 바로가기 링크용 파라미터 |
|
166 | 70 |
|
167 |
- isInitialLoad: true, // 초기 로드 여부 |
|
168 |
- |
|
169 |
- params: {}, |
|
71 |
+ loading: false, // 로딩 상태 추가 |
|
170 | 72 |
}; |
171 | 73 |
}, |
172 | 74 |
|
173 | 75 |
created() { |
174 |
- this.init(); // 초기화 |
|
175 |
- this.fnFindCategorys(); // 카테고리 목록 조회 (검색조건 없음) |
|
76 |
+ // 초기화 |
|
77 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
78 |
+ |
|
79 |
+ // URL 파라미터에서 검색 조건 가져오기 |
|
80 |
+ this.loadSearchParamsFromUrl(); |
|
176 | 81 |
}, |
177 | 82 |
|
178 | 83 |
mounted() { |
179 |
- let searchRecord = this.$route.query.searchRecord; |
|
180 |
- if (!this.$isEmpty(searchRecord)) { |
|
181 |
- switch (searchRecord) { |
|
182 |
- case 'pic': |
|
183 |
- this.isChkAllRecord = false; |
|
184 |
- this.searchReqDTO.usePhoto = true; |
|
185 |
- this.searchReqDTO.useVideo = false; |
|
186 |
- this.searchReqDTO.useMedia = false; |
|
187 |
- this.searchReqDTO.useNews = false; |
|
188 |
- break; |
|
189 |
- case 'video': |
|
190 |
- this.isChkAllRecord = false; |
|
191 |
- this.searchReqDTO.usePhoto = false; |
|
192 |
- this.searchReqDTO.useVideo = true; |
|
193 |
- this.searchReqDTO.useMedia = false; |
|
194 |
- this.searchReqDTO.useNews = false; |
|
195 |
- break; |
|
196 |
- case 'media': |
|
197 |
- this.isChkAllRecord = false; |
|
198 |
- this.searchReqDTO.usePhoto = false; |
|
199 |
- this.searchReqDTO.useVideo = false; |
|
200 |
- this.searchReqDTO.useMedia = true; |
|
201 |
- this.searchReqDTO.useNews = false; |
|
202 |
- break; |
|
203 |
- case 'bodo': |
|
204 |
- this.isChkAllRecord = false; |
|
205 |
- this.searchReqDTO.usePhoto = false; |
|
206 |
- this.searchReqDTO.useVideo = false; |
|
207 |
- this.searchReqDTO.useMedia = false; |
|
208 |
- this.searchReqDTO.useNews = true; |
|
209 |
- break; |
|
210 |
- default: |
|
211 |
- this.isChkAllRecord = true; |
|
212 |
- this.searchReqDTO.usePhoto = true; |
|
213 |
- this.searchReqDTO.useVideo = true; |
|
214 |
- this.searchReqDTO.useMedia = true; |
|
215 |
- this.searchReqDTO.useNews = true; |
|
216 |
- break; |
|
217 |
- } |
|
218 |
- } |
|
219 |
- |
|
220 |
- let searchText = this.$route.query.searchText; |
|
221 |
- if (searchText !== null) { |
|
222 |
- this.searchReqDTO.searchText = searchText; |
|
223 |
- } |
|
224 |
- |
|
225 |
- this.fnSearch(); // 통합검색 |
|
84 |
+ this.fnSearch(); // 초기 검색 실행 |
|
226 | 85 |
}, |
227 | 86 |
|
228 | 87 |
methods: { |
229 |
- // 초기화 |
|
230 |
- init() { |
|
231 |
- if (this.isInitialLoad) { |
|
232 |
- this.isInitialLoad = false; |
|
233 |
- } else { |
|
234 |
- if (!confirm('검색 조건을 초기화하시겠습니까?')) { |
|
235 |
- return; |
|
88 |
+ // URL 파라미터로부터 검색 조건 설정 |
|
89 |
+ loadSearchParamsFromUrl() { |
|
90 |
+ // 검색 기본 값 저장 |
|
91 |
+ let urlParams = JSON.parse(JSON.stringify(this.searchDefault)); |
|
92 |
+ let hasUrlParams = false; |
|
93 |
+ |
|
94 |
+ // searchRecord 파라미터 처리 |
|
95 |
+ let searchRecord = this.$route.query.searchRecord; |
|
96 |
+ if (!this.$isEmpty(searchRecord)) { |
|
97 |
+ hasUrlParams = true; |
|
98 |
+ |
|
99 |
+ switch (searchRecord) { |
|
100 |
+ case 'pic': |
|
101 |
+ urlParams.usePhoto = true; |
|
102 |
+ urlParams.useVideo = false; |
|
103 |
+ urlParams.useMedia = false; |
|
104 |
+ urlParams.useNews = false; |
|
105 |
+ break; |
|
106 |
+ case 'video': |
|
107 |
+ urlParams.usePhoto = false; |
|
108 |
+ urlParams.useVideo = true; |
|
109 |
+ urlParams.useMedia = false; |
|
110 |
+ urlParams.useNews = false; |
|
111 |
+ break; |
|
112 |
+ case 'media': |
|
113 |
+ urlParams.usePhoto = false; |
|
114 |
+ urlParams.useVideo = false; |
|
115 |
+ urlParams.useMedia = true; |
|
116 |
+ urlParams.useNews = false; |
|
117 |
+ break; |
|
118 |
+ case 'bodo': |
|
119 |
+ urlParams.usePhoto = false; |
|
120 |
+ urlParams.useVideo = false; |
|
121 |
+ urlParams.useMedia = false; |
|
122 |
+ urlParams.useNews = true; |
|
123 |
+ break; |
|
124 |
+ default: |
|
125 |
+ urlParams.usePhoto = true; |
|
126 |
+ urlParams.useVideo = true; |
|
127 |
+ urlParams.useMedia = true; |
|
128 |
+ urlParams.useNews = true; |
|
129 |
+ break; |
|
236 | 130 |
} |
237 | 131 |
} |
238 | 132 |
|
239 |
- this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
240 |
- this.isChkAllRecord = true; |
|
241 |
- this.isChkAllScope = true; |
|
133 |
+ // searchText 파라미터 처리 |
|
134 |
+ let searchText = this.$route.query.searchText; |
|
135 |
+ if (searchText !== null && searchText !== undefined) { |
|
136 |
+ hasUrlParams = true; |
|
137 |
+ urlParams.searchText = searchText; |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ // URL 파라미터가 있으면 저장 |
|
141 |
+ if (hasUrlParams) { |
|
142 |
+ this.urlParamsDefault = urlParams; |
|
143 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(urlParams)); |
|
144 |
+ } |
|
145 |
+ }, |
|
146 |
+ |
|
147 |
+ // 검색 폼 컴포넌트에서 검색 버튼 클릭 시 호출되는 메소드 |
|
148 |
+ handleSearch(formData) { |
|
149 |
+ this.searchReqDTO = formData; |
|
150 |
+ this.fnSearch(); |
|
151 |
+ }, |
|
152 |
+ |
|
153 |
+ // 검색 폼 컴포넌트에서 초기화 버튼 클릭 시 호출되는 메소드 |
|
154 |
+ handleReset() { |
|
155 |
+ // URL 파라미터가 있으면 그 값 사용, 없으면 기본값 사용 |
|
156 |
+ if (this.urlParamsDefault) { |
|
157 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.urlParamsDefault)); |
|
158 |
+ } else { |
|
159 |
+ this.searchReqDTO = JSON.parse(JSON.stringify(this.searchDefault)); |
|
160 |
+ } |
|
242 | 161 |
|
243 | 162 |
this.searchResult = []; // 검색결과 초기화 |
163 |
+ this.fnSearch(); // 초기화 후 검색 실행 |
|
244 | 164 |
}, |
245 | 165 |
|
246 |
- // 카테고리 목록 조회 |
|
247 |
- async fnFindCategorys() { |
|
248 |
- try { |
|
249 |
- const response = await findAllByNullProc(); |
|
250 |
- this.categorys = response.data.data.ctgry; |
|
251 |
- } catch (error) { |
|
252 |
- this.categorys = []; // 카테고리 목록 초기화 |
|
253 |
- |
|
254 |
- if (error.response) { |
|
255 |
- alert(error.response.data.message); |
|
256 |
- } |
|
257 |
- console.error(error.message); |
|
258 |
- } |
|
259 |
- }, |
|
260 |
- |
|
261 |
- // 통합검색 |
|
166 |
+ // 통합검색 실행 |
|
262 | 167 |
async fnSearch() { |
263 |
- // 유효성 검사 |
|
264 |
- if (!this.searchReqDTO.usePhoto && !this.searchReqDTO.useVideo && !this.searchReqDTO.useMedia && !this.searchReqDTO.useNews) { |
|
265 |
- alert('검색 유형은 최소 한 개 이상 선택해주세요.'); |
|
266 |
- return; |
|
267 |
- } |
|
268 |
- |
|
168 |
+ this.loading = true; // 로딩 시작 |
|
269 | 169 |
try { |
270 | 170 |
const params = JSON.parse(JSON.stringify(this.searchReqDTO)); |
271 | 171 |
|
... | ... | @@ -288,37 +188,10 @@ |
288 | 188 |
alert(error.response.data.message); |
289 | 189 |
} |
290 | 190 |
console.error(error.message); |
191 |
+ } finally { |
|
192 |
+ this.loading = false; // 로딩 종료 |
|
291 | 193 |
} |
292 | 194 |
}, |
293 |
- |
|
294 |
- // 기록유형 전체 선택 여부 변경 |
|
295 |
- fnChkAllOptions(type) { |
|
296 |
- switch (type) { |
|
297 |
- case 'record': |
|
298 |
- this.searchReqDTO.usePhoto = this.isChkAllRecord; |
|
299 |
- this.searchReqDTO.useVideo = this.isChkAllRecord; |
|
300 |
- this.searchReqDTO.useMedia = this.isChkAllRecord; |
|
301 |
- this.searchReqDTO.useNews = this.isChkAllRecord; |
|
302 |
- break; |
|
303 |
- case 'scope': |
|
304 |
- this.searchReqDTO.useSj = this.isChkAllScope; |
|
305 |
- this.searchReqDTO.useCn = this.isChkAllScope; |
|
306 |
- this.searchReqDTO.useAdres = this.isChkAllScope; |
|
307 |
- break; |
|
308 |
- } |
|
309 |
- }, |
|
310 |
- |
|
311 |
- // 기록유형 선택 여부 변경 |
|
312 |
- fnChkOption(type) { |
|
313 |
- switch (type) { |
|
314 |
- case 'record': |
|
315 |
- this.isChkAllRecord = this.searchReqDTO.usePhoto && this.searchReqDTO.useVideo && this.searchReqDTO.useMedia && this.searchReqDTO.useNews; |
|
316 |
- break; |
|
317 |
- case 'scope': |
|
318 |
- this.isChkAllScope = this.searchReqDTO.useSj && this.searchReqDTO.useCn && this.searchReqDTO.useAdres; |
|
319 |
- break; |
|
320 |
- } |
|
321 |
- } |
|
322 | 195 |
}, |
323 | 196 |
}; |
324 | 197 |
</script>(파일 끝에 줄바꿈 문자 없음) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?