fix(canvas): 画布 - 防止旧内容覆盖并支持版本历史恢复
This commit is contained in:
40
web/src/services/canvas-sync-drafts.ts
Normal file
40
web/src/services/canvas-sync-drafts.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { localForageStorageForScope } from "@/lib/localforage-storage";
|
||||
import { getActiveUserScope } from "@/lib/user-scope";
|
||||
import { sameCanvasContent } from "@/lib/canvas/canvas-content";
|
||||
import { withCanvasStorePersistenceLock, type CanvasProject } from "@/stores/canvas/use-canvas-store";
|
||||
import { withGenerationArtifactCommitLock } from "@/services/generation-asset-repository";
|
||||
|
||||
export type CanvasSyncDraft = { id: string; savedAt: string; project: CanvasProject };
|
||||
const draftKey = (projectId: string) => `infinite-canvas:sync-drafts:${projectId}`;
|
||||
const draftIndexKey = "infinite-canvas:sync-draft-index";
|
||||
|
||||
export async function readAllCanvasSyncDrafts(scope = getActiveUserScope()) {
|
||||
const raw = await localForageStorageForScope(scope).getItem(draftIndexKey);
|
||||
const ids: string[] = raw ? JSON.parse(raw) : [];
|
||||
return (await Promise.all(ids.map((id) => readCanvasSyncDrafts(id, scope)))).flat();
|
||||
}
|
||||
|
||||
export async function readCanvasSyncDrafts(projectId: string, scope = getActiveUserScope()): Promise<CanvasSyncDraft[]> {
|
||||
const raw = await localForageStorageForScope(scope).getItem(draftKey(projectId));
|
||||
return raw ? JSON.parse(raw) : [];
|
||||
}
|
||||
|
||||
export async function preserveCanvasSyncDraft(project: CanvasProject, scope = getActiveUserScope()) {
|
||||
// A separate record survives replacement of the active canvas and a browser reload.
|
||||
const snapshot = structuredClone(project);
|
||||
return withGenerationArtifactCommitLock(scope, () =>
|
||||
withCanvasStorePersistenceLock(scope, async () => {
|
||||
const drafts = await readCanvasSyncDrafts(snapshot.id, scope);
|
||||
if (!drafts.some((draft) => sameCanvasContent(draft.project, snapshot))) {
|
||||
const storage = localForageStorageForScope(scope);
|
||||
const rawIndex = await storage.getItem(draftIndexKey);
|
||||
const ids: string[] = rawIndex ? JSON.parse(rawIndex) : [];
|
||||
if (!ids.includes(snapshot.id)) await storage.setItem(draftIndexKey, JSON.stringify([...ids, snapshot.id]));
|
||||
drafts.push({ id: nanoid(), savedAt: new Date().toISOString(), project: snapshot });
|
||||
await storage.setItem(draftKey(snapshot.id), JSON.stringify(drafts));
|
||||
}
|
||||
return drafts.length;
|
||||
}),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user