From 6496601d120c0ff87ca00c32dc78b65222980283 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Thu, 10 Sep 2026 16:37:52 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=94=BB=E5=B8=83=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E7=94=9F=E6=88=90=E7=B4=A0=E6=9D=90=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=E5=B9=B6=E6=89=93=E9=80=9A=E6=97=A0=E6=BA=90=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E9=93=BE=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.tsx 只做导入、一个生成入口按钮、一处浮层渲染与提交回调;无 invoke 桥或项目未就绪时入口不渲染 - 提交走 derive_local_project_resource 的 create 模式:sourceResourceId 为 create:,sourceAssetId / sourcePath / sourceSubtype / producerTaskId / sourceVersionId 全为 null - 产出后经 pendingResourceFocusRef 定位并选中新素材卡,并写入生成资源已保存提示 - projectResourceLiveIntegration 补入口可见性、create 入参、重试复用 operationId 与新卡定位 2 条用例 - 实施计划文档补 C3 生成入口口径、图片无源生成未完成项与本轮验证数字 --- .../src/view/project-development/index.tsx | 115 ++++++++++++++++++ .../projectResourceLiveIntegration.test.tsx | 53 ++++++++ ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 2 + 3 files changed, 170 insertions(+) diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx index 92b472c9a..6ccbb4fa4 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx @@ -95,6 +95,15 @@ import { resolveResourceCanvasPanelEntries, resolveSelectedPanelEntries, } from '../../features/resource-canvas/resourceCanvasAssetTransferModel'; +import { + isResourceCanvasGenerationAvailable, + resourceCanvasGenerationOption, + resourceCanvasGenerationSourceId, +} from '../../features/resource-canvas/resourceCanvasGenerationModel'; +import { + ResourceCanvasGenerationPanelView, + type ResourceCanvasGenerationSubmitInput, +} from '../../features/resource-canvas/ResourceCanvasGenerationPanelView'; import { canRedoResourceCanvasHistory, canUndoResourceCanvasHistory, @@ -1247,6 +1256,7 @@ export default function ProjectDevelopmentView({ createResourceCanvasHistory, ); const [resourcePanelOpen, setResourcePanelOpen] = useState(false); + const [resourceGenerationOpen, setResourceGenerationOpen] = useState(false); const [resourcePanelNotice, setResourcePanelNotice] = useState(''); const [resourcePanelUploading, setResourcePanelUploading] = useState(false); const [uiEditorRoute, setUiEditorRoute] = useState( @@ -5065,6 +5075,86 @@ export default function ProjectDevelopmentView({ quickEditSourceLayer, ]); + /** + * 生成入口:从资源画布无源新建视频 / 音效 / 背景音乐。 + * + * 产出物是一张全新的资源卡(`generationMode: 'create'`),源素材、画布布局与 + * 已有 manifest 条目都不参与派生;成功后用 `pendingResourceFocusRef` 定位新卡。 + */ + const submitResourceCanvasGeneration = useCallback( + async (input: ResourceCanvasGenerationSubmitInput) => { + const invoke = window.__TAURI__?.core?.invoke; + if (!invoke) { + throw new Error('生成资源需要在客户端内执行'); + } + const option = resourceCanvasGenerationOption(input.kind); + const actionProject = { projectPath, projectId: manifest.projectId }; + const flowId = crypto.randomUUID(); + const status = await invoke<{ revision: number }>( + 'get_local_game_project_revision', + { projectPath }, + ); + if (!Number.isSafeInteger(status.revision) || status.revision < 0) { + throw new Error('项目 revision 无效'); + } + const result = await withPlatformSessionRefresh(() => + invoke( + 'derive_local_project_resource', + { + input: { + projectPath, + expectedProjectId: actionProject.projectId, + expectedProjectRevision: status.revision, + operationId: input.operationId, + idempotencyKey: input.idempotencyKey, + editKind: option.editKind, + generationMode: 'create', + sourceResourceId: resourceCanvasGenerationSourceId( + input.operationId, + ), + sourceAssetId: null, + sourcePath: null, + sourceMediaType: option.sourceMediaType, + sourceSubtype: null, + producerTaskId: null, + sourceVersionId: null, + prompt: input.prompt, + assetName: input.assetName, + }, + }, + ), + ); + if ( + !result.asset || + result.manifest.projectId !== actionProject.projectId + ) { + throw new Error('生成资源结果与当前项目不一致'); + } + onManifestChange?.(projectPath, result.manifest, { + projectId: result.manifest.projectId, + revision: result.committedProjectRevision, + source: 'asset-command', + commitId: result.operationId, + }); + activeFocusFlowIdRef.current = flowId; + pendingResourceFocusRef.current = { + flowId, + saveAttemptId: result.operationId, + sessionId: result.operationId, + draftId: result.operationId, + commitId: result.operationId, + projectPath, + projectId: result.manifest.projectId, + focusGeneration: focusGenerationRef.current, + resourceId: `asset:${result.asset.id}`, + completed: false, + }; + setResourceWorkbenchNotice('生成资源已保存,正在同步资源与布局…'); + setResourceGenerationOpen(false); + }, + [manifest.projectId, onManifestChange, projectPath], + ); + const selectedResourceCardPreview = selectedResourcePreviewIdentity ? (resourceCardPreviews.previews.get(selectedResourcePreviewIdentity) ?? null) @@ -5127,6 +5217,12 @@ export default function ProjectDevelopmentView({ canvasSize: resourceBookSceneSize, }) : null; + // 没有客户端 invoke 桥或项目还没就绪时不渲染生成入口,避免留下点了没反应的按钮。 + const resourceGenerationAvailable = isResourceCanvasGenerationAvailable({ + hasRuntimeInvoke: Boolean(window.__TAURI__?.core?.invoke), + projectPath, + projectId: manifest.projectId, + }); return (