From 5bc52a3441b3adcae2627ba0a15c878e5b4ab40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 14:14:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=B6=E6=B3=A5=E5=84=BF=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E8=B7=A8=E9=A1=B9=E7=9B=AE=E4=B8=8D=E5=86=8D=E4=B8=B2=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useTaonierTab 增加 projectPathRef,在打包/订阅/发布各 await 之后与进度回调里比对当前项目,避免旧项目进度、结果与失败落进新项目面板 --- .../export/state/useTaonierTab.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts b/apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts index 99105c06a..aa45caf59 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { resolveTauriInvoke } from '../../../../app/tauri'; import type { GamePublishProgressState } from '../../../../components/game-distribution/GamePublishProgressDialog'; @@ -71,6 +71,15 @@ export function useTaonierTab({ setDraft([]); setRuntimeNotice(''); }, [projectPath]); + + /** + * 发布链路跨 `await` 后仍要判断「面板当前展示的还是不是发起发布时的那个项目」:这个 hook 挂在 + * 面板根,切项目不卸载,旧项目的发布结果 / 进度 / 失败不能落进新项目的面板。 + */ + const projectPathRef = useRef(projectPath); + useEffect(() => { + projectPathRef.current = projectPath; + }, [projectPath]); const chat = useDirectProjectChatController({ enabled, ensureConversationReadAllowed, @@ -203,6 +212,8 @@ export function useTaonierTab({ }); return; } + // 打包期间换了项目:这次结论属于上一个项目,进度不能写进新项目。 + if (projectPathRef.current !== projectPath) return; if (!built) { // 打包自己会把校验红字 / 适配弹窗 / 失败现场交给用户,这里只收起进度。 setProgress(null); @@ -218,6 +229,8 @@ export function useTaonierTab({ let unsubscribe: TauriEventUnsubscribe = () => undefined; try { unsubscribe = await subscribeGamePackageUploadProgress((event) => { + // 发布途中换项目:旧项目的上传进度不能落到新项目面板上。 + if (projectPathRef.current !== projectPath) return; setProgress({ phase: 'running', message: event.message || '正在发布…', @@ -235,6 +248,8 @@ export function useTaonierTab({ // 订阅失败只影响阶段条:发布本身照常进行,按钮上仍显示「正在发布…」。 } try { + // 建立订阅期间换了项目:这次发布属于上一个项目,不提交、不写状态。 + if (projectPathRef.current !== projectPath) return; // `packageAll` 内部可能采纳一份更新的注册表表单(并已落盘);发布命令不再回读 // `.export/taonier.json`,所以文字字段与本地媒体路径都取这份权威表单,避免漂移。 const effectiveForm = taonier.getEffectiveForm() ?? form; @@ -253,11 +268,15 @@ export function useTaonierTab({ priceMudPoints: online.priceMudPoints, expectedPublicationRevision: online.revision, }); + // 发布期间换了项目:旧项目的结果属于旧项目,别落进新项目面板。 + if (projectPathRef.current !== projectPath) return; setPublishResult(next); setProgress(null); // 发布成功后重新读一次线上值:线上最近版本与状态要以平台为准。 void taonier.refreshOnline(); } catch (error) { + // 旧项目的发布失败不该记到新项目头上。 + if (projectPathRef.current !== projectPath) return; setProgress({ phase: 'failed', message: '发布失败',