diff --git a/.memory/worklog.json b/.memory/worklog.json index 7d3a8d4..3ac8cf0 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1,19 +1,5 @@ { "entries": [ - { - "files_changed": 9, - "hash": "b0ffd03", - "message": "auto-save 2026-05-12 16:02 (+2, ~6)", - "ts": "2026-05-12T16:05:47+08:00", - "type": "commit" - }, - { - "files_changed": 1, - "hash": "cc31bfe", - "message": "auto-save 2026-05-12 16:11 (~1)", - "ts": "2026-05-12T16:11:20+08:00", - "type": "commit" - }, { "files_changed": 4, "hash": "35b3278", @@ -3358,6 +3344,19 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 05:38 (~3)", "files_changed": 3 + }, + { + "ts": "2026-05-14T05:43:54+08:00", + "type": "commit", + "message": "auto-save 2026-05-14 05:43 (~3)", + "hash": "1b3148d", + "files_changed": 3 + }, + { + "ts": "2026-05-13T21:48:51Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 2 项未提交变更 · 最近提交:auto-save 2026-05-14 05:43 (~3)", + "files_changed": 2 } ] } diff --git a/web/components/lightbox.tsx b/web/components/lightbox.tsx index 00ddb79..1dfed51 100644 --- a/web/components/lightbox.tsx +++ b/web/components/lightbox.tsx @@ -58,7 +58,7 @@ const LIGHTBOX_TABS: Array<{ key: LightboxTab; label: string }> = [ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, onChange, onToggleSelect, onJobUpdate, onSwitchPanel, onCopyImage, embedded = false }: Props) { const [describing, setDescribing] = useState(false) - const [cleaning, setCleaning] = useState(false) + const [cleaningFrameIds, setCleaningFrameIds] = useState>(new Set()) const [batchCleaning, setBatchCleaning] = useState(false) const [batchCleanupProgress, setBatchCleanupProgress] = useState<{ done: number; total: number; failed: number } | null>(null) const [applying, setApplying] = useState(false) @@ -83,7 +83,9 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o const [draftRegion, setDraftRegion] = useState(null) // 当前正在拖的 const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null) const imgWrapRef = useRef(null) + const activeIndexRef = useRef(activeIndex) useEffect(() => setMounted(true), []) + useEffect(() => { activeIndexRef.current = activeIndex }, [activeIndex]) // 切换分镜时清空选区 useEffect(() => { @@ -116,6 +118,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o const elements = f.elements ?? [] const hasCleaned = !!f.cleaned_url const latestSceneAsset = f.scene_assets?.[f.scene_assets.length - 1] ?? null + const isCleaningCurrentFrame = cleaningFrameIds.has(f.index) const cleanedFrameCount = frames.filter((frame) => frame.cleaned_applied || frame.cleaned_url).length const pendingCleanFrames = frames.filter((frame) => !frame.cleaned_applied && !frame.cleaned_url) const selectedFrameIndices = Array.from(selected).sort((a, b) => a - b) @@ -140,22 +143,30 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o } const handleCleanup = async (useRegions = false) => { - setCleaning(true) + const frameIdx = f.index + const usable = useRegions ? regions.filter((r) => r.w >= 0.03 && r.h >= 0.03) : null + setCleaningFrameIds((prev) => new Set(prev).add(frameIdx)) try { - const usable = useRegions ? regions.filter((r) => r.w >= 0.03 && r.h >= 0.03) : null - const updated = await cleanupFrame(jobId, f.index, usable && usable.length > 0 ? usable : null) + const updated = await cleanupFrame(jobId, frameIdx, usable && usable.length > 0 ? usable : null) onJobUpdate?.(updated) - toast.success(`分镜 ${f.index + 1} 清洗完成${usable && usable.length > 0 ? `(${usable.length} 个区域)` : ""}`) - if (useRegions) { setCropMode(false); setRegions([]); setDraftRegion(null) } + toast.success(`分镜 ${frameIdx + 1} 清洗完成${usable && usable.length > 0 ? `(${usable.length} 个区域)` : ""}`) + if (useRegions && activeIndexRef.current === frameIdx) { + setCropMode(false); setRegions([]); setDraftRegion(null) + } } catch (e) { toast.error("清洗失败:" + (e instanceof Error ? e.message : String(e))) } finally { - setCleaning(false) + setCleaningFrameIds((prev) => { + const next = new Set(prev) + next.delete(frameIdx) + return next + }) } } const handleCleanupAllFrames = async () => { - const targets = pendingCleanFrames.length > 0 ? pendingCleanFrames : frames + const targets = (pendingCleanFrames.length > 0 ? pendingCleanFrames : frames) + .filter((frame) => !cleaningFrameIds.has(frame.index)) if (targets.length === 0) return setBatchCleaning(true) setBatchCleanupProgress({ done: 0, total: targets.length, failed: 0 }) @@ -502,7 +513,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o )} @@ -651,7 +662,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o