feat(wordcloud): 收口在途开发(布局/存储/前端)+ R4 WCD 生产任务(jobs wcd_file)与生产订单列表

This commit is contained in:
2026-08-13 14:22:48 +08:00
parent 1d17b5e20d
commit e518540235
32 changed files with 3525 additions and 592 deletions
+231
View File
@@ -0,0 +1,231 @@
# 画布模板导入导出包(`.wcd`)方案(规划)
> 状态:第一版已实现(画布导出 `.wcd`、首页导入 `.wcd`)。
> 目的:实现画布/设计的完整导入导出,要求包内不仅包含画布尺寸、背景、图层、元素摆放信息,还要把元素用到的素材一起带出去,使得包可以在另一台机器或另一个实例中导入复用。
## 1. 包格式
建议采用 Zip 包,文件后缀为 `.wcd`。没有必要自定义二进制格式。
预期目录结构:
```
example.wcd
├── manifest.json // 包元数据与 schema version
├── document.json // CanvasDocument:画布结构
├── preview.png // 可选封面图
├── fonts/ // 可选字体文件
│ └── ...
└── assets/
├── asset-001.svg
├── asset-002.png
└── asset-003.svg
```
## 2. manifest.json
```json
{
"format": "wordcloud-canvas",
"version": 1,
"name": "海报模板",
"description": "示例模板",
"createdAt": "2026-08-06T00:00:00Z",
"canvas": {
"width": 1600,
"height": 1000,
"background": "#ffffff"
},
"assets": [
{
"id": "asset-001",
"originalAssetId": "asset_xxx",
"name": "词云 A",
"type": "svg",
"mimeType": "image/svg+xml",
"sha256": "abc...",
"size": 1024
}
],
"fonts": []
}
```
字段说明:
- `format`:固定标识,防止其他 Zip 被误导入。
- `version`:包格式版本,后续升级时便于兼容。
- `assets[].id`:包内临时 ID,只在这个包内有效。
- `originalAssetId`:导出时的来源素材 ID,仅记录,不要求导入后保留。
- `sha256`:可选,导入时用于去重。
## 3. document.json
`document.json` 就是当前前端的 `CanvasDocument` 模型:
- `width`:画布宽度。
- `height`:画布高度。
- `background`:画布背景色。
- `layers`:图层列表。
- `layerFolders`:图层文件夹列表。
- `elements`:元素列表。
对 Sticker 元素有一个关键规则:**导出时把 `assetId` 替换成包内临时 ID**。
示例:
```json
{
"width": 1600,
"height": 1000,
"background": "#ffffff",
"layers": [
{ "id": "layer-1", "name": "词云", "visible": true, "locked": false }
],
"layerFolders": [],
"elements": [
{
"id": "element-1",
"type": "sticker",
"assetId": "asset-001",
"x": 100,
"y": 80,
"width": 800,
"height": 500,
"rotation": 0,
"opacity": 1
}
]
}
```
## 4. 导出流程
建议由后端提供导出接口,例如:
```text
GET /api/designs/{id}/export
```
或当前模板库扩展为:
```text
GET /api/design-templates/{id}/export
```
导出步骤:
1. 从数据库读取画布文档 `design_documents`
2. 序列化 `CanvasDocument`
3. 遍历 Sticker 元素,收集所有真实素材 ID。
4. 读取每个素材文件字节。
5. 为每个素材生成包内 ID,例如 `asset-001`
6. 用包内 ID 替换 `document.json` 中的 `assetId`
7. 把素材写入 `assets/` 目录。
8. 可选:生成 `preview.png` 作为导入时的缩略图。
9. 可选:如果模板使用了后端字体,把字体文件写入 `fonts/`
10. 生成 `manifest.json`
11. 打包为 `.wcd` 并返回。
## 5. 导入流程
建议后端提供导入接口,例如:
```text
POST /api/designs/import
multipart/form-data: file=.wcd
```
导入步骤:
1.`.wcd` 解压到临时目录。
2. 校验 `manifest.json`
- 是否是 `wordcloud-canvas` 格式。
- `version` 是否兼容。
- `document.json` 是否结构合法。
3. 读取 `document.json` 并通过现有 `normalizeDocument` 逻辑归一化。
4. 逐个处理 `assets/` 下素材:
- 计算 SHA-256。
- 如果素材表中已有相同 SHA-256,复用已有素材 ID。
- 否则调用素材导入逻辑写入 `assets` 表 + 文件系统。
5.`document.json` 中的包内 `assetId` 重新映射为真实素材 ID。
6. 保存为新的 `design_documents`
7. 可选:把 `preview.png` 作为模板封面。
8. 返回新设计/模板 ID。
## 6. 与现有模板系统的关系
当前模板保存是把 `CanvasDocument``reference_asset_ids` 写到目录 JSON 里:
- 在线模板:保持后端素材引用,适合当前实例内复用。
- `.wcd`:把素材一起打包,适合跨机器/离线/换实例导入导出。
两者最终统一到:
- `design_documents`:存画布文档。
- `assets`:存素材元数据。
- `design_templates`:存模板元数据并引用素材。
`.wcd` 只是外部交换容器。
## 7. 边界与设计决策
### 先不做自定义二进制格式
Zip + JSON 足够,方便调试、校验和后续扩展。
### 不把素材 base64 塞进 document.json
素材单独放文件,避免 JSON 膨胀;`document.json` 只保存引用 ID。
### 素材缺失处理
导出时如果某个素材文件缺失,可以选择:
- 导出失败并提示哪个素材缺失。
- 或在 `manifest` 中标记为 `missing`,导入时提示并跳过。
建议第一版采用“导出失败并提示”,保证导入包完整。
### 字体处理
第一版建议只保留 `fontFamily` 字符串,不打包字体。
后续如果确实需要跨机器还原,再把字体文件放进 `fonts/`,导入时注册到字体库。
### 去重
`assets.sha256` 是导入去重的关键字段:
- 包内相同素材只存一次。
- 多次导入相同素材时直接复用数据库中的现有素材。
## 8. 分阶段实施
### 阶段一:最小可用包(已完成)
- 定义 `.wcd`,包含 `manifest.json``document.json``assets/`
- 支持导出当前画布或模板。
- 支持解压导入,只处理贴纸素材和画布布局。
- 不处理字体,不生成 preview。
### 阶段二:导入体验完善
- 生成 `preview.png`
- 导入时检查素材缺失。
- 支持同一设计重复导入去重。
### 阶段三:与 PostgreSQL 打通
- `POST /api/designs/import` 最终写入 `design_documents`
- 素材导入自动写入 `assets` 表。
- 导出接口直接读取 `design_documents``assets`,不再依赖前端状态。
## 9. 相关文件参考
- `frontend/src/lib/svgExport.ts`:当前图层 ZIP 导出。
- `frontend/src/lib/templateLibrary.ts`:当前模板保存/读取。
- `frontend/src/lib/canvasDocument.ts``CanvasDocument` 模型与归一化。
- `frontend/src/types.ts``CanvasDocument``StickerAsset` 等类型。
- `backend/service/app.py`:当前 `/api/assets``/api/design-templates` 接口。
- `docs/DESIGN_DATA_STORAGE_PLAN.md`:存储层重构后文档落库设计。