From 0e69218710c879a92a59226fd62c4dc065d70f11 Mon Sep 17 00:00:00 2001 From: sb Date: Sat, 11 Jul 2026 13:26:42 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=A7=80=EB=8F=84=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=EB=A1=9C=20=EC=A0=84=ED=99=98=20+=20=ED=99=95?= =?UTF-8?q?=EB=8C=80/=EC=B6=95=EC=86=8C=C2=B7=ED=98=84=EC=9E=AC=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20(=EB=84=A4=EC=9D=B4=EB=B2=84=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=9C=A0=EC=A7=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 홈 지도를 Kakao Maps JS SDK 로 교체. ZoomControl(확대/축소)과 현재위치 버튼(@capacitor/geolocation → 파란 점 표시) 추가. naverMap.ts / NaverMap.vue 는 미사용으로 보존. 시뮬레이터에서 렌더·현재위치 확인. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 7 +- package-lock.json | 19 ++++ package.json | 1 + src/components/KakaoMap.vue | 193 ++++++++++++++++++++++++++++++++++++ src/env.d.ts | 2 + src/lib/kakaoMap.ts | 41 ++++++++ src/pages/HomePage.vue | 6 +- src/types/kakao-maps.d.ts | 67 +++++++++++++ 8 files changed, 332 insertions(+), 4 deletions(-) create mode 100644 src/components/KakaoMap.vue create mode 100644 src/lib/kakaoMap.ts create mode 100644 src/types/kakao-maps.d.ts diff --git a/.env.example b/.env.example index b1ae6da..c8226b4 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,12 @@ # 백엔드 API 주소 (dognation_BT) VITE_API_BASE_URL=http://localhost:8080 -# 네이버 지도 (네이버 클라우드 플랫폼 > Maps 에서 발급) +# 지도: 현재 카카오 지도 사용 (홈 화면). 네이버 키는 참고용으로 남겨둠. +# 카카오 지도 (Kakao Developers > 내 애플리케이션 > 앱 키 > JavaScript 키) +# 콘솔 > 플랫폼 > Web 에 서비스 도메인 등록 필요 (개발: http://localhost:9000) +VITE_KAKAO_MAP_KEY=your_kakao_javascript_key + +# 네이버 지도 (네이버 클라우드 플랫폼 > Maps) — 현재 미사용, 코드는 유지 VITE_NAVER_MAP_CLIENT_ID=your_ncp_key_id # 신규 키는 ncpKeyId(기본), 구형 키면 ncpClientId 로 변경 # VITE_NAVER_MAP_AUTH_PARAM=ncpKeyId diff --git a/package-lock.json b/package-lock.json index 143ff42..d183fa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@capacitor-community/apple-sign-in": "^7.1.0", "@capacitor/app": "^8.0.0", "@capacitor/core": "^8.3.4", + "@capacitor/geolocation": "^8.2.0", "@quasar/extras": "^1.16.12", "@stomp/stompjs": "^7.3.0", "pinia": "^2.3.0", @@ -158,6 +159,18 @@ "tslib": "^2.1.0" } }, + "node_modules/@capacitor/geolocation": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-8.2.0.tgz", + "integrity": "sha512-N29QcoIPmme0xSxRkm7+3hjoHp6mBAOarxecvtCCZKyOBeKiJsFUq981cezg2XWBa6fhCXJMCCjQPngKK/dIag==", + "license": "MIT", + "dependencies": { + "@capacitor/synapse": "^1.0.4" + }, + "peerDependencies": { + "@capacitor/core": ">=8.0.0" + } + }, "node_modules/@capacitor/ios": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-8.4.1.tgz", @@ -168,6 +181,12 @@ "@capacitor/core": "^8.4.0" } }, + "node_modules/@capacitor/synapse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@capacitor/synapse/-/synapse-1.0.4.tgz", + "integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==", + "license": "ISC" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", diff --git a/package.json b/package.json index e4c813a..b4f3dac 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@capacitor-community/apple-sign-in": "^7.1.0", "@capacitor/app": "^8.0.0", "@capacitor/core": "^8.3.4", + "@capacitor/geolocation": "^8.2.0", "@quasar/extras": "^1.16.12", "@stomp/stompjs": "^7.3.0", "pinia": "^2.3.0", diff --git a/src/components/KakaoMap.vue b/src/components/KakaoMap.vue new file mode 100644 index 0000000..6e36440 --- /dev/null +++ b/src/components/KakaoMap.vue @@ -0,0 +1,193 @@ + + + + + \ No newline at end of file diff --git a/src/env.d.ts b/src/env.d.ts index 67d58be..3535c9c 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -11,6 +11,7 @@ interface ImportMetaEnv { readonly VITE_API_BASE_URL: string readonly VITE_NAVER_MAP_CLIENT_ID: string readonly VITE_NAVER_MAP_AUTH_PARAM?: string + readonly VITE_KAKAO_MAP_KEY: string } interface ImportMeta { @@ -19,4 +20,5 @@ interface ImportMeta { interface Window { naver: typeof naver + kakao: typeof kakao } diff --git a/src/lib/kakaoMap.ts b/src/lib/kakaoMap.ts new file mode 100644 index 0000000..f344311 --- /dev/null +++ b/src/lib/kakaoMap.ts @@ -0,0 +1,41 @@ +// 카카오 지도 JS SDK 동적 로더 (싱글턴) +// JavaScript 키는 Kakao Developers > 내 애플리케이션 > 앱 키 > JavaScript 키. +// .env 의 VITE_KAKAO_MAP_KEY 로 주입. 콘솔 > 플랫폼 > Web 에 서비스 도메인 등록 필요 +// (개발: http://localhost:9000 / 라이브리로드 IP, 배포: 실제 도메인·capacitor 스킴). +let loadPromise: Promise | null = null + +export function loadKakaoMaps(): Promise { + if (typeof window !== 'undefined' && window.kakao?.maps) { + return Promise.resolve(window.kakao) + } + if (loadPromise) { + return loadPromise + } + + const appKey = import.meta.env.VITE_KAKAO_MAP_KEY + + loadPromise = new Promise((resolve, reject) => { + if (!appKey) { + reject(new Error('VITE_KAKAO_MAP_KEY 가 설정되지 않았습니다.')) + return + } + const script = document.createElement('script') + // autoload=false → 스크립트 로드 후 kakao.maps.load 로 명시적으로 초기화한다. + script.src = `https://dapi.kakao.com/v2/maps/sdk.js?appkey=${appKey}&autoload=false` + script.async = true + script.onload = () => { + // 키/도메인이 유효하지 않으면 load 콜백이 호출되지 않을 수 있어 타임아웃으로 방어. + const timer = setTimeout( + () => reject(new Error('카카오 지도 초기화 실패 · 키/도메인 등록을 확인하세요.')), + 8000, + ) + window.kakao.maps.load(() => { + clearTimeout(timer) + resolve(window.kakao) + }) + } + script.onerror = () => reject(new Error('카카오 지도 SDK 를 불러오지 못했습니다.')) + document.head.appendChild(script) + }) + return loadPromise +} \ No newline at end of file diff --git a/src/pages/HomePage.vue b/src/pages/HomePage.vue index 5358b92..0126a9b 100644 --- a/src/pages/HomePage.vue +++ b/src/pages/HomePage.vue @@ -1,8 +1,8 @@