feat(edit): 优化图片导入ozon问题

This commit is contained in:
2026-10-07 21:49:28 +08:00
parent 79b310efe7
commit 06dbd817f0
13 changed files with 289 additions and 70 deletions
+1 -1
View File
@@ -341,7 +341,7 @@ Headers:`X-Atlas-Platform-Id`、`Idempotency-Key`、`If-Match: "product_revisi
`GET /api/product-publish-jobs/{publish_job_id}` 返回 `{data: ProductPublishJob}`;必须传平台上下文,仅可访问当前工作空间和平台。`GET /api/product-platform-profiles/{profile_id}/publish-jobs` 返回 `{data: ProductPublishJob[]}`,最近 10 次任务,供页面刷新恢复。实际 `items` 含 id、variant_id、display_name、offer_id、status、platform_product_id、errors(code/field/message),不返回发布快照、签名 URL、密钥。job 状态为 `queued/running/succeeded/partially_succeeded/failed/reconciling`;item 状态为 `queued/submitting/polling/imported/failed/skipped/reconciling`。`reconciling` 表示提交结果不确定,listing 保持 `submitting`,禁止再次导入。202/任务 ID 仅表示受理。
Worker 提交前查询远端货号;已存在则标 `skipped` 并保留原因,不能调用导入更新它。每批最多 50 个 SKU,提交前生成七牛独立 HTTPS 私有签名图地址(有效期可配置,WebP 转 JPEG);来源与派生对象身份固定,地址仅在内存使用。导入请求的 task ID 持久化后通过延迟 Outbox 轮询,逐项处理 imported/failed/skipped。提交前预写 `submitting`:如果超时、5xx 或响应丢失,下次仅按货号对账,不盲目再次导入;无法确认则保持 reconciling。明确 429 可按 Retry-After 延迟再提交。读请求失败可以重试。平台 errors 必须脱敏,不得包含签名 URL 或请求体。
Worker 提交前查询远端货号;已存在则标 `skipped` 并保留原因,不能调用导入更新它。每批最多 50 个 SKU,提交前生成七牛独立 HTTPS 私有签名图地址(有效期可配置,WebP 转 JPEG);交付域名应配置海外或全球加速并保证 Ozon 抓取端可访问,本地可下载不能替代海外连通性验收。来源与派生对象身份固定,地址仅在内存使用。导入请求的 task ID 持久化后通过延迟 Outbox 轮询,逐项处理 imported/failed/skipped。Ozon 商品导入与图片抓取独立异步完成:收到 imported 后通过 `/v2/product/pictures/info` 核对主图和附加图数量;图片尚未齐且无图片错误时继续既有轮询,不提前报告全量成功。确认缺图或图片下载错误时保留 imported 身份及脱敏警告,结果说明包含实际接收数/快照图片数,Web 显示「已导入(有提示)」。超过既有 120 次快速轮询窗口仍未齐或无法核对时,以 imported 并提示图片未齐/尚未确认结束,不把已创建商品降为可重复导入失败。平台导入返回的警告也必须保留;图片链接只用于内存核对,不持久化。提交前预写 `submitting`:如果超时、5xx 或响应丢失,下次仅按货号对账,不盲目再次导入;无法确认则保持 reconciling。明确 429 可按 Retry-After 延迟再提交。读请求失败可以重试。平台 errors 必须脱敏,不得包含签名 URL 或请求体。
导入成功锁定历史货号/product ID 与商品型号;其他草稿属性可修改,不隐式更新平台。存在提交中 SKU 时禁止删除该 SKU、改型号或变更目标店铺。任一 SKU 已导入后型号不可修改。沿用现有草稿换店行为:没有正在提交的 SKU 时可调整目标店铺,已导入 SKU 保留原店铺和导入身份,仍不能重复上架。失败保留草稿/报价,可修复并新建任务;任务成功不代表审核通过或有库存,在线商品事实仍由独立同步维护。
+1 -1
View File
@@ -234,7 +234,7 @@ Headers:`Idempotency-Key` 必填;请求体为 `{}`。将当前工作空间
商品编辑的“图片悬浮 → 编辑 → 添加水印”使用 `POST /api/media-assets/{asset_id}/watermark-derivatives` 创建异步派生任务,需 `Idempotency-Key`,请求体为 `{ "watermark_template_id": "uuid", "product_id": "uuid" }`。`product_id` 在商品编辑器中传入,旧调用可省略。仅接受当前工作空间内已校验、最大 20 MiB、最大边长 10,000px 的 JPG/PNG/WebP 正式素材和活动模板。创建时固定模板当前版本,在同一事务写入派生任务、operation 和 Outbox,返回 HTTP `202`;`GET /api/media-watermark-derivatives/{derivative_id}` 查询进度。响应包含 `id`、`status`、`source_asset_id`、`watermark_template_id`、`watermark_template_version`、`output_asset` 和 `error_code`。成功时结果为保留源图显示方向及尺寸的独立 JPG 素材,透明源图用白底合成,返回短时预览地址;失败只返回稳定错误码。
单张和批量处理逐张创建任务。成功结果在图片弹窗中替换对应位置;来源候选图成功后加入已选区,失败图保持原样。弹窗可撤销本次水印替换;确认后才写入当前编辑表单,页面保存后持久化 SKU 选图。上架任务不会临时加水印。
单张和批量水印处理逐张创建任务。成功结果进入当前商品的图片处理记录,并在图片弹窗中替换当前卡片;已选图仅替换原位置,未选的来源候选图不自动加入已选区,且处理不受已选图片数量上限影响。失败图保持原样。弹窗可撤销本次水印替换,撤销不删除已归档的处理记录;用户可主动从候选区或处理记录选用结果,确认后才写入当前编辑表单,页面保存后持久化 SKU 选图。上架任务不会临时加水印。
`GET /api/products/{product_id}/image-derivatives` 返回当前工作空间内该商品最近 100 条成功的 3:4 与水印处理记录,按处理时间倒序;商品不存在返回 `404`。每条记录包含 `id`、`kind`(`aspect_ratio_3_4` / `watermark`)、`source_asset_id`、`created_at` 和带短时预览地址的 `output_asset`。编辑页选图弹窗的「图片处理记录」Tab 用它找回结果,选用后仍需确认选图并保存页面。未绑定商品的历史任务无法确定商品归属,不进入该列表;来源图与原素材不被覆盖。
+3 -1
View File
@@ -25,6 +25,8 @@
页面以编辑草稿工作,不采用字段失焦即写库。保存草稿需原子提交父商品、SKU、属性和媒体顺序;存在未保存修改时关闭页面须二次确认。SKU 定价确认是例外:它会即时持久化该 SKU 的价格与定价快照。
商品编辑页支持 Command + S(Mac)或 Ctrl + S(Windows/Linux)保存草稿,输入框内同样生效,沿用保存按钮的表单校验与结果提示,并拦截浏览器保存网页动作。页面加载、保存期间、输入法组合输入、按键持续重复以及未确认的弹窗内不触发草稿保存;离开编辑页后移除快捷键监听。
主要信息中的“中文商品名”用于 Atlas 内部识别;“俄文标题”默认在 SPU 通用,也可切换为按 SKU 设置。草稿保存允许标题留空;首次上架前按当前标题模式校验所需标题。
采集进入采集箱时,商品**型号**和各 SKU 的目标平台**货号(Ozon `offer_id`)**默认都为空。进入编辑页后,用户可手动填写或点击“AI 填报”生成并直接填入表单;生成货号不直接照搬来源 SKU。型号属于商品通用资料,货号属于当前平台下的每个 SKU。两者允许随草稿保存而暂时为空,但首次上架校验必须全部通过:商品型号非空,且每个待上架 SKU 的货号非空并在目标店铺内唯一。详见[AI 填报方案](./ai-autofill-plan.md)。
@@ -73,7 +75,7 @@ SKU 图片选择弹窗左侧是该 SKU 的已选图片(排序/移除),右
2026-10-03:AI 套图使用从右侧滑出的三列抽屉:商品资料、生图策略、生成结果。资料含目标 SKU、最多 8 张底图(建议 3–6)、商品名/颜色/实物尺寸重量、采集信息及核心卖点文本域。选图来源顺序为采集图片、AI 生图记录、图片处理记录、上传图片、网络图片;底图首张决定商品主体,每张生成图使用最多 3 张相关参考图。策略保留白底、场景、卖点、其他四类,默认 4 张(1/1/2/0):白底主图、场景展示图、核心卖点图、细节特写图各 1 张,展开后可逐张修改类型、主题、描述、依据或删除;智能规划使用 DeepSeek,按当前总张数预算和 SKU 资料重新分配用途,不强制凑齐图类;完成后全部展开供确认,不自动生图。五种视觉风格放在策略列,可修改描述并恢复默认;比例为 3:4、1:1、4:3,文字语言为俄/中/英/阿拉伯语。尺寸图只使用有依据的实物尺寸;默认方案不含尺寸图,可手动添加或由智能规划选择。Pcore 逐张生成,可关闭后后台运行、保留部分成功结果、取消及重试未完成项。结果加入目标 SKU 只回填表单,保存商品后持久化。契约见 [商品 AI 套图](../api/product-image-suites.md)。
打开「SKU 图片选择」时静默读取当前工作空间默认水印。点击单张或批量「添加水印」时,有默认模板便直接生成带水印的派生素材;没有默认模板或读取失败才打开每行最多三张卡片的选模板弹窗,水印管理在新标签页打开。原图和其他 SKU 的选择不被改写;生成结果替换当前图片位置,并可在同一弹窗撤销。弹窗确认只更新编辑表单,页面保存后才持久化选图;发布时不会自动加水印。
打开「SKU 图片选择」时静默读取当前工作空间默认水印。点击单张或批量「添加水印」时,有默认模板便直接生成带水印的派生素材;没有默认模板或读取失败才打开每行最多三张卡片的选模板弹窗,水印管理在新标签页打开。原图和其他 SKU 的选择不被改写;生成结果替换当前图片卡片并进入当前商品的「图片处理记录」,可在同一弹窗撤销。已选图片只替换原位置;未选候选图不自动加入左侧已选区,即使已选数量达到上限仍可处理。撤销只恢复本次卡片替换,不删除处理记录。弹窗确认只更新编辑表单,页面保存后才持久化选图;发布时不会自动加水印。
首期素材规则:发布图片仅接受 JPG、PNG、WebP;单文件最大 20 MB,最短边低于 700 px 给出警告且不得作为主图,超过 10,000 px 的边长在上传时拒绝;建议 1:1 或 3:4,允许其他比例但在预览中提示裁切风险。采集候选素材可保留原始文件供编辑选择,实际发布时始终按目标平台的图片数、格式和可访问性校验。Ozon 发布图片必须是可由 Ozon 拉取的 HTTPS 地址。
+26
View File
@@ -823,3 +823,29 @@ Contracts/API(含测试)/Web 类型检查和构建通过;API 商品编辑
维护者要求简介/产品描述上报和复制保留换行。本轮修改 Worker 发布请求适配,新增 ozon-description.ts;Web 新增 CopyTextButton 并接入通用描述、SKU 描述、中俄对照和 SKU AI 结果预览;同步 API 契约说明与发布集成回归,无 API 字段、数据库迁移或草稿存储格式变更。Ozon 官方商品描述规范明确简介支持 br 换行标签。Worker 仅在提交边界将属性 4191 的纯文本 CRLF/CR/LF 转为 br,空行保留连续 br,&/< /> 转义为实体;不修改持久化发布快照或其他属性。编辑与剪贴板继续使用含换行的原文,SKU 空白描述复制有效 SPU 继承值。修复只影响后续提交,不自动更新已导入商品。
API 源码/测试、Worker 和 Web 类型检查及构建通过;13 项发布 HTTP/数据库/Worker 模拟回归通过,新增 SKU 覆盖、SPU 继承、空行/特殊字符、实际请求内容和快照不可变验证。ego-browser TaskSpace 16 先核对官方规则,再使用真实组件和模拟剪贴板验证通用/SKU/继承描述以及中俄对照、AI 结果复制内容逐字一致,显示使用 pre-wrap;临时 QA 页面和浏览器已清理。没有修改真实商品、调用收费 AI 或向 Ozon 发布,没有手动启停维护者服务,Web 原有包体警告保留。
### 2026-10-06:SKU 选图水印结果显示与归档修复
维护者要求「编辑 → 添加水印」仅处理当前图,结果进入图片处理记录,未选候选图不得自动加入左侧已选区。本轮修改 Web `SkuImageEditorModal`、`ProductVariantSection` 与水印相关产品/API 说明,沿用现有派生任务与商品记录接口,没有 HTTP 字段、API/Worker、共享契约或数据库变更。候选卡片即时显示水印结果;已选图仅替换原位置,未选图保持未选且不受 30 张选图上限影响。成功结果立即进入处理记录,较早的列表响应不能覆盖新结果;刷新失败时已有记录仍显示。撤销恢复卡片,保留归档结果。只读核查本地 16 次水印任务均成功,无水印失败队列记录;原候选卡片未更新是本次发现的展示问题。
Web 类型检查、生产构建、差异检查通过,Worker 既有水印渲染回归 5 项通过。ego-browser TaskSpace 17 用真实弹窗/真实水印客户端及模拟接口验证:满 30 张仍可处理单张候选,另一候选不变且左侧数量不增加;默认模板与无默认模板选择;候选/已选图撤销;手动选用处理记录;重开恢复记录;失败保留原图且无新增选图/记录。临时回归页面与任务浏览器已清理,未保存真实商品、未手动启停服务。生产构建保留既有包体大小警告。
### 2026-10-07:Ozon 图片下载缺失与发布结果修复
维护者指定商品 `26662645-a6cf-4978-8fa1-154945bf2510` 的「月读鼬【高约22CM】盒装」作为样例:快照 3 图,Ozon 仅 1 图。只读核查确认前两张的签名有效且文件可下载,平台报 host unreachable;七牛交付域名为 china 加速,无访问限制。Atlas 22 秒结束任务,Ozon 约 90 秒才完成图片处理。修复范围为 Worker 发布结果核对、Web 发布结果警告样式、API 发布集成回归和文档,沿用既有接口/状态/Outbox/RLS,无共享字段或数据库迁移。imported 后等待图片查询,缺图和下载错误保留 imported 身份及脱敏提示,不因缺图允许重复创建商品;完整图片结果继续显示正常成功。
15 项发布闭环回归、6 项 Worker 既有媒体/包装回归、Worker/Web 类型检查与构建、API 测试类型检查通过。ego-browser TaskSpace 18 核对官方文档,并用真实结果组件验证缺图警告与完整成功样式;临时页面已清理。未手动启停维护者服务,保留 Web 原有包体警告。真实三图恢复尚未执行:涉及七牛域名改为 global 与指定 SKU 图片专用更新,需要维护者确认。详细证据与操作范围见 `docs/reviews/ozon-image-delivery-diagnosis.md`。
### 2026-10-07:商品编辑页保存草稿快捷键
本轮仅修改 Web `ProductEditPage`、新增 `useDraftSaveShortcut` 及产品说明,无 API、共享契约、Worker 或数据库变更。Command/Ctrl + S 在页面输入框内复用 `form.submit()`,保留现有校验、版本冲突处理与保存反馈,拦截浏览器保存网页。加载、保存、输入法组合输入、按键重复或可见弹窗期间不提交背景草稿;离开编辑页移除监听。保存入口新增同步锁,避免表单校验完成后并发保存;按钮提示与可访问性属性说明快捷键。
Web 类型检查、生产构建和差异检查通过。ego-browser TaskSpace 19 使用真实 Hook 与 AntD 表单验证 Mac/Windows 快捷键、当前输入与多行描述、必填校验、保存中拦截、弹窗输入拦截、按键重复/组合输入/其他组合键边界、非英文键盘物理 S 键及卸载清理;未保存真实用户草稿。临时页面与浏览器已清理,未手动启停现有服务,保留既有包体大小警告。
七牛后续状态:维护者已批准 global 切换,2026-10-07 20:56:36 请求成功受理;最后观测为 processing。维护者随后要求停止监控,已停止本会话轮询进程,尚未向 Ozon 提交图片恢复。须等待维护者通知就绪后再执行后续动作,具体范围与暂停记录见 `docs/reviews/ozon-image-delivery-diagnosis.md`。
### 2026-10-07:七牛全球生效后的指定 SKU 三图恢复完成
维护者通知配置完成并要求继续后,只读确认七牛 global/success,三张发布副本下载和 SHA-256 校验通过。仅使用 Ozon 图片专用接口更新 `ShouBan-HYRZ-V1-001`,未提交标题、价格或属性更新,未修改 Atlas 草稿/历史发布记录。第一轮任务 `5770626999` 无下载错误但旧替代主图保留,内容最终顺序为 3、1、2;核对官方 V2 schema 后,第二轮任务 `5770634249` 以 primary_image 指定原第一张,images 传原第二、三张,最终 imported,无错误。
最终图片专用查询为 1 主图 + 2 附加图,图片错误为空;下载实际平台图片并与原图内容比对,顺序 1、2、3、平均像素差均 0。前后标题、价格和类目相关字段一致。临时恢复脚本/状态文件和 ego-browser TaskSpace 20 已清理,无后续监控进程,未手动启停现有服务。此前业务代码回归结果继续有效,本轮仅外部图片恢复及结果文档更新,无新增代码或契约变更。详细证据见 `docs/reviews/ozon-image-delivery-diagnosis.md`。
+1 -1
View File
@@ -144,7 +144,7 @@
### 4.3 商品编辑时主动加水印规则
打开「SKU 图片选择」时静默读取当前工作空间默认水印。用户点击“编辑 → 添加水印”后,有默认模板就直接生成带水印的派生图;没有默认模板或读取失败才在弹窗中选择工作空间水印模板。生成后以派生图替换此 SKU 当前图片位置。规则如下:
打开「SKU 图片选择」时静默读取当前工作空间默认水印。用户点击“编辑 → 添加水印”后,有默认模板就直接生成带水印的派生图;没有默认模板或读取失败才在弹窗中选择工作空间水印模板。生成后以派生图替换当前图片卡片并进入当前商品的「图片处理记录」;已选图只替换原位置,未选候选图不自动加入左侧已选区,也不受已选数量上限影响。弹窗撤销只恢复卡片,不删除处理记录。规则如下:
- 商品级候选图片与每个 SKU 已选图片都可处理;最终仅提交用户明确选中的图片集合。
- 原始图片不被改写;水印处理产物是独立、可追溯的派生素材,用户可在编辑弹窗恢复使用原图。
@@ -0,0 +1,42 @@
# Ozon 图片交付排查(2026-10-07)
商品 `26662645-a6cf-4978-8fa1-154945bf2510`,SKU「月读鼬【高约22CM】盒装」,货号 `ShouBan-HYRZ-V1-001`,Ozon product_id `6537891375`。
## 已确认事实
- 发布快照包含 3 张正式 PNG 素材,显示顺序未丢失。三张发布副本均能通过原交付域名下载,HTTP 200,尺寸均为 1086×1448,大小分别为 1,226,554、1,524,027、2,025,426 字节。
- Ozon `/v2/product/pictures/info` 仅返回 1 张主图、0 张附加图;第 1、2 张交付链接均返回 `request process failed: unknown error host unreachable`。失败链接签名正确,截止时间为 2026-10-14 15:15:35(北京时间),并非签名过期。
- 七牛只读域名配置显示 `img-dev.atlas.joeyone.cn` 为 `geoCover=china`、HTTPS、正常运行、七牛桶回源;没有 Referer/IP/UA 限制。结合 Ozon 抓取错误,当前大陆加速域名的跨境连通性是本次最明确的原因。
- Atlas 发布任务在 2026-10-07 15:15:54 完成;Ozon 图片错误于约 15:17:12 出现。原流程收到商品 imported 就结束,图片仍在抓取,且 imported 分支丢弃平台警告。
## 本地修复与验证
Worker 收到 imported 后继续查询图片状态,等待完整结果;存在下载错误或缺图时保留导入身份、图片数量和脱敏提示。已创建商品不因缺图重新进入首次上架。发布结果界面对有提示的已导入任务使用警告样式,展示逐项说明;接口字段和数据库结构不变。
15 项发布 HTTP/数据库/Worker 回归通过,覆盖商品先导入、图片后到、1/3 缺图、完整成功、长时间未齐、平台警告持久化、签名链接脱敏与不重复导入。6 项既有 Worker 媒体交付/包装规格回归通过。Worker/Web 类型检查与构建、API 测试类型检查和差异检查通过;真实结果组件的模拟界面验证通过。没有修改真实商品资料或向 Ozon 提交写请求,未手动启停维护者服务。
## 已授权的线上恢复范围
1. 将该七牛域名的加速区域从 `china` 改为 `global`,保留域名、HTTPS、回源和访问控制配置。此域名的其他图片也会使用新的加速区域。
2. 域名变更生效后重新验证三张交付副本,生成新的短期签名地址。
3. 通过 Ozon `/v2/product/pictures/import` 仅更新 `ShouBan-HYRZ-V1-001` 的原 3 张图片和顺序,以 `primary_image` 明确指定第一张、`images` 传其余两张;不调用商品导入更新价格、标题或属性。
4. 查询图片导入任务和图片专用结果,必须确认主图加附加图共 3 张且无下载错误,才宣称该 SKU 恢复。
维护者已于 2026-10-07 确认执行。七牛区域变更请求于北京时间 20:56:36 受理(HTTP 200 / code 200),配置已显示 `global`;21:28:20 仍为 `processing`,域名、CNAME 和 HTTPS 保持不变。维护者随后要求停止监控,监控及其子进程已停止;暂停期间未向 Ozon 提交图片更新。维护者后续通知全球配置完成并明确要求继续,本次恢复已完成,详见下节。
## 实际恢复结果
- 恢复前七牛接口已确认 `geoCover=global`、`operatingState=success`、HTTPS 与 CNAME 不变,配置更新时间为 `2026-10-07T13:32:01.835Z`。原三张交付副本重新下载均 HTTP 200,SHA-256 与冻结发布快照一致。
- 第一轮图片任务 `5770626999` 已导入且无错误。仅提交三图的 `images` 后,平台先保留旧主图及三张附加图,随后收敛为三图,但内容顺序为 3、1、2。未仅凭任务 imported 或图片数量宣称恢复。
- 核对官方 V2 请求 schema 后,第二轮任务 `5770634249` 显式传 `primary_image=原第1张`、`images=[原第2张, 原第3张]`,最终任务 imported,无任务错误。
- 最终图片查询为 1 张主图、2 张附加图,图片错误为空。下载 Ozon 三张实际图片后以统一尺寸 RGB 内容比对原图,匹配顺序为 1、2、3,平均像素差均为 0,确认主图与附加图顺序正确。
- 仅调用图片专用更新接口,没有提交商品导入或价格/属性更新。前后核对 name、price、old_price、min_price、currency_code、description_category_id、type_id 一致;未改写 Atlas 草稿或历史发布记录。
- 临时恢复脚本、任务状态文件与官方文档浏览器已清理,无持续监控进程,未手动启停维护者服务。
## 官方依据
- [Ozon 图片查询](https://docs.ozon.ru/api/seller/#operation/ProductAPI_ProductInfoPicturesV2)
- [Ozon 图片更新](https://docs.ozon.ru/api/seller/#operation/ProductImportPicturesV2):每次提交完整目标图片集合;`primary_image` 可显式指定主图,`images` 指定其余图片顺序。本次旧主图替代场景已验证须显式恢复主图。
- [Ozon 图片直链指南](https://seller-edu.ozon.ru/libra/work-with-goods/trebovaniya-k-kartochkam-tovarov/media/foto-i-video-tovara)
- [七牛 CDN 跨境访问说明](https://developer.qiniu.com/fusion/6389/function-of-consulting-the-faq)
- [七牛加速区域配置接口](https://developer.qiniu.com/fusion/13364/fusion-api-domain-config)