feat: 完成短剧项目空间与结构化资产创作闭环 (#38)

* feat(canvas): 短剧项目空间 - 建立项目章节与画布关联 MVP

* feat(canvas): 短剧项目空间 - 完善项目资产、镜头与流程闭环

Refs #30

* fix(deploy): 本地部署 - 修复前端构建并忽略本地 PostgreSQL 配置

* feat(*): 短剧项目空间 - 完成项目、章节、资产、角色与画布创作闭环

Refs #30

---------

Co-authored-by: ddCat <ddcat666@88.com>
This commit is contained in:
ddcat666andddCat authored and GitHub committed 2026-07-27 10:45:11 +08:00
1 parent 243c43f6c2
commit ea15000541
208 files changed
+22655 -4234

No files matched your search

@@ -35,11 +35,11 @@ type UseCanvasRenderModelOptions = {
upscaleNodeId: string | null;
superResolveNodeId: string | null;
angleNodeId: string | null;
emotionNodeId: string | null;
previewNodeId: string | null;
contextMenu: ContextMenuState | null;
versionCompareRootId: string | null;
directorNodeId: string | null;
documentEditorNodeId: string | null;
scriptEditorNodeId: string | null;
dialogNodeId: string | null;
};
@@ -66,11 +66,11 @@ export function useCanvasRenderModel({
upscaleNodeId,
superResolveNodeId,
angleNodeId,
emotionNodeId,
previewNodeId,
contextMenu,
versionCompareRootId,
directorNodeId,
documentEditorNodeId,
scriptEditorNodeId,
dialogNodeId,
}: UseCanvasRenderModelOptions) {
@@ -150,6 +150,7 @@ export function useCanvasRenderModel({
const upscaleNode = upscaleNodeId ? nodeById.get(upscaleNodeId) || null : null;
const superResolveNode = superResolveNodeId ? nodeById.get(superResolveNodeId) || null : null;
const angleNode = angleNodeId ? nodeById.get(angleNodeId) || null : null;
const emotionNode = emotionNodeId ? nodeById.get(emotionNodeId) || null : null;
const previewNode = previewNodeId ? nodeById.get(previewNodeId) || null : null;
const contextMenuNode = contextMenu?.type === "node" ? nodeById.get(contextMenu.nodeId) || null : null;
const activeNodeId = selectedNodeIds.size > 1 ? null : hoveredNodeId || (selectedNodeIds.size === 1 ? Array.from(selectedNodeIds)[0] : null);
@@ -237,7 +238,6 @@ export function useCanvasRenderModel({
return map;
}, [connections, semanticNodes]);
const activeDirectorNode = useMemo(() => semanticNodes.find((node) => node.id === directorNodeId) || null, [directorNodeId, semanticNodes]);
const activeDocumentNode = useMemo(() => semanticNodes.find((node) => node.id === documentEditorNodeId && node.type === CanvasNodeType.Text) || null, [documentEditorNodeId, semanticNodes]);
const activeStylePresetId = useMemo(() => semanticNodes.find((node) => node.metadata?.workflowKind === "styleboard")?.metadata?.stylePresetId, [semanticNodes]);
const activeScriptNode = useMemo(() => semanticNodes.find((node) => node.id === scriptEditorNodeId && node.type === CanvasNodeType.Script) || null, [scriptEditorNodeId, semanticNodes]);
const activeDirectorScene = useMemo(() => directorScenes?.find((scene) => scene.id === activeDirectorNode?.metadata?.directorSceneId) || null, [activeDirectorNode?.metadata?.directorSceneId, directorScenes]);
@@ -253,11 +253,11 @@ export function useCanvasRenderModel({
return {
activeDirectorNode,
activeDirectorScene,
activeDocumentNode,
activeNodeId,
activeScriptNode,
activeStylePresetId,
angleNode,
emotionNode,
annotationNode,
batchChildCountById,
batchMotionById,