Files
mini-programs/src/store/userStore.ts
2025-12-08 13:32:12 +08:00

146 lines
4.9 KiB
TypeScript

import { create } from "zustand";
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<UserInfoType | undefined>;
updateUserInfo: (userInfo: Partial<UserInfoType>) => void;
nicknameChangeStatus: Partial<NicknameChangeStatus>;
checkNicknameChangeStatus: () => void;
updateNickname: (nickname: string) => void;
// NTRP 测试结果缓存
lastTestResult: LastTimeTestResult | null;
fetchLastTestResult: () => Promise<LastTimeTestResult | null>;
}
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}`;
};
export const useUser = create<UserState>()((set) => ({
user: {},
fetchUserInfo: async () => {
try {
const res = await fetchUserProfile();
const userData = res.data;
set({ user: userData });
// 当 userLastLocationProvince 更新时,同步更新 area
if (userData?.last_location_province) {
const listStore = useListStore.getState();
const currentArea = listStore.area;
// 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新
if (!currentArea || currentArea[1] !== userData.last_location_province) {
const newArea: [string, string] = ["中国", userData.last_location_province];
listStore.updateArea(newArea);
}
}
return userData;
} catch (error) {
console.error("获取用户信息失败:", error);
return undefined;
}
},
updateUserInfo: async (userInfo: Partial<UserInfoType>) => {
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];
listStore.updateArea(newArea);
}
}
return { user: newUser };
});
// 不再每次都重新获取完整用户信息,减少请求次数
// 只有在更新头像等需要服务器返回新URL的字段时才需要重新获取
// 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo
} catch (error) {
console.error("更新用户信息失败:", error);
throw error;
}
},
nicknameChangeStatus: {},
checkNicknameChangeStatus: async () => {
try {
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);
}
},
updateNickname: async (nickname) => {
try {
await updateNicknameApi(nickname);
await useUser.getState().checkNicknameChangeStatus();
set((state) => ({
user: { ...state.user, nickname },
}));
} catch (error) {
console.error("更新用户昵称失败:", error);
}
},
// NTRP 测试结果缓存
lastTestResult: null,
fetchLastTestResult: async () => {
try {
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;
}
},
}));
export const useUserInfo = () => useUser((state) => state.user);
export const useNicknameChangeStatus = () =>
useUser((state) => state.nicknameChangeStatus);
export const useUserActions = () =>
useUser((state) => ({
fetchUserInfo: state.fetchUserInfo,
updateUserInfo: state.updateUserInfo,
checkNicknameChangeStatus: state.checkNicknameChangeStatus,
updateNickname: state.updateNickname,
fetchLastTestResult: state.fetchLastTestResult,
}));
export const useLastTestResult = () => useUser((state) => state.lastTestResult);