fix(core): 删脚本分镜联动删故事板帧 + 演员库自取 person + 分镜编辑行抽组件

- views.py: delete-script-segment 同步删对应 StoryboardFrame(原 SET_NULL 留孤儿帧致故事板仍显示已删的场),并重排剩余帧 sort_order
- actor-library.tsx: 演员库改自取 person 资产(全局 assets 已懒加载不再全量预载,否则演员库全空),保存后 reload 即时入列
- pipeline.tsx: 抽出 EditableShotField 组件、PromptBox 参数化
- 附 perf-report 产物

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-17 19:18:15 +08:00
co-authored by Claude Opus 4.8
parent f1bc5933ef
commit c62abed536
5 changed files with 174 additions and 182 deletions
+19 -3
View File
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import type { CSSProperties } from "react";
import { api } from "../api";
import type { Asset } from "../types";
import { useBodyScrollLock, MediaLightbox } from "./overlays";
@@ -52,8 +53,22 @@ export function ActorLibrary({ open, mode, initialStudio, assets, onClose, onPic
setCandidates([]); setPicked(null); setActorName(""); setTriReady(false);
}, [open, initialStudio]);
// person 类资产 → 演员;按 preset / mine 分两 tab
const people = useMemo(() => assets.filter((a) => a.category === "person" && previewOf(a)), [assets]);
// 演员库自取 person 资产:全局 assets 已不再全量预载(按需懒加载),不能再依赖传入的 assets prop,
// 否则平台预设/我的演员全空。打开时拉一页(团队 person 资产),保存后 reload 让新人物即时入列。
const [fetched, setFetched] = useState<Asset[]>([]);
const reload = useCallback(async () => {
const res = await api.assetsPage({ category: "person", pageSize: 200, ordering: "-created_at" }).catch(() => null);
setFetched(res?.results ?? []);
}, []);
useEffect(() => { if (open) void reload(); }, [open, reload]);
// person 类资产 → 演员;按 preset / mine 分两 tab。合并 prop(兼容旧调用)+ 自取,按 id 去重。
const source = useMemo(() => {
const map = new Map<string, Asset>();
for (const a of [...assets, ...fetched]) map.set(a.id, a);
return [...map.values()];
}, [assets, fetched]);
const people = useMemo(() => source.filter((a) => a.category === "person" && previewOf(a)), [source]);
const list = people.filter((a) => (tab === "preset" ? isPreset(a) : !isPreset(a)));
// 选某张候选立绘 → 进右侧栏(预填名字,清三视图标志)
@@ -99,6 +114,7 @@ export function ActorLibrary({ open, mode, initialStudio, assets, onClose, onPic
const name = actorName.trim();
if (name && name !== picked.name && onRename) await onRename(picked.id, name);
onRefresh();
void reload(); // 新保存的人物即时进「我的演员」列表(自取,不依赖父级全局 assets)
setStudio(false);
setCandidates([]); setPicked(null); setActorName(""); setTriReady(false);
setTab("mine");