From cdf39e85af8546878e3c2564f2b7cd9fda6da58e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Fri, 17 Jul 2026 14:11:41 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E4=BD=99=E9=A2=9D=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E5=80=92=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ai-game-creator-shell/src/App.tsx | 34 +++++++++++-------- .../tests/appSurface.test.ts | 29 +++++++++------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index 2b650855d..d2d06d4d7 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -75,7 +75,6 @@ import { selectGameCreationAppReadyTasks, } from '../../../packages/shared/src/contracts/gameCreationApp'; import type { - ProfileDashboardSummary, ProfileMudPointBalance, ProfileRechargeCenterResponse, ProfileRechargeProduct, @@ -5360,8 +5359,8 @@ export function WorkspaceLauncher({ const [runtimeConfigOpen, setRuntimeConfigOpen] = useState(false); const [pendingNonEmptyProject, setPendingNonEmptyProject] = useState(null); - const [profileDashboard, setProfileDashboard] = - useState(null); + const [walletBalance, setWalletBalance] = useState(null); + const walletBalanceRevisionRef = useRef(0); const [mudPointBalance, setMudPointBalance] = useState(null); const [mudPointBalanceStatus, setMudPointBalanceStatus] = useState< @@ -5830,18 +5829,25 @@ export function WorkspaceLauncher({ useEffect(() => { let disposed = false; + const walletBalanceRevision = walletBalanceRevisionRef.current; void getClientProfileDashboard() .then((dashboard) => { - if (disposed) { + if ( + disposed || + walletBalanceRevisionRef.current !== walletBalanceRevision + ) { return; } - setProfileDashboard(dashboard); + setWalletBalance(dashboard.walletBalance); }) .catch((error) => { - if (disposed) { + if ( + disposed || + walletBalanceRevisionRef.current !== walletBalanceRevision + ) { return; } - setProfileDashboard(null); + setWalletBalance(null); setMudPointBalanceError( error instanceof Error ? error.message : '泥点读取失败', ); @@ -6198,9 +6204,8 @@ export function WorkspaceLauncher({ try { const center = await getClientProfileRechargeCenter(); setMudPointBalance(center.mudPointBalance ?? null); - setProfileDashboard((current) => - current ? { ...current, walletBalance: center.walletBalance } : current, - ); + walletBalanceRevisionRef.current += 1; + setWalletBalance(center.walletBalance); setMudPointBalanceStatus('ready'); } catch (error) { setMudPointBalance(null); @@ -6236,9 +6241,8 @@ export function WorkspaceLauncher({ setMudPointBalance(center.mudPointBalance ?? null); setMudPointBalanceStatus('ready'); setMudPointBalanceError(''); - setProfileDashboard((current) => - current ? { ...current, walletBalance: center.walletBalance } : current, - ); + walletBalanceRevisionRef.current += 1; + setWalletBalance(center.walletBalance); } async function loadRechargeCenter() { @@ -8682,7 +8686,7 @@ export function WorkspaceLauncher({
{ it('opens the shared recharge modal from the wallet and sidebar entries', async () => { const rechargeCenter = { walletBalance: 120, - mudPointBalance: { - totalPoints: 120, - permanentPoints: 100, - limitedPoints: 20, - limitedExpiresAt: '2026-08-01T00:00:00Z', - dailyFreePoints: 0, - dailyFreeResetPoints: 20, - dailyFreeResetsAt: '2026-07-18T00:00:00Z', - }, membership: { status: 'inactive', tier: 'normal', @@ -1631,13 +1622,14 @@ describe('AI 游戏创作 App 界面边界', () => { }; let rechargeOrderRequestCount = 0; let releaseLateRechargeOrder: (() => void) | null = null; + let resolveInitialDashboard: ((response: Response) => void) | null = null; const fetchSpy = vi .spyOn(globalThis, 'fetch') .mockImplementation(async (input: RequestInfo | URL) => { const url = String(input); if (url === '/api/profile/dashboard') { - return new Response(JSON.stringify({ walletBalance: 120 }), { - status: 200, + return new Promise((resolve) => { + resolveInitialDashboard = resolve; }); } if (url === '/api/profile/recharge-center') { @@ -1698,9 +1690,13 @@ describe('AI 游戏创作 App 界面边界', () => { ...rechargeCenter, walletBalance: 180, mudPointBalance: { - ...rechargeCenter.mudPointBalance, totalPoints: 180, permanentPoints: 160, + limitedPoints: 20, + limitedExpiresAt: '2026-08-01T00:00:00Z', + dailyFreePoints: 0, + dailyFreeResetPoints: 20, + dailyFreeResetsAt: '2026-07-18T00:00:00Z', }, }, }), @@ -1717,6 +1713,7 @@ describe('AI 游戏创作 App 界面边界', () => { await screen.findByRole('dialog', { name: '购买更多泥点' }), ).not.toBeNull(); expect(screen.getByText('当前余额 120 泥点')).not.toBeNull(); + expect(screen.getByRole('button', { name: '泥点 120' })).not.toBeNull(); fireEvent.click(screen.getByRole('button', { name: '关闭购买更多泥点' })); fireEvent.click(screen.getByRole('button', { name: '我的' })); @@ -1748,6 +1745,14 @@ describe('AI 游戏创作 App 界面边界', () => { expect(screen.queryByRole('dialog', { name: '微信扫码支付' })).toBeNull(); }); expect(screen.getByText('当前余额 180 泥点')).not.toBeNull(); + expect(screen.getByRole('button', { name: '泥点 180' })).not.toBeNull(); + + await act(async () => { + resolveInitialDashboard?.( + new Response(JSON.stringify({ walletBalance: 40 }), { status: 200 }), + ); + }); + expect(screen.getByRole('button', { name: '泥点 180' })).not.toBeNull(); fireEvent.click(screen.getByRole('button', { name: /60泥点.*购买/ })); await waitFor(() => {