test/1114/app/store/weatherStore.ts

142 lines
4.5 KiB
TypeScript

import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { WeatherAPI } from '@/services/weatherApi';
const CACHE_EXPIRY = 10 * 60 * 1000;
export interface Location {
name: string;
country: string;
region: string;
lat: string;
lon: string;
timezone_id: string
localtime: string;
localtime_epoch: number;
utc_offset: string;
}
export interface Current {
observation_time: string;
temperature: number;
weather_code: number;
weather_icons: string[];
weather_descriptions: string[];
wind_speed: number;
wind_degree: number;
wind_dir: string;
pressure: number;
precip: number;
humidity: number;
cloudcover: number;
feelslike: number;
uv_index: number;
visibility: number;
is_day: string;
}
export interface WeatherData {
request?: {
type: string;
query: string;
language: string;
unit: string;
};
location: Location;
current: Current;
}
export interface WeatherCache {
data: WeatherData;
timestamp: number;
}
export interface WeatherStore {
currentWeather: WeatherData | null;
weatherCache: Map<string, WeatherCache>;
isLoading: boolean;
error: string | null;
// Actions
setCurrentWeather: (weather: WeatherData | null) => void;
getWeatherFromCache: (city: string) => WeatherData | null;
cacheWeather: (city: string, weather: WeatherData) => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
reset: () => void;
// API Actions
searchWeather: (city: string) => Promise<void>;
refreshWeather: () => Promise<void>;
}
export const useWeatherStore = create<WeatherStore>()(
persist(
(set,get)=>({
currentWeather:null,
weatherCache:new Map(),
isLoading:false,
error:null,
setCurrentWeather:(weather)=>set({currentWeather:weather}),
getWeatherFromCache:(city)=>{
const cache = get().weatherCache.get(city.toLowerCase());
if(!cache) return null;
const isExpired = Date.now() - cache.timestamp > CACHE_EXPIRY;
return isExpired ? null : cache.data;
},
cacheWeather:(city,weather)=>set((state)=>{
const newCache = new Map(state.weatherCache);
newCache.set(city.toLowerCase(),{data:weather,timestamp:Date.now()});
return {weatherCache:newCache};
}),
setLoading:(loading)=>set({isLoading:loading}),
setError:(error)=>set({error:error}),
reset:()=>set({currentWeather:null,weatherCache:new Map(),isLoading:false,error:null}),
searchWeather:async(city:string)=>{
try{
set({isLoading:true,error:null});
const cachedWeather = get().weatherCache.get(city.toLowerCase());
if(cachedWeather){
set({currentWeather:cachedWeather.data,isLoading:false});
return;
}
const weatherData = await WeatherAPI.getWeather(city);
set({currentWeather:weatherData,isLoading:false});
get().cacheWeather(city,weatherData);
}catch(error){
set({error:error instanceof Error ? error.message : '获取失败'});
}
},
refreshWeather:async()=>{
const currentWeather = get().currentWeather;
if(!currentWeather) return;
try{
set({isLoading:true,error:null});
const city = currentWeather.location.name;
const weatherData = await WeatherAPI.getWeather(city);
set({currentWeather:weatherData,isLoading:false});
get().cacheWeather(currentWeather.location.name,weatherData);
}catch(error){
set({error:error instanceof Error ? error.message : '刷新失败'});
set({isLoading:false});
}
}
}
),
{
name:'weatherStore',
storage:createJSONStorage(()=>localStorage),
partialize:(state)=>({
weatherCache:Array.from(state.weatherCache.entries())
}),
onRehydrateStorage:(state)=>{
if(state && Array.isArray(state.weatherCache)){
state.weatherCache = new Map(state.weatherCache as any);
}
}
}
)
)