import { ref, computed } from 'vue' import { defineStore } from 'pinia' import { getUsdcBalance, formatUsdcBalance, getUserInfo } from '@/api/user' import { getUserWsUrl } from '@/api/request' import { UserSdk, type BalanceData } from '../../sdk/userSocket' export interface UserInfo { /** 用户 ID(API 可能返回 id 或 ID) */ id?: number | string ID?: number headerImg?: string nickName?: string userName?: string [key: string]: unknown } const STORAGE_KEY = 'poly-user' function loadStored(): { token: string; user: UserInfo } | null { try { const raw = localStorage.getItem(STORAGE_KEY) if (!raw) return null return JSON.parse(raw) as { token: string; user: UserInfo } } catch { return null } } function saveToStorage(token: string, user: UserInfo) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ token, user })) } catch { // } } function clearStorage() { try { localStorage.removeItem(STORAGE_KEY) } catch { // } } export const useUserStore = defineStore('user', () => { const stored = loadStored() const token = ref(stored?.token ?? '') const user = ref(stored?.user ?? null) const isLoggedIn = computed(() => !!token.value && !!user.value) const avatarUrl = computed(() => user.value?.headerImg ?? '') /** 钱包余额显示,如 "0.00",可从接口或 UserSocket 推送更新 */ const balance = ref('0.00') let userSdkRef: UserSdk | null = null // 若从 storage 恢复登录态,自动连接 UserSocket if (stored?.token && stored?.user) { // 延迟到 nextTick 后连接,避免 store 未完全初始化 Promise.resolve().then(() => connectUserSocket()) } function connectUserSocket() { if (!token.value) return disconnectUserSocket() const sdk = new UserSdk({ url: getUserWsUrl(), token: token.value, autoReconnect: true, reconnectInterval: 2000, }) sdk.onBalanceUpdate((data: BalanceData) => { const avail = data.available ?? data.amount if (avail != null) { balance.value = formatUsdcBalance(String(avail)) } }) sdk.onConnect(() => { console.log('[UserStore] UserSocket 已连接') }) sdk.onDisconnect(() => { console.log('[UserStore] UserSocket 已断开') }) sdk.onError((e) => { console.error('[UserStore] UserSocket 错误:', e) }) userSdkRef = sdk sdk.connect() } function disconnectUserSocket() { if (userSdkRef) { userSdkRef.disconnect() userSdkRef = null } } function setUser(loginData: { token?: string; user?: UserInfo }) { const t = loginData.token ?? '' const raw = loginData.user ?? null token.value = t if (raw) { const rawId = raw.ID ?? raw.id const numId = typeof rawId === 'number' ? rawId : rawId != null ? parseInt(String(rawId), 10) : undefined user.value = { ...raw, id: rawId ?? numId, ID: Number.isFinite(numId) ? numId : raw.ID, } } else { user.value = null } if (t && user.value) { saveToStorage(t, user.value) connectUserSocket() } else { clearStorage() disconnectUserSocket() } } function logout() { disconnectUserSocket() token.value = '' user.value = null clearStorage() } /** 鉴权请求头:x-token 与 x-user-id,未登录时返回 undefined */ function getAuthHeaders(): Record | undefined { if (!token.value) return undefined const uid = user.value?.id ?? user.value?.ID return { 'x-token': token.value, ...(uid != null && uid !== '' && { 'x-user-id': String(uid) }), } } /** 请求 USDC 余额(需已登录),amount/available 除以 1000000 后更新余额显示 */ async function fetchUsdcBalance() { const headers = getAuthHeaders() if (!headers) return try { const res = await getUsdcBalance(headers) if (res.code === 0 && res.data) { balance.value = formatUsdcBalance(res.data.available) } } catch (e) { console.error('[fetchUsdcBalance] 请求失败:', e) } } /** 请求用户信息(需已登录),更新 store 中的 user */ async function fetchUserInfo() { const headers = getAuthHeaders() if (!headers) return try { const res = await getUserInfo(headers) console.log('[fetchUserInfo] 接口响应:', JSON.stringify(res, null, 2)) const data = res.data as Record | undefined // 接口返回 data.userInfo 或 data.user,取实际用户对象;若仍含 userInfo 则再取一层 let u = (data?.userInfo ?? data?.user ?? data) as Record if (u?.userInfo && (u.ID == null && u.id == null)) { u = u.userInfo as Record } if ((res.code === 0 || res.code === 200) && u) { const rawId = u.ID ?? u.id const numId = typeof rawId === 'number' ? rawId : rawId != null ? parseInt(String(rawId), 10) : undefined user.value = { ...u, userName: (u.userName ?? u.username) as string | undefined, nickName: (u.nickName ?? u.nickname) as string | undefined, headerImg: (u.headerImg ?? u.avatar ?? u.avatarUrl) as string | undefined, id: (rawId ?? numId) as number | string | undefined, ID: Number.isFinite(numId) ? numId : undefined, } as UserInfo if (token.value && user.value) saveToStorage(token.value, user.value) } } catch (e) { console.error('[fetchUserInfo] 请求失败:', e) } } return { token, user, isLoggedIn, avatarUrl, balance, setUser, logout, getAuthHeaders, fetchUsdcBalance, fetchUserInfo, connectUserSocket, disconnectUserSocket, } })