fix(auth): 账号切换 - 切换用户后清空旧账号缓存并隔离积分响应

This commit is contained in:
ddCat
2026-07-28 08:02:59 +08:00
parent cbcdcc2be2
commit b1d8a0a9ae
4 changed files with 61 additions and 28 deletions

View File

@@ -1,32 +1,52 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { getWallet } from "@/services/api/wallet";
const WALLET_REFRESH_INTERVAL_MS = 30_000;
type WalletBalanceSnapshot = {
userId: string;
availableMicrocredits: number | null;
refreshing: boolean;
};
export function useWalletBalance(userId?: string, enabled = true) {
const [availableMicrocredits, setAvailableMicrocredits] = useState<number | null>(null);
const [refreshing, setRefreshing] = useState(false);
const activeUserId = enabled ? userId || "" : "";
const requestSequence = useRef(0);
const [snapshot, setSnapshot] = useState<WalletBalanceSnapshot>({ userId: "", availableMicrocredits: null, refreshing: false });
const refresh = useCallback(async () => {
if (!enabled || !userId) {
setAvailableMicrocredits(null);
const requestedUserId = activeUserId;
const sequence = ++requestSequence.current;
if (!requestedUserId) {
setSnapshot({ userId: "", availableMicrocredits: null, refreshing: false });
return;
}
setRefreshing(true);
setSnapshot((current) => ({
userId: requestedUserId,
availableMicrocredits: current.userId === requestedUserId ? current.availableMicrocredits : null,
refreshing: true,
}));
try {
const wallet = await getWallet(1, 1);
setAvailableMicrocredits(wallet.account.availableMicrocredits);
} catch {
// 顶栏余额是只读辅助信息,读取失败时保留上次成功值,避免短暂网络错误造成闪烁。
} finally {
setRefreshing(false);
if (sequence !== requestSequence.current) return;
if (wallet.account.userId !== requestedUserId) throw new Error("积分账户与当前用户不一致");
setSnapshot({ userId: requestedUserId, availableMicrocredits: wallet.account.availableMicrocredits, refreshing: false });
} catch (error) {
if (sequence !== requestSequence.current) return;
console.warn("积分余额刷新失败", error);
setSnapshot((current) => ({
userId: requestedUserId,
availableMicrocredits: current.userId === requestedUserId ? current.availableMicrocredits : null,
refreshing: false,
}));
}
}, [enabled, userId]);
}, [activeUserId]);
useEffect(() => {
if (!enabled || !userId) {
setAvailableMicrocredits(null);
if (!activeUserId) {
requestSequence.current += 1;
setSnapshot({ userId: "", availableMicrocredits: null, refreshing: false });
return;
}
void refresh();
@@ -39,12 +59,18 @@ export function useWalletBalance(userId?: string, enabled = true) {
window.addEventListener("wallet:updated", handleFocus);
document.addEventListener("visibilitychange", handleVisibility);
return () => {
requestSequence.current += 1;
window.clearInterval(timer);
window.removeEventListener("focus", handleFocus);
window.removeEventListener("wallet:updated", handleFocus);
document.removeEventListener("visibilitychange", handleVisibility);
};
}, [enabled, refresh, userId]);
}, [activeUserId, refresh]);
return { availableMicrocredits, refreshing, refresh };
const snapshotMatchesUser = snapshot.userId === activeUserId;
return {
availableMicrocredits: snapshotMatchesUser ? snapshot.availableMicrocredits : null,
refreshing: snapshotMatchesUser ? snapshot.refreshing : Boolean(activeUserId),
refresh,
};
}