diff --git a/src/stores/useWeatherStore.js b/src/stores/useWeatherStore.js index 862f687..407a2a4 100644 --- a/src/stores/useWeatherStore.js +++ b/src/stores/useWeatherStore.js @@ -1,9 +1,8 @@ /* 작성자 : 서지희 작성일 : 2025-04-04 - 수정자 : - 수정일 : - 설명 : 위치 기반으로 날씨를 조회하고, 오늘의 최저/최고 기온과 현재 날씨 아이콘/설명을 저장합니다. + 수정일 : 2025-04-07 + 설명 : 위치 기반으로 날씨를 조회하고, 10분 단위 캐시로 저장합니다. */ import { ref } from 'vue'; import { defineStore } from 'pinia'; @@ -20,67 +19,96 @@ export const useWeatherStore = defineStore('weather', () => { const dailyWeatherList = ref([]); const getWeatherInfo = async () => { - navigator.geolocation.getCurrentPosition(async position => { - const lat = position.coords.latitude; - const lon = position.coords.longitude; + return new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(async position => { + const lat = position.coords.latitude; + const lon = position.coords.longitude; - try { - const res = await $api.get(`/weather`, { - params: { lat, lon }, - withCredentials: true, - }); + try { + const res = await $api.get(`/weather`, { + params: { lat, lon }, + withCredentials: true, + }); - if (!res?.data?.data) return; + if (!res?.data?.data) return; - const resData = res.data.data; - const raw = resData.weatherInfo; - const data = JSON.parse(raw); - console.log(data.list) - if (!data || !Array.isArray(data.list) || data.list.length === 0) { - console.error('날씨 데이터 형식 오류 또는 없음:', data); - return; + const resData = res.data.data; + const raw = resData.weatherInfo; + const data = JSON.parse(raw); + if (!data || !Array.isArray(data.list)) { + console.error('날씨 데이터 형식 오류'); + return; + } + + dailyWeatherList.value = resData.dailyWeatherList; + + const now = new Date(); + const todayStr = now.toISOString().split('T')[0]; + const nowTime = now.getTime(); + + const todayList = data.list.filter(item => item.dt_txt.startsWith(todayStr)); + if (todayList.length > 0) { + const minTemp = Math.min(...todayList.map(i => i.main.temp_min)); + const maxTemp = Math.max(...todayList.map(i => i.main.temp_max)); + weather.value.tempMin = Math.round(minTemp); + weather.value.tempMax = Math.round(maxTemp); + } + + const closest = data.list.reduce((prev, curr) => { + const prevDiff = Math.abs(new Date(prev.dt_txt).getTime() - nowTime); + const currDiff = Math.abs(new Date(curr.dt_txt).getTime() - nowTime); + return currDiff < prevDiff ? curr : prev; + }); + + weather.value.icon = closest.weather[0].icon.replace(/n$/, 'd'); + weather.value.description = closest.weather[0].description; + + resolve({ weather: weather.value, dailyWeatherList: dailyWeatherList.value }); + } catch (e) { + console.error('날씨 정보 가져오기 실패:', e); + reject(e); } - - // 주간 예보 리스트 저장 - dailyWeatherList.value = resData.dailyWeatherList; - - const now = new Date(); - const nowTime = now.getTime(); - const todayStr = now.toISOString().split('T')[0]; - - // 오늘의 데이터만 필터링 - const todayList = data.list.filter(item => item.dt_txt.startsWith(todayStr)); - - if (todayList.length > 0) { - // 오늘의 최저 / 최고 기온 계산 - const minTemp = Math.min(...todayList.map(i => i.main.temp_min)); - const maxTemp = Math.max(...todayList.map(i => i.main.temp_max)); - weather.value.tempMin = Math.round(minTemp); - weather.value.tempMax = Math.round(maxTemp); - } else { - weather.value.tempMin = null; - weather.value.tempMax = null; - } - - // 현재 시간과 가장 가까운 시간대 데이터 추출 (아이콘 및 설명용) - const closest = data.list.reduce((prev, curr) => { - const prevDiff = Math.abs(new Date(prev.dt_txt).getTime() - nowTime); - const currDiff = Math.abs(new Date(curr.dt_txt).getTime() - nowTime); - return currDiff < prevDiff ? curr : prev; - }); - - weather.value.icon = closest.weather[0].icon.replace(/n$/, 'd'); - weather.value.description = closest.weather[0].description; - - } catch (e) { - console.error('날씨 정보 가져오기 실패:', e); - } + }, reject); }); }; + // 로컬스토리지 캐시 포함한 로직 + const getWeatherInfoWithCache = async () => { + const now = new Date(); + const pad = n => String(n).padStart(2, '0'); + const key = `weather_${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${Math.floor(now.getMinutes() / 10) * 10}`; + + const cached = localStorage.getItem(key); + if (cached) { + const parsed = JSON.parse(cached); + weather.value = parsed.weather; + dailyWeatherList.value = parsed.dailyWeatherList; + return; + } + + // 캐시 삭제 + Object.keys(localStorage).forEach(k => { + if (k.startsWith('weather_')) localStorage.removeItem(k); + }); + + try { + const { weather: w, dailyWeatherList: d } = await getWeatherInfo(); + localStorage.setItem(key, JSON.stringify({ weather: w, dailyWeatherList: d })); + } catch (e) { + // 오류 시 기존 로컬스토리지 값 중 가장 최신 값 사용 + const oldKey = Object.keys(localStorage).filter(k => k.startsWith('weather_')).sort().pop(); + if (oldKey) { + const fallback = JSON.parse(localStorage.getItem(oldKey)); + weather.value = fallback.weather; + dailyWeatherList.value = fallback.dailyWeatherList; + } + } + }; + return { weather, dailyWeatherList, getWeatherInfo, + getWeatherInfoWithCache, }; });