import { create } from "zustand"; import Taro from "@tarojs/taro"; import { fetchUserProfile, updateUserProfile, UserInfoType, checkNicknameChangeStatus as checkNicknameChangeStatusApi, NicknameChangeStatus, updateNickname as updateNicknameApi, } from "@/services/userService"; import evaluateService, { LastTimeTestResult, } from "@/services/evaluateService"; import { useListStore } from "./listStore"; export interface UserState { user: UserInfoType | {}; fetchUserInfo: () => Promise; updateUserInfo: (userInfo: Partial) => void; nicknameChangeStatus: Partial; checkNicknameChangeStatus: (force?: boolean) => void; updateNickname: (nickname: string) => void; // NTRP 测试结果缓存 lastTestResult: LastTimeTestResult | null; fetchLastTestResult: () => Promise; } const getTimeNextDate = (time: string) => { const date = new Date(time); date.setDate(date.getDate() + 1); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; // 请求锁,避免重复调用 let isFetchingLastTestResult = false; let isCheckingNicknameStatus = false; const CITY_CACHE_KEY = "USER_SELECTED_CITY"; export const useUser = create()((set) => ({ user: {}, fetchUserInfo: async () => { try { const res = await fetchUserProfile(); const userData = res.data; set({ user: userData }); // 优先使用缓存中的城市,不使用用户信息中的位置 // 检查是否有缓存的城市 const cachedCity = (Taro as any).getStorageSync?.(CITY_CACHE_KEY); if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) { // 如果有缓存的城市,使用缓存,不更新 area console.log("[userStore] 检测到缓存的城市,使用缓存,不更新 area"); return userData; } // 只有当没有缓存时,才使用用户信息中的位置 if (userData?.last_location_province) { const listStore = useListStore.getState(); const currentArea = listStore.area; // 只有当 area 不存在时才使用用户信息中的位置 if (!currentArea) { const newArea: [string, string] = [ userData.last_location_province || "", userData.last_location_city || "", ]; listStore.updateArea(newArea); // 保存到缓存 useUser.getState().updateCache(newArea); } } return userData; } catch (error) { console.error("获取用户信息失败:", error); return undefined; } }, // 更新缓存 updateCache: async (newArea: [string, string]) => { try { (Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea); } catch (error) { console.error("保存城市缓存失败:", error); } }, updateUserInfo: async (userInfo: Partial) => { try { // 先更新后端 await updateUserProfile(userInfo); // 然后立即更新本地状态(乐观更新) set((state) => { const newUser = { ...state.user, ...userInfo }; // 当 userLastLocationProvince 更新时,同步更新 area if (userInfo.last_location_province) { const listStore = useListStore.getState(); const currentArea = listStore.area; // 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新 if ( !currentArea || currentArea[1] !== userInfo.last_location_province ) { const newArea: [string, string] = [ userInfo.last_location_province || "", userInfo.last_location_city || "", ]; listStore.updateArea(newArea); } } return { user: newUser }; }); // 不再每次都重新获取完整用户信息,减少请求次数 // 只有在更新头像等需要服务器返回新URL的字段时才需要重新获取 // 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo } catch (error) { console.error("更新用户信息失败:", error); throw error; } }, nicknameChangeStatus: {}, checkNicknameChangeStatus: async (force = false) => { // 如果正在请求中,直接返回,避免重复调用 if (isCheckingNicknameStatus) { return; } // 如果已经有状态数据且不是强制更新,跳过,避免重复调用 if (!force) { const currentState = useUser.getState(); if ( currentState.nicknameChangeStatus && Object.keys(currentState.nicknameChangeStatus).length > 0 ) { return; } } try { isCheckingNicknameStatus = true; const res = await checkNicknameChangeStatusApi(); const { next_period_start_time } = res.data; set({ nicknameChangeStatus: { ...res.data, next_period_start_date: getTimeNextDate(next_period_start_time), }, }); } catch (error) { console.error("检查昵称变更状态失败:", error); } finally { isCheckingNicknameStatus = false; } }, updateNickname: async (nickname) => { try { await updateNicknameApi(nickname); // 更新昵称后强制更新状态 await useUser.getState().checkNicknameChangeStatus(true); set((state) => ({ user: { ...state.user, nickname }, })); } catch (error) { console.error("更新用户昵称失败:", error); } }, // NTRP 测试结果缓存 lastTestResult: null, fetchLastTestResult: async () => { // 如果已经有缓存数据,直接返回,避免重复调用 const currentState = useUser.getState(); if (currentState.lastTestResult) { return currentState.lastTestResult; } // 如果正在请求中,等待请求完成,避免重复调用 if (isFetchingLastTestResult) { // 等待请求完成,最多等待 3 秒 let waitCount = 0; while (isFetchingLastTestResult && waitCount < 30) { await new Promise((resolve) => setTimeout(resolve, 100)); waitCount++; const state = useUser.getState(); if (state.lastTestResult) { return state.lastTestResult; } } return null; } try { isFetchingLastTestResult = true; const res = await evaluateService.getLastResult(); if (res.code === 0) { set({ lastTestResult: res.data }); return res.data; } return null; } catch (error) { console.error("获取NTRP测试结果失败:", error); return null; } finally { isFetchingLastTestResult = false; } }, })); export const useUserInfo = () => useUser((state) => state.user); export const useNicknameChangeStatus = () => useUser((state) => state.nicknameChangeStatus); export const useUserActions = () => useUser((state) => ({ fetchUserInfo: state.fetchUserInfo, updateCache: state.updateCache, updateUserInfo: state.updateUserInfo, checkNicknameChangeStatus: state.checkNicknameChangeStatus, updateNickname: state.updateNickname, fetchLastTestResult: state.fetchLastTestResult, })); export const useLastTestResult = () => useUser((state) => state.lastTestResult);