Skip to content

Commit ab44228

Browse files
Merge pull request #65 from full-ownership/feature/search
feat : 자동완성검색 by Trie 알고리즘
2 parents 2797ad8 + 10f8f67 commit ab44228

File tree

3 files changed

+77
-49
lines changed

3 files changed

+77
-49
lines changed

src/stores/mapCard.js

-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export const useHouseInfoStore = defineStore('houseInfo', {
7373
console.log(endpoint)
7474
// API 호출
7575
const response = await apiClient.get(endpoint);
76-
7776
this.houseDeals = response.data.data; // 응답 데이터를 상태에 저장
7877
console.log("거래 정보 데이터:", response.data.data);
7978
} catch (error) {
@@ -84,12 +83,10 @@ export const useHouseInfoStore = defineStore('houseInfo', {
8483
async fetchHouseNames() {
8584
try {
8685
const endpoint = `/api/house-info/building-name`;
87-
console.log('이름 가져오는 맵카드');
8886
console.log(endpoint)
8987
// API 호출
9088
const response = await apiClient.get(endpoint);
9189
this.houseNames = response.data.data; // 응답 데이터를 상태에 저장
92-
console.log("이름데이터 ", response.data.data);
9390

9491
} catch (error) {
9592
console.error("이름데이터를 가져오는데 실패했습니다:", error);

src/views/CardView.vue

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ defineProps({
1919
// 랜덤 이미지를 설정하는 변수
2020
const randomImg = new URL(`../assets/img/home/home (${Math.floor(Math.random() * 21) + 1}).jpeg`, import.meta.url).href;
2121
22-
console.log(randomImg)
2322
</script>
2423
2524
<style scoped>

src/views/MapView.vue

+77-45
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ const state = reactive({
302302
303303
const search = () => {
304304
console.log(state.검색어)
305-
console.log('검색어')
306305
applyFilter1()
307306
}
308307
@@ -318,12 +317,10 @@ const toggleSlider = (filter) => {
318317
};
319318
320319
const applyFilter1 = async() => {
321-
322320
const query1 = { buildingUse: '아파트',
323321
fromArea: state.면적[0],
324322
toArea:state.면적[1],
325323
keyword:state.검색어 }
326-
327324
const queryString1 = new URLSearchParams(query1).toString();
328325
await fetchData(queryString1); // 데이터 로드
329326
};
@@ -340,7 +337,6 @@ const navigateTo = (param) => {
340337
router.push({ name: 'map', params: { param } }); // 이름과 params를 명확히 지정
341338
};
342339
343-
344340
//*상세 정보 불러오는 곳
345341
const selectedHouse = ref(null); // 반드시 ref로 선언
346342
@@ -364,7 +360,7 @@ const selectHouse = (house) => {
364360
365361
const findDealsByAptseq = async (aptSeq) => {
366362
try {
367-
console.log(`Fetching deals for aptSeq: ${aptSeq}`);
363+
// console.log(`Fetching deals for aptSeq: ${aptSeq}`);
368364
await houseInfoStore.fetchHouseDeals(aptSeq); // Pinia 스토어 호출
369365
370366
} catch (error) {
@@ -410,7 +406,6 @@ class TrieNode {
410406
}
411407
return this._collectWords(node, prefix);
412408
}
413-
414409
_collectWords(node, prefix) {
415410
const results = [];
416411
if (node.isEndOfWord) {
@@ -435,53 +430,82 @@ onMounted(async () => {
435430
houseNames.value = Array.isArray(houseInfoStore.houseNames?.data)
436431
? houseInfoStore.houseNames.data
437432
: [];
438-
439-
// 트라이에 이름 삽입
440-
console.log("트라이가 생성전", trie);
441-
console.log('houseNames.value의 타입:', Array.isArray(houseNames.value) ? '배열' : typeof houseNames.value);
442-
console.log('houseNames.value의 타입:', Array.isArray(houseNames.value) ? '배열' : typeof houseNames.value);
443433
for (const name of houseInfoStore.houseNames) {
444434
if (name?.aptNm) { // aptNm이 존재하는지 확인
445435
trie.insert(name.aptNm);
446-
console.log(`삽입된 이름: ${name.aptNm}`);
447436
} else {
448437
console.warn("aptNm이 없는 데이터:", name);
449438
}
450439
}
451-
452-
console.log("트라이가 생성되었습니다:", trie);
453440
});
454441
455442
// 검색 처리
443+
// const updateSearchResults = () => {
444+
// console.log('검색처리중')
445+
// if (!searchQuery.value || searchQuery.value.trim() === "") {
446+
// filteredNames.value = [];
447+
// console.log("검색어가 비어 있습니다.");
448+
// return;
449+
// }
450+
// filteredNames.value = trie.search(searchQuery.value.trim());
451+
// };
456452
const updateSearchResults = () => {
457-
console.log('검색처리중')
458-
if (!searchQuery.value || searchQuery.value.trim() === "") {
453+
if (!searchQuery.value.trim()) {
459454
filteredNames.value = [];
460-
console.log("검색어가 비어 있습니다.");
461455
return;
462456
}
463457
464-
filteredNames.value = trie.search(searchQuery.value.trim());
465-
console.log("검색 결과:", JSON.stringify(filteredNames.value)); // 일치하는 결과 콘솔 출력
458+
const results = [];
459+
let node = trie.root;
460+
const prefix = searchQuery.value.trim();
461+
462+
for (const char of prefix) {
463+
if (!node.children[char]) {
464+
filteredNames.value = []; // 검색어에 맞는 결과가 없으면 초기화
465+
return;
466+
}
467+
node = node.children[char];
468+
}
469+
470+
// 결과를 최대 5개까지만 수집
471+
const collectWords = (currentNode, currentWord) => {
472+
if (results.length >= 5) return; // 5개를 찾으면 종료
473+
if (currentNode.isEndOfWord) {
474+
results.push(currentWord);
475+
}
476+
for (const [char, childNode] of Object.entries(currentNode.children)) {
477+
collectWords(childNode, currentWord + char);
478+
}
479+
};
480+
481+
collectWords(node, prefix);
482+
filteredNames.value = results; // 결과 저장
466483
};
484+
485+
const selectKeyword = (name) =>{
486+
searchQuery.value=name
487+
}
488+
489+
490+
467491
</script>
468492
<template>
469493
<div class="flex flex-row items-center w-full h-[100vh] overflow-hidden ">
470494
<!-- 지도 및 필터 영역 -->
471-
<div class="flex flex-col justify-start w-full h-full mt-40">
495+
<div class="relative flex flex-col justify-start w-full h-full mt-40">
472496
<!-- 필터 전체 버튼 -->
473-
<div class="flex flex-row items-center py-4 h-14 border-b border-gray-200 z-100">
474-
<!--검색 창-->
475-
<div class="relative w-[370px] ml-4 mr-2 ">
497+
<div class="flex flex-row items-center py-4 h-14 border-b border-gray-200 z-100 relative">
498+
<!--검색 창-->
499+
<div class="w-[370px] ml-4 mr-2 relative justify-center">
476500
<input
477501
v-model="searchQuery"
478502
type="text"
479503
@input="updateSearchResults"
480504
placeholder="찾고자하는 아파트 이름을 입력하세요"
481-
class="absolute w-full h-8 px-4 pr-10 text-sm text-gray-700 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"/>
505+
class="w-full h-8 px-4 pr-10 text-sm text-gray-700 border border-gray-300 rounded-lg shadow-sm focus:outline-none "/>
482506
<button
483507
type="button"
484-
class="absolute inset-y-0 right-0 flex items-center px-3 text-gray-500 hover:text-gray-700"
508+
class="absolute flex justify-center right-0 top-2 px-3 text-gray-500 hover:text-gray-700"
485509
@click="search">
486510
<svg
487511
class="w-4 h-4"
@@ -498,19 +522,24 @@ const updateSearchResults = () => {
498522
</svg>
499523
</button>
500524
<!-- 검색 결과 -->
501-
<div v-if="filteredNames.length > 0" class="absolute bg-yellow-400 z-100">
502-
<p>검색 결과:</p>
525+
</div>
526+
<!-- 검색 결과 -->
527+
<div v-if="filteredNames.length > 0" class="absolute w-[360px] h-auto max-h-96 z-100 top-12 left-4 shadow-lg rounded-md border border-gray-300">
528+
<!-- 결과 없음 메시지 -->
529+
<div class="bg-white text-gray-700 px-4 py-2 font-semibold border-b border-gray-300">
503530
<ul>
504-
<li v-for="(name, index) in filteredNames" :key="index">
505-
{{ name }}
506-
</li>
507-
</ul>
508-
</div>
509-
<div v-else>
510-
<p>일치하는 결과가 없습니다.</p>
531+
<li v-for="(name, index) in filteredNames"
532+
:key="index"
533+
class="px-4 py-2 hover:bg-blue-100 cursor-pointer"
534+
@click="selectKeyword(name)">
535+
{{ name }}
536+
</li>
537+
</ul>
511538
</div>
539+
<!-- 검색 결과 리스트 -->
512540
</div>
513541
542+
514543
<div class="relative inline-block text-left ml-2">
515544
<!-- 버튼 -->
516545
<button
@@ -587,6 +616,7 @@ const updateSearchResults = () => {
587616
</button>
588617
</div>
589618
</div>
619+
590620
</div>
591621
<!-- 필요한 필터 수 만큼 반복 -->
592622
<button type="button" class="relative inline-block text-left ml-2 h-8 px-2 py-2 bg-white border border-gray-300 shadow-sm focus:ring-indigo-500">
@@ -596,22 +626,24 @@ const updateSearchResults = () => {
596626
</button>
597627
</div>
598628
<!-- 리스트와 지도 영역 -->
599-
<div class="flex flex-row h-full font-Pretendard text-gray-600 relaitvie">
629+
630+
631+
<div class="flex h-full font-Pretendard text-gray-600 z-10">
600632
<div class="flex flex-col h-full rounded-lg">
601-
<div class="flex flex-row p-2 text-s bg-blue-100">
602-
<p class="mr-1 ml-2 cursor-pointer font-bold">인기순</p>
603-
<p class="mr-1 cursor-pointer font-bold">가격순</p>
604-
<p class="mr-1 cursor-pointer font-bold">면적순</p>
605-
<FilterButton></FilterButton>
606-
</div>
607633
<!-- 목록 영역 추가할 수 있습니다 -->
608-
<div class="p-2 overflow-y-auto">
609-
<div class="text-center ">
634+
<div class="p-2 overflow-y-auto ">
635+
636+
<div class="flex flex-row p-2 text-s h-[24px] fixed bg-white-800 z-20">
637+
<p class="mr-1 ml-2 cursor-pointer font-bold">인기순</p>
638+
<p class="mr-1 cursor-pointer font-bold">가격순</p>
639+
<p class="mr-1 cursor-pointer font-bold">면적순</p>
640+
</div>
641+
<div class="text-center">
610642
<div v-for="name in houseNames" :key="name.aptSeq">
611643
{{ name.aptNm }}
612644
</div>
613-
</div>
614-
<div v-for="house in houseInfos" :key="house.id" >
645+
</div>
646+
<div v-for="house in houseInfos" :key="house.id" class="z-10">
615647
<CardView
616648
:jibun="house.jibun"
617649
:imgUrl="house.imgUrl"

0 commit comments

Comments
 (0)