From 28e11c47184cd06f28463b48889fdacd81c37854 Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 25 Jun 2026 21:59:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A1=B9=E7=9B=AE=E5=B0=81?= =?UTF-8?q?=E9=9D=A2=E6=9C=AC=E5=9C=B0=E5=85=9C=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增项目封面 IndexedDB 本地缓存。 封面 Blob 生成后先写入本地缓存,上传失败仍可展示。 项目列表优先服务端封面,其次本地缓存,再回退画布图层。 补充封面兜底测试和项目记忆文档。 --- docs/project-memory/shared-memory/pitfalls.md | 8 + .../useImageCanvasProjectPersistence.test.tsx | 81 +++++++- .../useImageCanvasProjectPersistence.ts | 27 ++- .../project/ProjectCanvasCover.test.ts | 196 +++++++++++++++++- src/components/project/ProjectCanvasCover.tsx | 97 ++++++++- .../project/ProjectGalleryView.test.tsx | 158 ++++++++++++-- src/components/project/ProjectGalleryView.tsx | 170 +++++++++++---- .../image-editor/editorProjectCoverCache.ts | 152 ++++++++++++++ 8 files changed, 811 insertions(+), 78 deletions(-) create mode 100644 src/services/image-editor/editorProjectCoverCache.ts diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 67ef60b2a..a04a9bb5d 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -191,6 +191,14 @@ - 验证:Network 中 `/api/editor/projects*`、`PATCH /api/editor/projects/{id}`、素材库接口不应出现 `data:image` / `data:video` / `data:audio`;素材库和图层面板缩略图都能换签显示;`npm run test -- src/components/image-editor/ImageCanvasEditorModel.test.ts src/components/image-editor/useImageCanvasProjectPersistence.test.tsx src/components/image-editor/ImageCanvasAssetRowView.test.tsx src/components/common/PlatformMediaFrame.test.tsx src/services/assetReadUrlService.test.ts src/services/image-editor/editorProjectClient.test.ts`,后端跑 `cargo test -p api-server editor_project --manifest-path server-rs/Cargo.toml`。 - 关联:`server-rs/crates/api-server/src/editor_project.rs`、`src/components/image-editor/ImageCanvasEditorModel.ts`、`src/components/image-editor/useImageCanvasProjectPersistence.ts`、`src/components/common/PlatformMediaFrame.tsx`、`src/services/assetReadUrlService.ts`。 +## 图片画布项目封面上传失败要有本地展示兜底 + +- 现象:画布项目已反复打开、保存或操作,但 `/project` 列表卡片仍只显示“项目”占位,没有封面图。 +- 原因:项目封面快照需要先在浏览器生成 Blob,再上传 OSS 并创建 `assetKind: "project-cover-snapshot"` 项目资源;本地 dev 或 OSS CORS 异常时,Blob 生成成功但上传失败,服务端不会产生正式封面资源。 +- 处理:服务端 `project-cover-snapshot` 仍是跨设备正式封面;前端在生成封面 Blob 后立即把 Blob 以项目 ID 写入 IndexedDB,仅作为当前浏览器展示兜底。项目列表读取时优先使用服务端封面资源,其次使用本地 IndexedDB 封面,最后才退回可见画布图层或占位。IndexedDB 兜底不得写入项目快照、不得进入 `editor_project_resource`,也不得替代 OSS / asset object 正式持久化。 +- 验证:`npm run test -- src/components/project/ProjectCanvasCover.test.ts src/components/project/ProjectGalleryView.test.tsx src/components/image-editor/useImageCanvasProjectPersistence.test.tsx` 覆盖服务端封面优先、本地缓存兜底、上传失败仍保留本地封面缓存;浏览器 smoke 可在 `/project` 对没有服务端封面的项目写入 `genarrative-editor-project-covers` IndexedDB 记录,刷新后应显示 `blob:` 封面图。 +- 关联:`src/services/image-editor/editorProjectCoverCache.ts`、`src/components/project/ProjectGalleryView.tsx`、`src/components/project/ProjectCanvasCover.tsx`、`src/components/image-editor/useImageCanvasProjectPersistence.ts`。 + ## 图片画布框选预览要复用源图换签缓存 - 现象:UI 设计素材提取或快速编辑框选时,画布上的红色框选还在,但底部“框选区域预览”卡片变成空白。 diff --git a/src/components/image-editor/useImageCanvasProjectPersistence.test.tsx b/src/components/image-editor/useImageCanvasProjectPersistence.test.tsx index cbcc16b40..7412477ae 100644 --- a/src/components/image-editor/useImageCanvasProjectPersistence.test.tsx +++ b/src/components/image-editor/useImageCanvasProjectPersistence.test.tsx @@ -16,6 +16,7 @@ const createEditorProjectResourceMock = vi.hoisted(() => vi.fn()); const createProjectCoverSnapshotBlobMock = vi.hoisted(() => vi.fn()); const loadEditorProjectMock = vi.hoisted(() => vi.fn()); const loadOrCreateRecentEditorProjectMock = vi.hoisted(() => vi.fn()); +const putEditorProjectCoverCacheMock = vi.hoisted(() => vi.fn()); const saveEditorProjectLayoutMock = vi.hoisted(() => vi.fn()); const uploadEditorMediaAssetFileMock = vi.hoisted(() => vi.fn()); const EDITOR_PROJECT_RECENT_SESSION_CACHE_KEY = @@ -48,6 +49,10 @@ vi.mock('../../services/image-editor/editorMediaAssetUploadClient', () => ({ uploadEditorMediaAssetFile: uploadEditorMediaAssetFileMock, })); +vi.mock('../../services/image-editor/editorProjectCoverCache', () => ({ + putEditorProjectCoverCache: putEditorProjectCoverCacheMock, +})); + function createLayer( id: string, overrides: Partial = {}, @@ -167,7 +172,10 @@ function ProjectPersistenceHarness({ {generationDialogs - .map((dialog) => `${dialog.id}:${dialog.prompt}:${dialog.placeholder?.x}`) + .map( + (dialog) => + `${dialog.id}:${dialog.prompt}:${dialog.placeholder?.x}`, + ) .join(',')}