feat(canvas): 条件读取与历史 - 减少画布同步传输并校准版本

This commit is contained in:
ddcat666
2026-09-29 08:26:29 +08:00
parent bcccddb4e9
commit 6ad1adc197
17 changed files with 783 additions and 25 deletions

View File

@@ -89,7 +89,8 @@ export async function loadCanvasProjectForEditing(id: string, options: { latest?
}
let remote: CanvasProject;
try {
remote = (await getRemoteCanvasProject(id)).project;
const knownRemote = verifiedProjects.has(id) ? acknowledgedProjects.get(id) : undefined;
remote = (await getRemoteCanvasProject(id, knownRemote)).project;
} catch (error) {
if (epoch !== sessionEpoch) throw new Error("账号已切换,请重新打开画布");
const local = useCanvasStore.getState().openProject(id);
@@ -158,7 +159,8 @@ export async function refreshCanvasAfterAgent(id: string) {
const epoch = sessionEpoch;
return withRemoteUserDataSyncExclusive(async () => {
if (!activeRemoteUserId) throw new Error("请先登录再刷新 Agent 画布结果");
const { project } = await getRemoteCanvasProject(id);
const knownRemote = verifiedProjects.has(id) ? acknowledgedProjects.get(id) : undefined;
const { project } = await getRemoteCanvasProject(id, knownRemote);
if (epoch !== sessionEpoch) throw new Error("账号已切换");
const current = useCanvasStore.getState().projects.find((candidate) => candidate.id === id);
const baseline = acknowledgedProjects.get(id);
@@ -823,6 +825,26 @@ async function saveRemoteUserDataBatch(uploaded: Map<string, string>, options: {
if (pending) syncQueued = true;
} catch (error) {
const conflict = error instanceof ApiError && error.reason !== "canvas_history_resources_missing" && (error.status === 409 || error.status === 428);
if (conflict) {
try {
const { project: remote } = await getRemoteCanvasProject(source.id);
const current = useCanvasStore.getState().openProject(source.id);
if (current && current === useCanvasStore.getState().openProject(source.id) && sameCanvasContent(current, remote)) {
const hash = await canvasContentHash(remote);
if (current === useCanvasStore.getState().openProject(source.id)) {
const reconciled = { ...remote, viewport: current.viewport, remoteContentHash: hash };
acknowledgedProjects.set(source.id, reconciled);
verifiedProjects.add(source.id);
useCanvasStore.setState((state) => ({ projects: state.projects.map((project) => project.id === source.id ? reconciled : project) }));
await flushCanvasStorePersistence();
useSyncProgressStore.getState().setProjectProgress(source.id, { phase: "done", message: "云端内容一致,已自动校准版本" });
continue;
}
}
} catch {
// Keep the original conflict and preserve the local draft below.
}
}
useSyncProgressStore.getState().setProjectProgress(source.id, {
phase: conflict ? "conflict" : "error",
message: error instanceof Error ? error.message : "云端同步失败,等待重试",