fix(canvas): 画布删除 - 删除云端记录并等待本地持久化
This commit is contained in:
@@ -1,20 +1,29 @@
|
||||
import { Button, Modal } from "antd";
|
||||
import { App, Button, Modal } from "antd";
|
||||
import { useState } from "react";
|
||||
|
||||
import { useAssetStore } from "@/stores/use-asset-store";
|
||||
import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
|
||||
import { useCanvasUiStore } from "@/stores/canvas/use-canvas-ui-store";
|
||||
import { deleteCanvasProjectsWithRemoteSync } from "@/services/user-data-sync";
|
||||
|
||||
export function CanvasDeleteProjectsDialog() {
|
||||
const { message } = App.useApp();
|
||||
const ids = useCanvasUiStore((state) => state.deleteProjectIds);
|
||||
const setDeleteIds = useCanvasUiStore((state) => state.setDeleteProjectIds);
|
||||
const removeSelectedIds = useCanvasUiStore((state) => state.removeSelectedProjectIds);
|
||||
const deleteProjects = useCanvasStore((state) => state.deleteProjects);
|
||||
const cleanupImages = useAssetStore((state) => state.cleanupImages);
|
||||
const confirm = () => {
|
||||
deleteProjects(ids);
|
||||
cleanupImages();
|
||||
removeSelectedIds(ids);
|
||||
setDeleteIds([]);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const confirm = async () => {
|
||||
setDeleting(true);
|
||||
try {
|
||||
await deleteCanvasProjectsWithRemoteSync(ids);
|
||||
cleanupImages();
|
||||
removeSelectedIds(ids);
|
||||
setDeleteIds([]);
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? `删除画布失败:${error.message}` : "删除画布失败,请稍后重试");
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -26,7 +35,7 @@ export function CanvasDeleteProjectsDialog() {
|
||||
footer={
|
||||
<>
|
||||
<Button onClick={() => setDeleteIds([])}>取消</Button>
|
||||
<Button danger type="primary" onClick={confirm}>
|
||||
<Button danger type="primary" loading={deleting} onClick={() => void confirm()}>
|
||||
删除
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { CanvasBackgroundMode } from "@/lib/canvas-theme";
|
||||
import { removeCanvasDrawing } from "@/lib/canvas/canvas-drawing-storage";
|
||||
import { hydrateAssistantImages, hydrateCanvasImages, resetInterruptedGeneration } from "@/lib/canvas/canvas-project-generation";
|
||||
import { listAddedSkills, type Skill } from "@/services/api/skills";
|
||||
import { createCanvasProjectWithRemoteSync, saveRemoteUserDataNow } from "@/services/user-data-sync";
|
||||
import { createCanvasProjectWithRemoteSync, deleteCanvasProjectsWithRemoteSync, saveRemoteUserDataNow } from "@/services/user-data-sync";
|
||||
import { flushCanvasStorePersistence, useCanvasStore } from "@/stores/canvas/use-canvas-store";
|
||||
import type { CanvasAssistantSession, CanvasConnection, CanvasNodeData, CanvasNodeMetadata, ViewportTransform } from "@/types/canvas";
|
||||
import type { CanvasHistorySnapshot } from "./use-canvas-history";
|
||||
@@ -70,7 +70,6 @@ export function useCanvasProjectLifecycle({
|
||||
const openProject = useCanvasStore((state) => state.openProject);
|
||||
const updateProject = useCanvasStore((state) => state.updateProject);
|
||||
const renameProject = useCanvasStore((state) => state.renameProject);
|
||||
const deleteProjects = useCanvasStore((state) => state.deleteProjects);
|
||||
const currentProject = useCanvasStore((state) => state.projects.find((project) => project.id === projectId));
|
||||
const [addedSkills, setAddedSkills] = useState<Skill[]>([]);
|
||||
const viewportSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
@@ -172,16 +171,21 @@ export function useCanvasProjectLifecycle({
|
||||
});
|
||||
}, [message, navigate]);
|
||||
|
||||
const deleteCurrentProject = useCallback(() => {
|
||||
const deleteCurrentProject = useCallback(async () => {
|
||||
const drawingIds = nodesRef.current.flatMap((node) => node.type === "drawing" && node.metadata?.drawingId ? [node.metadata.drawingId] : []);
|
||||
try {
|
||||
await deleteCanvasProjectsWithRemoteSync([projectId]);
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? `删除画布失败:${error.message}` : "删除画布失败,请稍后重试");
|
||||
return;
|
||||
}
|
||||
if (drawingIds.length) {
|
||||
void Promise.all(drawingIds.map((drawingId) => removeCanvasDrawing(projectId, drawingId)))
|
||||
.catch(() => message.warning("项目已删除,但部分本地绘图缓存清理失败"));
|
||||
}
|
||||
deleteProjects([projectId]);
|
||||
cleanupAssetImages();
|
||||
navigate("/canvas");
|
||||
}, [cleanupAssetImages, deleteProjects, message, navigate, nodesRef, projectId]);
|
||||
}, [cleanupAssetImages, message, navigate, nodesRef, projectId]);
|
||||
|
||||
const renameCurrentProject = useCallback((title: string) => {
|
||||
renameProject(projectId, title);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { resourceFileUrl, resourceIdFromStorageKey, resourceStorageKey, uploadRe
|
||||
import type { Asset } from "@/stores/use-asset-store";
|
||||
import { useAssetStore } from "@/stores/use-asset-store";
|
||||
import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
|
||||
import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
|
||||
import { flushCanvasStorePersistence, useCanvasStore } from "@/stores/canvas/use-canvas-store";
|
||||
|
||||
let activeRemoteUserId = "";
|
||||
let applyingRemoteState = false;
|
||||
@@ -177,6 +177,22 @@ export async function deleteAssetWithRemoteSync(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteCanvasProjectsWithRemoteSync(ids: string[]) {
|
||||
const projectIds = [...new Set(ids.map((id) => id.trim()).filter(Boolean))];
|
||||
if (!projectIds.length) return;
|
||||
await withRemoteUserDataSyncPaused(async () => {
|
||||
if (activeRemoteUserId) {
|
||||
for (const id of projectIds) {
|
||||
await deleteRemoteCanvasProject(id);
|
||||
remoteProjectVersions.delete(id);
|
||||
}
|
||||
}
|
||||
useCanvasStore.getState().deleteProjects(projectIds);
|
||||
// 删除完成后再返回,确保刷新不会读到尚未写入 IndexedDB 的旧快照。
|
||||
await flushCanvasStorePersistence();
|
||||
});
|
||||
}
|
||||
|
||||
export async function saveRemoteUserDataNow() {
|
||||
if (!activeRemoteUserId) return;
|
||||
if (syncPauseCount) {
|
||||
|
||||
Reference in New Issue
Block a user