# 设计数据 → WCD 生产任务契约 v1 > 跨路线契约:**R2(数据生产者)与本路线 R4(WCD 打包消费者)共同遵守**。 > 冻结目的:R4 下单后要把设计清单以 `.wcd` 包投递到词云平台形成生产任务 > (见 `docs/routes/route-r4-upload-wordcloud.md` §3)。R4 能打包,取决于 R2 > 保存的 `designData` 携带哪些字段。本文档把这些字段**先定死**。 > > 版本规则:字段只能新增 optional 字段;改名/改语义/改类型必须升版本并同步本文件。 ## 1. 为什么需要本契约 词云平台用 `.wcd`(Zip:`manifest.json` + `document.json` + `assets/`)还原整套画布。 还原需要三样东西全部可用: 1. **画布尺寸 / 背景** ← 来自 `category.mask`。 2. **贴纸布局**(位置、大小、旋转、层级)← 来自 `stickers[]`。 3. **贴纸图片字节** ← 来自每个贴纸的**持久 URL**(COS)。 第 3 点是关键约束:如果贴纸图是 `wxfile://`/`tmp` 临时路径,后端打包时下载不到字节, WCD 生产任务直接失败。因此本契约把"图片必须持久化"从 R2 的已知限制升级为**冻结约束**。 ## 2. 冻结的 `designData` 结构(v1) 与现有前端 `DesignItem.designData` 对齐,保留 `imageSrc/imagePos` 兼容旧版,**新增**如下字段: ```ts /** 设计数据 v1 —— 支持 R4 WCD 生产任务打包 */ interface DesignDataV1 { /** 结构版本,缺省按 v1 处理;旧数据可由后端/前端按版本迁移 */ version?: 1 /** 商品品类(已有)。mask 是画布尺寸来源,保存清单时必须保留 */ category?: { id: string mask: { shape: 'rect' | 'circle'; width: number; height: number; borderRadius?: number } tone?: [number, number, number] } /** 底图(已有 imageSrc 语义的规范化):src 必须是持久 URL */ background?: { src: string // COS 持久 URL;禁止 wxfile:// / tmp 临时路径 color?: string // 画布底色(缺省由 mask/主题决定) pos?: { x: number; y: number; scale: number } // 兼容旧 imagePos } /** * 词云信息(R4 在词云生成后写入;R2 保存/更新清单时原样保留这组字段, * 后端 items JSON 白名单放行)。 */ wordcloud?: { jobId?: string // 生成该词云的 wxmp_backend 侧任务 id imageUrl: string // 词云结果图持久 URL(COS) names: string[] // 名单快照(≤200),生产/重建用,可为空 } /** 贴纸列表(已有)。每个贴纸的 src 升级为持久 URL 约束 */ stickers?: Array<{ id: string src: string // ★ 必须为 COS 持久 URL(https),禁止 wxfile:// / tmp / 空 x: number y: number scale: number width: number height: number rotation?: number // 已冻结(2026-08-12 决策#2):本期 DIY 持久化;无旋转则省略 zIndex?: number // 已冻结(2026-08-12 决策#2):图层顺序;WCD 按 zIndex 排列元素 isOverlapping?: boolean edits?: { brightness?: number // -100~100 hue?: number // -180~180 contrast?: number // -100~100 sketchSrc?: string } }> } ``` 关系说明: - `DesignItem.designData`(前端类型文件 `src/types/index.ts`)与后端 `design-list.items[].designData` (服务端 JSON)为**同一份**结构;前端类型以本契约为准,后端只做白名单校验不改业务 JSON。 - `imageSrc/imagePos` 保留为兼容旧版字段;新写入统一走 `background.src/pos`, WCD 打包器同时兜底读旧字段。 ## 3. 冻结约束(R2 需落地) | # | 约束 | 说明 | |---|---|---| | 1 | **贴纸图持久化(R4 负责)** | 决策#4:**贴纸持久化由 R4 完成**。R2 允许保存/更新清单时贴纸 `src` 暂为本地路径(`wxfile://`/`tmp`);**R4 在下单/派单前**把本地图上传为 COS 持久 URL 并回写 `designData.stickers[].src`。WCD 打包只消费持久 URL。R2 需保证该字段可被 R4 回写 | | 2 | **词云字段保留** | `designData.wordcloud` 由 R4 写入后,R2 的 PATCH/列表接口不得丢弃该分组 | | 3 | **mask 必须存在** | `designData.category.mask` 是画布尺寸来源;缺 mask 的旧数据 WCD 打包按产品默认尺寸兜底 | | 4 | **布局字段持久化** | 决策#2:`rotation`/`zIndex` 本期由 DIY 随贴纸持久化(当前 `StickerItem` 缺 rotation,需补) | | 5 | **白名单放行** | 后端 `design-list` 的 items JSON 白名单放行 `version/background/wordcloud/rotation/zIndex` 字段;单条 ≤1MB 上限以新结构复核(图片在远端 URL,JSON 本体仍应很小) | | 6 | **状态映射不变** | `ordered` 继续由 `orderId != null` 派生,本契约不改变 R2 状态机 | ## 4. 边界(本期不做) - 贴纸 `edits`(亮度/色相/对比度/`sketchSrc` 线稿)无法由词云平台 `.wcd` `document.json` 表达,本期不随 WCD 携带;仅记录在 `manifest.meta`。若后续生产需要 线稿还原,需单独升 WCD 契约(wordcloud 侧支持后再谈)。 - 字体不随包携带(wordcloud 第一阶段不做字体打包)。 - `.wcd` 只做"订单 → wordcloud"单向投递;暂不做"词云平台 → 小程序"的反向导出。 ## 5. 落地位置 | 文件 | 内容 | |---|---| | 前端类型 | `wechat_wc/src/types/index.ts` 的 `DesignItem.designData` 按本契约补齐字段 | | 前端页面 | `diy`(保存 designData)、`checkout`(下单前确认 designData 完整) | | 后端白名单 | `wxmp_backend/src/design-list/*` 的 items 校验放行新字段 | | 契约发行 | `wxmp_backend/docs/api-contract-v1.md` §5 引用本文档 | ## 6. 决策记录(2026-08-12 冻结) | 评审点 | 决策 | |---|---| | 1. `background`/`wordcloud` 命名 | **接受**,按 §2 结构冻结 | | 2. `rotation`/`zIndex` 是否本期持久化 | **本期持久化**,DIY 随贴纸保存(见约束 #4) | | 3. 名单快照 `wordcloud.names` 是否必须 | **小程序可不必须**:`names` 保持 optional,小程序可不带;R4 生成词云后按实际写入,生产侧不强依赖 | | 4. 贴纸图持久化由谁触发 | **R4 负责**:下单/派单前把本地贴纸图上传为 COS 持久 URL 并回写 `src`(见约束 #1) |