Files
atlas-seller-kit/apps/web/HANDOFF.md
T

230 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Web 前端交接:商品编辑器与 AI 填报
更新日期:2026-10-06
## 2026-10-06 SKU 文案用户要求与弹窗重设计
SKU 文案弹窗以「用户描述 / 生成要求」为主要输入(1000 字符,计数、生成时禁用),标明优先采用;当前 SKU 名称独立展示,采集标题/描述/规格移入默认折叠的辅助参考,右侧按标题/标签/描述展示俄文与中文对照,窄屏单列且内容可滚动。用户要求通过既有 `hint` 提交,按 SKU 暂存于页面内;不写采集信息或商品草稿。要求修改会清空旧预览并禁用应用。生成/重新生成/应用状态明确,仍需用户应用并保存。
Web 请求方法接受共享 `RequestProductAiTask`,复用共享 1000 字符常量;API 字段和校验规则不变。Worker 将用户要求作为独立高优先级输入,明确用户补充或修正优先于采集资料、旧 SKU 和既有文案,辅助 SKU 摘要仅包含当前 SKU,输出格式/俄文/标签约束继续生效。前端通过请求序号隔离关闭或切换 SKU 后完成的旧任务,并核对结果 SKU 与采集/产品/profile 版本。应用当前标题需切换逐 SKU 模式时,保留其他 SKU 原先继承的标题和中文对照,修复旧行为清空其他 SKU 标题的问题。
Contracts/API(含测试)/Worker/Web 类型检查及构建通过;API 单元测试 2 项、Worker 文案测试 12 项通过,均模拟数据库或供应商,不创建真实任务或收费请求。ego-browser TaskSpace 9 的真实 ProductEditPage + 模拟 API 验证 hint 请求、修改要求使旧结果失效、按 SKU 保留要求、关闭/切换后旧结果不回填、加载禁用输入、当前 SKU 应用/模拟保存、中俄对照、其他 SKU 标题保留、空要求兼容、1000 字符边界及 1280/390px 布局。弹窗在 390px 下宽度/scrollWidth 均 374px;底层编辑页有原有 478px 横向宽度,本轮未扩展修改该布局。临时页面与浏览器已清理,未读写真实商品、调用 AI 供应商或 Ozon,未手动启停维护者服务。Web 原有大包体警告保留。
## 2026-10-06 SKU 货号以型号为自动前缀
本轮仅修改 Web 商品编辑器、SKU 信息区及局部样式,新增 `skuOfferId.ts` 与 `SkuOfferIdInput.tsx`,并同步 API/AI 方案与决策说明;HTTP 字段、服务端、数据库、Worker 和扩展无改动。货号控件占整行,型号加连接符为只读前缀,用户只输入 SKU 后缀,表单与保存请求继续持有完整 `offer_id`。手工修改型号同步全部未导入 SKU,包括未挂载的收起项;使用完整表单值,避免丢失采购价、选图等资料。清空型号保留后缀,清空后缀保持空货号。已导入/进行中货号只读并保留历史事实,已有型号锁定规则继续生效。
加载时匹配当前型号的旧货号拆出后缀;未匹配的旧值完整保留为后缀,补前缀只进入待保存草稿并标记未保存,不做后台批量写入。AI 结果的生成型号前缀先拆出,再按表单型号组合,用户非空后缀不被覆盖。完整货号限制 50 字符;输入长度扣除前缀占用,型号变长不截断已有后缀,超限保存给予明确提示。
Web 类型检查与生产构建通过,原有大包体警告保留。ego-browser TaskSpace 8 的隔离真实 SkuInfoPanel/Form 验证前缀及后缀编辑、反复修改/清空型号、收起字段联动、旧值完整保留、空后缀、采购价/图片保留、已上架只读、50 字符输入上限和 390/1280px 布局;长型号导致整串 57 字符时,38 字符旧后缀完整保留。临时 QA 页面和浏览器已清理,没有读取/保存真实商品或触发发布;未手动启停维护者现有服务。
## 2026-10-06 采集与编辑保存支持超过 100 个 SKU
用户补充的明确字段错误为 `variants: Too big: expected array to have <=100 items`,关闭上一轮待定位事项:根因是插件与 API 共享的采集数组上限为 100,且编辑完整草稿也有独立的 100 项上限,真实 1688 组合超过此值即失败。当前集成会话修改共享契约、API 采集响应统计、扩展/API 回归与 API/交接文档。新增 `PRODUCT_VARIANT_LIMIT=1000`,采集和商品完整保存统一使用;超限中文提示,不静默截断 SKU。采集响应的 `variant_count` 改为实际未删除 SKU 数。首次发布每批 50 个、媒体数量、其他字段约束、工作空间采集商品配额及 Ozon 公开页有界补全规则均保持原边界,无数据库迁移或 Worker/Web 业务逻辑修改。
扩展回归 15 项通过,验证 1688 200 条明确可售记录完整解析、101/1000 条接受、1001 条拒绝和上架 50/51 条边界。API 采集/商品编辑 16 项通过,新增完整 1000 SKU 的采集入库、编辑初始化、读取末尾 SKU、完整草稿保存、复采保留 ID 与人工修改、超限请求不改变来源版本或 SKU 数;测试数据隔离,无真实采集或 Ozon 发布。Contracts/API(含测试)/Web/Worker/Extension 类型检查和构建通过;Web 原有包体警告保留,差异检查通过。维护者现有 API 开发进程随源码自动重载,未手动启停服务;插件静态产物已重建,需重载扩展并刷新来源页后再次采集。
## 2026-10-05 采集插件编辑上架进入商品编辑器
修改扩展 `collector.content.ts`、API `extension.service.ts`、Web 编辑页及 `productEditor` 服务和 API/交接文档。根因是采集响应仍提供测试页路径,且新商品尚未初始化平台编辑配置。采集成功响应改为 `/products/{product_id}/editor?collection_item_id={collection_item_id}`,扩展继续使用响应入口并提示「已打开商品编辑页」。Web 携带采集 ID 调用现有 `editor-contexts`,核对商品 ID 后读取快照;当前页头平台和默认店铺规则沿用既有契约。重复采集进入原商品,既有上下文保留资料和上架状态;「采集商品」仍不打开编辑页,没有自动上架、媒体下载或平台绑定写入采集事务。测试页和旧手工商品入口保留,无新增 HTTP 字段或数据库迁移。
API 采集/商品编辑集成回归 15 项通过,覆盖新入口实际商品 ID、幂等重放、复采路径稳定以及首次上下文初始化。API 源码/测试类型检查与构建、Web 类型检查/构建、扩展 WXT prepare/类型检查/Chrome MV3 构建通过;Web 原有包体大小警告保留。ego-browser 隔离真实前端服务验证首次入口先初始化后读快照,普通既有入口直接读取,商品不匹配及无默认店铺阻断读取,并沿用当前平台。临时页面和任务浏览器已清理,没有采集/保存真实商品或调用 Ozon,未手动启停维护者服务。扩展新产物位于 `apps/extension/.output/chrome-mv3`,已加载静态扩展的浏览器需重载扩展并刷新来源页以更新成功提示;既有插件已使用响应入口,API 更新即可更改下一次跳转地址。
## 2026-10-05 已上架 SKU 本地价格重新试算
本轮跨 Web `SkuPricing`、定价 API、商品编辑读模型、共享契约与接口/交接文档。已上架 SKU 开放「重新试算」和「试算详情」,应用价格前确认:「该 SKU 已上架。本次价格调整仅保存为本地记录,不会同步至 Ozon;如需修改线上价格,请前往 Ozon 后台。」取消不修改价格,确认后更新草稿,仍须保存商品。批量计算和自动试算继续跳过已导入项。
编辑快照新增 `variants[].listing.store_id`。已上架 SKU 固定读取首次导入店铺的定价目录和币种,即使 profile 的将来目标店铺已变更。API 允许此 SKU 生成预览,跨店铺试算返回 `PRICING_VARIANT_STORE_MISMATCH`;显式 `pricing_selection` 按已有有效期、输入、规则和幂等边界确认新本地报价,普通草稿保存保留原报价。保持首次导入状态、店铺、货号、平台商品 ID 和导入时间,不创建发布或价格同步任务,无数据库迁移、Worker 或扩展业务改动。
定价保存 13 项、首次发布 11 项、商品编辑 13 项和采集 2 项集成测试通过,覆盖已上架新报价、错误店铺拦截、失效报价原子回滚、幂等重放、普通保存保留报价及零平台任务。Contracts/API/Web/Worker 类型检查与构建通过;Web 存在原有大包体警告。ego-browser 隔离真实组件验证两个入口均可用,取消不改变草稿,确认后实际售价 120 / 划线价 240,始终使用首次导入店铺,批量不自动改价。临时页面与代理浏览器已清理;未保存真实商品或操作 Ozon,没有手动启停维护者服务。
## 2026-10-05 采集页面地址回填货源链接
当前集成会话修改 API `extension.service.ts` 新采集商品写入、`product-editor.service.ts`/models 编辑读模型、extension HTTP 集成回归以及 API/交接文档。插件既有解析器已上报 `source.canonicalUrl`,问题是地址只保存于采集记录,未用于商品货源字段。新建商品同时初始化 `purchase_url`;编辑读模型优先使用手工非空链接,空值回退关联采集记录 `source_url`,历史商品无需复采,手动无来源商品仍为空。清空表示恢复来源地址,复采不覆盖手工非空链接。不修改插件、HTTP 字段或数据库,无历史草稿批量写入。
采集授权/素材 HTTP 2 项与商品编辑 13 项通过,覆盖新 1688 地址初始化、历史空字段回填、Ozon 地址、复采保留手工链接和既有商品编辑边界;API 源码/测试类型检查与构建、Web 类型检查/构建及差异检查通过。在用户当前商品的独立浏览器验证页确认 1688 来源地址已显示、打开按钮启用,输入框与按钮均 35px 且对齐。原用户页面未重载或保存,避免丢失编辑;API 开发进程自动重载,无手动启停。未向真实平台发布,未重新采集或写入真实商品。
## 2026-10-05 货源链接按钮与输入框等高
仅修改 Web `ProductOtherSection` 和编辑页局部样式,货源链接 Compact 组增加专用类,按钮按输入框所在 flex 行伸展高度,避免 Input 的 35px 主题高度与 Button 的默认 32px 不一致;添加按钮可访问名称。其他按钮样式和打开链接行为不变,无接口变更。
Web 类型检查、构建及差异检查通过;ego-browser 隔离真实组件在 620/390/1280px 宽度检查启用与禁用按钮,均与输入框同为 35px 且顶部对齐,打开回调正常。临时页面已清理,未修改真实商品,未启停原有服务。
## 2026-10-05 部分上架按钮显示进行中状态
本轮仅修改 Web `ProductPublishActions.tsx` 与交接文档,复用现有任务读取、提交和轮询接口,无 API、Worker、数据库或契约变更。「部分上架」按钮在任务未结束时显示排队中、提交中、等待 Ozon、等待对账或处理中,配合时钟/加载/提醒图标;running 任务按 SKU 状态细分阶段。点击进行中按钮直接打开任务详情,保持可查看,避免同一入口再次创建任务;任务成功、部分成功或失败后恢复正常部分上架选择入口。页面重载沿用现有最近任务恢复逻辑。
Web 类型检查、生产构建与差异检查通过。ego-browser 隔离真实组件验证页面恢复排队任务、轮询切换提交/等待平台/对账、进行中点击详情不保存或创建任务、失败与成功后恢复入口,以及新任务提交后立即显示排队状态;模拟提交仅一次。临时页面已清理,未向真实 Ozon 发布,未保存真实商品,未手动启停维护者服务。
## 2026-10-04 SKU 主动重算使用最新默认方案
根因:`SkuPricing.calculate` 优先使用 SKU 已保存的 `pricing_draft`,「重新试算」和批量按钮只强制重发相同参数,旧零折扣因此使实际售价与划线价相同。当前集成会话仅调整 Web `SkuPricing`、补充定价引擎公式回归测试及 API/交接说明,不修改服务端业务、HTTP 字段、定价引擎或数据库。
两个主动入口重读目标店铺定价目录,使用最新默认方案的完整参数替换旧 SKU 参数,沿用当前成本与有效包装;无默认方案/费率不可用/读取失败时明确提示,不回退零折扣。自动试算、手工售价输入和试算详情继续使用当前参数。批量跳过已导入 SKU,试算结果仍需保存草稿确认。表单监听保留未注册字段,返回报价直接核对实时表单,避免参数回填的渲染时序误丢弃报价;建立同一计算上下文时不取消已经发出的匹配请求。
验证:ego-browser 隔离真实组件复现旧零折扣两价相同,确认单 SKU 与批量使用最新 50% 折扣、划线价为实际售价两倍,保留成本和包装继承,跳过已上架 SKU;页面打开后将默认方案改为 25% 再重算能读取新值;手工实际售价不覆盖当前折扣;无默认方案、费率不可用、目录失败均不生成回退报价。定价引擎 16 项(新增 CNY/RUB 的 50% 折扣)和定价保存 12 项通过;Web/API 源码与测试类型检查、构建及差异检查通过。临时页面已清理,无真实商品保存或平台发布,未手动启停原有服务。
## 2026-10-04 实际售价、划线价展示与首次发布价格
本轮由当前集成会话负责,范围为 Web `SkuPricing`、`PricingCalculator`、`ProductPublishActions`、SKU 样式,API 发布映射/校验、发布回归测试和相关文档。按维护者要求,首次上架的 Ozon `price` 改为已确认 `listing.list_price`,不发送 `old_price`;保持 HTTP 字段、定价公式、数据库和 Worker 冻结快照执行方式。实际售价继续用于目标利润计算,用户上线后在 Ozon 调整实际售价;已创建任务沿用原价格快照,已导入 SKU 不自动更新。
SKU 收起摘要和展开定价区显示采购价、实际售价、划线价、预估净利润;试算结果实际售价与划线价同行。非人民币报价按同一报价快照比例换算摘要,不读取当前汇率改写历史价格。确认上架表格同时显示两价,划线价标为「本次上报价」。服务端预检与创建要求划线价有效且不低于实际售价,缺失/零值返回 `LIST_PRICE_REQUIRED`,低于实际售价返回 `LIST_PRICE_INVALID`;零折扣两价相同可发布。
验证:发布 11 项、商品编辑 13 项、定价引擎 15 项、定价保存 12 项全部通过,覆盖十进制划线价冻结/实际模拟 Ozon 请求、实际售价保留、零折扣、缺失/零划线价阻断、幂等和租户隔离。API 源码/测试类型检查及构建、Web 类型检查及构建通过。ego-browser 隔离真实组件检查 721px/390px 下的两价同行与无页面横向溢出、展开区、上架确认和 RUB 报价的人民币摘要;未向真实 Ozon 发布,未修改真实商品,原有服务未手动启停。临时验证页面已清理。
## 2026-10-04 主题标签格式与 AI 输出校验
本轮由当前集成会话负责,范围为共享 `ozon-hashtags.ts` 规则、Web SPU/SKU 标签提示、API 发布预检/创建校验、Worker AI 全局及 SKU 文案提示词与输出整理,以及相关测试和文档;不修改 HTTP 请求结构、数据库或标签覆盖继承语义。标签逐项以单个 # 开头,正文只允许字母、数字和下划线,无内部空格;每项含 # 最多 30 字符,最多 30 项,发布继续拼为一个 Ozon 属性值。AI 补齐缺失 #,词间空白及连字符转下划线,过滤非法、超长及重复项,并保留同项中文对照。
历史与手工草稿仍允许保存,Web 给出具体格式提示;预检和任务创建按所选 SKU 实际使用的标签拦截,返回 `OZON_HASHTAG_INVALID`,合法 SKU 独立覆盖不受未使用的通用标签阻断。Web 支持以空格拆分多个输入标签,不自动改写已有内容。新规则及示例见商品编辑 API 文档。
验证:Worker 11 项、发布 HTTP/数据库/模拟 Ozon 10 项、商品编辑 13 项通过;contracts/API/Worker/Web 类型检查与构建通过。ego-browser 隔离真实组件验证缺少 #、内部空格、非法标点、合法标签清除提示、空格拆分及 SKU 覆盖独立提示;临时页面已清理。未调用收费 AI 或向真实 Ozon 店铺发布,API/Worker 仍沿用原有开发监听进程,无手动启停。
## 2026-10-04 上架 SKU 整行选择
「选择与校验上架 SKU」弹窗支持点击整行选中/取消 SKU;复选框保留原有行为,点击不会因冒泡重复切换。行点击与复选框共用状态判断,只有未上架或失败 SKU 可选,已导入、提交中及其他不可重复提交状态仍禁选。仅修改 Web `ProductPublishActions.tsx` 和本文档,无接口、契约或发布规则变更。
Web 类型检查和生产构建通过;ego-browser 隔离页面验证整行选中/取消、复选框无重复切换、失败 SKU 可选、已导入/提交中禁选与全选。未执行真实预检或发布,临时页面已删除,未启停维护者服务。
## 2026-10-04 商品编辑属性与 SKU 文案显示修复
本轮负责人为当前前端会话,修改范围为 `ProductEditPage.tsx`、`DynamicAttributeFields.tsx`、`SkuInfoPanel.tsx` 和本文档;复用商品编辑快照、类目 schema、草稿保存与 AI 任务接口,无 API、Worker、数据库或共享契约变更。
属性草稿补齐从 schema 请求回调拆为独立表单联动:同类目保存重载过滤掉空属性后,仍补齐商品级与已有 SKU 的属性控件;动态属性组件监听顶层 `attributes`,避免缓存 schema 下不重新渲染。schema 请求仅随 profile、平台、类目或刷新版本变化,避免请求自身写入的缓存状态清理其轮询回调。AI 任务前后比较归一化后的保存内容,补齐空属性控件不会误判为人工修改。
SKU 展开区始终显示标题、标签、描述和文案 AI/中文对照入口;通用模式只预览 SPU 文案,不写入 SKU 覆盖值,开启逐 SKU 编辑后沿用原有字段绑定和标题模式。全局 AI 仍只生成 SPU 文案;类目属性仍按 schema 手工填写。
验证:Web 类型检查、生产构建和 `git diff --check` 通过。ego-browser 隔离模拟商品验证了 AI 选定类目后必填/选填及 SKU 属性出现、空属性保存重载后控件恢复、商品/SKU 属性作用域与重读、通用预览不产生覆盖值、AI 前自动保存后正常回填、缺失 schema 自动轮询恢复、逐 SKU 标题/描述编辑保存后恢复。未调用真实模型或写入真实商品;临时验证页面已删除。沿用维护者原有 Web/API 服务,无手动启动、停止或重启。
## 2026-10-04 套图生成固定操作区
按维护者确认的「并列操作」方案实现。生图策略列拆为独立滚动内容和底部常驻操作区;待生成保留 48px 主按钮,排队/生成时左侧取消、右侧状态,生成数量进度显示在下方。规划期间显示「取消规划」与规划状态,取消前确认并保留当前方案;生成取消前提示已完成数量,取消请求有重复操作保护。失败/取消后的未完成图片可在底部重试,成功图片保留;原结果列重复的进度与重试入口移至操作区。执行和重试的摘要取任务快照,调整下一轮方案不改变任务摘要;另保留按当前方案创建新任务的入口。
本轮负责人为当前集成会话,修改范围为 Web 抽屉、操作区组件、样式和交接记录,复用既有套图取消/重试接口,无共享契约、API、Worker 或数据库变更。桌面三列保持独立滚动,880px 以下两列时策略区随抽屉保持可见,580px 以下上下排列;策略高度取抽屉正文容器高度,避免依赖固定标题高度。当前业务页停留在登录页,使用临时隔离页面挂载真实组件,以模拟任务验证 1280px、838px、320px 布局、滚动固定、取消确认/继续生成、取消后保留成功图片、只重试未完成项、取消规划保留方案及任务快照摘要。未提交真实模型请求或修改商品草稿,临时验证页面已删除;Web 类型检查、生产构建和差异格式检查通过,沿用维护者原有开发服务,无手动重启。
## 2026-10-03 AI 套图生成
智能规划失败诊断已补齐:真实 DeepSeek 诊断复现连续两次在四张图片的 `type` 字段收到枚举校验错误。Worker 提示词改用有效的 `white_background` 示例和完整英文类型枚举,第二次规划携带具体字段路径及校验规则;共享错误码区分字段、张数、首图、主题、尺寸与保存失败。每次校验及最终失败打印结构化日志,安全诊断保存在 operation.result.failure。历史失败没有原始诊断,仍保持原记录。本轮实际模型请求限用户授权的两次,未执行生图;修复后的真实模型结果需下次规划确认。Worker 规划及 DeepSeek 客户端 19 项测试通过,覆盖同类错误反馈与纠正;contracts/API/Worker/Web 类型检查与构建通过,API/Worker 原有 watch 进程运行,无手动重启。
参考底图弹窗改为左右两列,复用 `SkuImageCard`、`SkuImageSourceTabs` 和 SKU 弹窗基础样式。左侧用 3:4 缩略图和顺序编号展示已选底图,第一张标为主体图,可移除、设为主体和拖动排序;右侧保留五类来源,点击图片选中/取消,左上角显示勾选。移除重复来源名称标签,不对原图裁切或拉伸。共享图片卡片允许不传编辑菜单,主体标记文案可配置,键盘操作只响应卡片自身,避免操作子按钮时重复触发。顶部数量靠左、灰色提示靠右;左右区域独立滚动,580px 以下上下排列。已在页面核对框比例 0.75、选择两张、主体切换、拖动排序、键盘移除和预览返回;Web 类型检查和构建通过,验证后恢复原有未选状态,未保存商品或调用生图。
本轮验证:Worker 规划/DeepSeek 客户端相关 17 项、API/数据库套图相关 8 项通过;contracts/API/Worker/Web 类型检查与构建通过。页面核对总张数由 4 调整到 5 后预算提示同步,已恢复默认 4。模型响应使用模拟数据,未实际调用 DeepSeek 或收费生图;没有手动启动或重启维护者服务。
智能规划按当前方案总张数提交 `image_count`(1–20,默认 4),预算独立于商品文本。DeepSeek 基于当前 SKU 的文字资料分配用途,按必要性选择场景、尺寸、材质等;规划完成后显示主题、说明和依据,不自动生图。取消/失败保留当前方案,诊断区分配置、连接和无效方案;历史恢复剥离规划预算字段,避免将其传入生成接口。
四类图片数量控件的减号按钮、输入框外框和加号按钮统一由 24px 加高至 28.8px(20%),输入内容垂直居中,宽度保持现有规格。
生成策略移除默认/AI 两个选项,改为右对齐的「AI 智能规划」操作按钮。默认四张自动展示;点击按钮异步规划并更新当前方案,规划成功后可再次点击重新规划;失败保留当前方案,规划期间禁用重复提交。
三列布局在上次策略列加宽的基础上,生图策略收窄 5%、商品资料加宽 5%;标准及 1100px 以下的三列布局同步调整比例和最小宽度。
界面反馈已落实:实物尺寸拆为长/宽/高,默认 CM,切换 MM/M 时换算实际数值,仍沿用带单位尺寸字符串契约。长/宽/高和实物重量统一使用 Ant Design `InputNumber`,支持小数;重量默认 g,可切换 kg 并换算实际净重,历史带明确单位的重量以 g 回填,提交仍使用带单位字符串。文本域为「采集信息/描述」「核心卖点/要求」。风格折叠标题、文本域和恢复默认按钮与风格按钮对齐,生成按钮高 48px。四类图片数量采用减号/输入框/加号组合,支持直接输入 0–5,边界禁用对应按钮;点击数量控件不触发分类展开/收起。
底部「AI 套图生成」已接入 `ProductImageSuiteDrawer` 三列右侧抽屉。目标为已保存 SKU,底图库最多 8 张,来源顺序采集/AI/处理/上传/网络;默认 4 张(白底/场景/核心卖点/细节各 1),分类数量 1/1/2/0,四大类逐张计划可编辑,AI 规划走异步 DeepSeek。Pcore 使用现有单图 Worker 生成子任务,整套与子任务通过数据库汇总,可后台生成、取消、失败重试。成功图片加入目标 SKU 后只修改表单,仍需保存。新契约见 [套图 API](../../docs/api/product-image-suites.md),迁移为 056–059。联调验证不执行真实收费生图,实际图像质量需用业务商品验证。
本文记录 Web 编辑页的现行状态;跨领域总体进度以 [`../../docs/project/HANDOFF.md`](../../docs/project/HANDOFF.md) 的 1.39 为准。开始继续开发前请查看仓库根目录的 `git status --short`,保留目前 API、Worker、contracts、迁移及 Web 中未提交和未跟踪的改动。
## 当前状态(2026-09-30)
- 编辑页 `/products/:id/editor` 的 `ProductEditPage.tsx` 将底部操作条固定在视口底部,提供「AI 填报」和「保存草稿」;AI 套图生成已接入三列右侧抽屉;首次上架已接入,见下方记录。全局 AI 填报会先保存未保存草稿,再创建异步任务并轮询;核对商品、profile、来源版本和本地表单未变化后,只把合格结果填进空字段,不直接持久化。用户仍须检查并保存。
- 全局 AI 只回填 SPU 发布标题、标签、描述和中文对照,以及合格的类目、型号、未导入 SKU 货号与有证据的包装建议。类目有多个候选时,「确认 AI 推荐类目」弹窗用单选卡片让用户选择;选择前不自动写入类目。类目一旦确定,页面按现有机制加载动态属性,但不调用 AI 填写 Ozon 类目属性。
- SPU 的「中文商品名」和「俄文标题」标示首次上架必填,草稿保存允许留空;俄文标题可在通用与按 SKU 设置间切换并保存模式,按 SKU 设置时清空、禁用 SPU 标题并在各 SKU 填写。标题、标签、描述各有中文对照入口;用户可在当前 SKU 弹窗中单独生成、预览并明确应用,不因全局 AI 填报而批量覆盖 SKU。
- SKU 的 Ozon `is_aspect` 字段现在直接放在展开卡片的「SKU 信息」中,不另显示「Ozon 变体属性」标题。产品类目 Cascader 的清除事件按空类目处理,避免读取 `undefined.at`。来源采集信息侧栏仍展示来源资料与差异处理。
- 关键组件:`ProductMainInfoSection.tsx`(名称、类目、SPU 标题等)、`ProductAttributeSection.tsx`(SPU 属性、标签与描述)、`ProductVariantSection.tsx`(SKU 信息及动态变体字段)、`ProductCopyAiDialogs.tsx`(SKU AI 生成与中俄对照)。商品编辑流程编排仍主要在 `ProductEditPage.tsx`。
下一轮前端回归应覆盖固定 footer 在不同视口/侧栏状态下不遮挡内容、类目清除和候选确认、AI 任务失败/部分成功/版本过期、SPU/SKU 文案继承与中文对照保存后重读。俄文禁汉字的最终拦截在 Worker,旧文案不会由前端自动清洗。本次更新只修改交接文档,未重新运行浏览器回归。
## 2026-09-30 首次上架
- `ProductPublishActions.tsx` 提供「上架至 OZON」「部分上架」,沿用父页面草稿保存与版本锁,按指定 SKU 调用预检;超过 50 个需分批选择,任一待提交项失败不创建任务。
- 选择表禁选已导入/进行中 SKU,并显示原因;确认摘要列出店铺、货号、售价和图片数量。任务列表恢复最近任务,轮询后仅合并 listing 状态,保留未保存表单。
- 发布标题最多 500、货号最多 50、SKU 图片最多 30;中文来源商品名仍为 1000。已导入或进行中锁定型号,进行中锁定换店;其他草稿资料可以编辑。
- Web 类型检查及构建通过。隔离数据库页面验证了禁选、全部/部分预检、缺货号阻断、确认提交和刷新恢复;没有向真实 Ozon 店铺导入。
- VAT 首期省略且生产发布默认关闭;真实店铺与七牛图片交付待验收。后端契约见 `docs/api/product-editor-and-publishing.md` 第 7 节。
## 2026-09-11 历史前端记录(以下内容仅供追溯)
### 商品编辑器
- 编辑页为 `/products/:id/editor`,主文件为 `src/pages/products/ProductEditPage.tsx`。
- 已接入门店级类目 Cascader:保存时只提交末级类目 ID;父级节点可展开,只有叶子节点可选。类目下拉菜单高度为 324px(相对 Ant Design 默认菜单高度提高 80%)。
- “更多特征”位于 **02 产品属性** Card 内,不再单独使用 Card;展开后按当前选定类目加载 schema,折叠再展开且类目未变时复用已加载的 schema。加载、空 schema、同步类目属性、字典值搜索、清除字段和旧属性告警均在该区处理。
- 动态属性字段按 schema 渲染:普通值为输入框、布尔值为选择框、字典值为可搜索下拉、多值为多选/标签输入;保存时会过滤空的可选属性值,避免提交无效空数组。
- “主题标签”和“JSON 富内容”属于产品属性的普通字段,不属于“更多特征”。
- 编辑页表单已去除页面级的字号、控件高度覆盖,恢复 Ant Design 主题默认规格。仍保留业务性宽度:型号/品牌/条码 170px,包装重量 150px,包装尺寸各 130px。
- 包装重量通过 `package-weight-field` 单独约束输入组宽度,避免 `addonAfter="g"` 与输入框分离;父表单的标签列为 190px、控件区域为可收缩 680px,避免控件被换到标签下一行。
### 组件拆分现状
已拆出的组件:
- `src/pages/products/components/ProductMainInfoSection.tsx`:主要信息、目标门店、类目、标题、品牌、型号、父商品包装规格。
- `src/pages/products/components/ProductOtherSection.tsx`:货源链接和备注。
- `src/pages/products/components/CollectedProductInfoPanel.tsx`:右侧“采集的商品信息”侧栏。
仍在 `ProductEditPage.tsx` 中的视图:产品属性/更多特征,以及变体设置。后续若继续组件化,应将它们分别迁为展示组件;父页面只保留快照读取、草稿保存、类目/schema/字典同步和状态编排。迁移时不要改变 `Form.List` 字段路径、乐观锁保存流程或动态属性的按需加载缓存条件。
### 门店与类目调试入口
- 店铺列表的“刷新门店类目”按钮在 `src/pages/shops/ShopsPage.tsx`;前端会等待请求完成才结束 loading,并展示成功或失败反馈。
- 左侧菜单新增“调试 → Ozon 类目树调试”,路由为 `/shops/category-tree-debug`。
- 调试页文件:`src/pages/shops/CategoryTreeDebugPage.tsx`、`CategoryTreeDebugPage.css`;服务封装为 `src/services/categoryTreeDebug.ts`。该页只负责调用已存在的前端 API 封装并以 Ant Design 树展示响应,不能在前端处理或持久化 API Key。
## 关键前端行为
1. 选定目标门店后才读取该门店的类目缓存;加载期间 Cascader 显示“正在读取该店铺的类目缓存”。
2. 切换类目会清空草稿属性;展开“更多特征”后才读取新类目的 schema。
3. 动态属性的字典搜索输入至少两个字符后,用户可显式选择“从 Ozon 搜索”;前端不传递或记录 API Key。
4. 页面 API、错误码和返回结构以 `docs/api/` 与 `@atlas/contracts` 为准。前端不要自行扩展接口字段或模拟同步完成状态。
## 已执行验证
本次前端改动已执行:
```bash
cd apps/web
../../node_modules/.bin/tsc -p tsconfig.json --noEmit
git diff --check
```
两项均通过。后续对交互或样式作变更时,应在已启动的 Web 环境中回归:类目选择、更多特征展开/收起与加载状态、字典查询、包装重量同一行展示、SKU 展开编辑、货源链接按钮对齐,以及调试页的树形渲染。
## 当前工作约定
- 当前任务可按仓库 `AGENTS.md` 修改相关项目代码;跨领域改动需遵守 [`../../docs/project/development-collaboration-contract.md`](../../docs/project/development-collaboration-contract.md) 并说明影响范围。
- 验证需要时可在确认目标进程和端口后启动、停止或重启 API/Worker;完成后说明实际操作与状态。上方 2026-09-11 的验证记录不能替代新改动的检查。
- 不在浏览器持久化、日志或页面状态中保存 Ozon API Key。
## 2026-10-06 SKU 上传/网络图片按商品隔离
`useSkuImageLibrary` 必须接收 productId,两个候选 GET 携带 product_id,网络导入和商品上传意图绑定当前商品。变体图片弹窗与套图参考图均已接入;水印协议不变。同商品 SKU 可共用候选,切换商品立即隐藏旧候选并重置指纹和计数,延迟请求使用商品世代隔离。直接上传到 SKU 使用编辑会话序号隔离,关闭/切换后不追加旧结果。历史无归属候选不再全局展示,已有 SKU 选图保留。需先应用数据库迁移 060,API 与 Web 一起更新。浏览器真实 Hook 回归和 Web 类型检查/构建通过;临时 QA 文件与 TaskSpace 10 已清理。
## 2026-10-06 SKU 名称与货号恢复同行
修复型号前缀控件引入时将货号设置为整行的布局回归。Web `SkuInfoPanel` 将名称与货号放入独立两列基础资料行,`ProductVariantSection.css` 调整行布局和长型号前缀截断宽度;即使其余发布字段在窄容器中切为单列,基础资料仍保持同行。型号前缀、后缀编辑、完整货号与锁定规则不变,无 API/共享契约/数据库变更。Web 类型检查、生产构建和差异检查通过;ego-browser TaskSpace 11 验证 1280/620/390px 名称和货号输入同行、不溢出,并确认后缀修改仍组成完整货号。临时 QA 文件和浏览器已清理,未手动启停服务或修改真实商品,保留既有包体警告。
## 2026-10-06 SKU 候选图片永久删除
`SkuImageEditorModal` 右侧候选图片的「编辑」菜单最底部新增红色「删除」,二次确认明确同步永久删除七牛文件。左侧「移出已选」仅取消选图。接口确认接受后清理当前商品候选、所有未保存 SKU 选图及本地处理/预览缓存;删除状态轮询成功后才显示存储清理完成,失败可在确认框或弹窗「重试清理」入口恢复,重新打开可读取待处理任务。已保存引用的图片被服务端拒绝,提示先移除引用并保存。
依赖共享 `ProductImageDeletion` 和 `mediaApi` 商品删除/列表/读取/重试接口,API/Worker 与迁移 061、062 需同步更新,契约见 `docs/api/watermarks-and-assets.md`。Web 类型检查、生产构建通过;ego-browser TaskSpace 13 实际组件验证菜单、二次确认、取消、引用拒绝、失败提示和重试恢复,临时文件与浏览器已清理。后端另以真实七牛对象验证删除后 HEAD 404;没有删除真实用户图片,未手动启停服务,保留原有包体大小警告。
## 2026-10-06 定价试算费用显示精度
`PricingCalculator` 的费用明细统一四舍五入显示两位小数(包括零费用),不修改接口原始金额、计算精度或应用到 SKU 的价格数据。本轮仅修改前端显示。Web 类型检查、生产构建和差异检查通过,保留既有包体大小警告;未启停维护者服务。
## 2026-10-06 SKU 颜色多选与已选文本
`DynamicAttributeFields` 使用共享 `isOzonProductColorAttribute` / `productAttributeValueRules`,颜色属性 10096 在 schema 单值时仍支持多选,保存和发布也采用同一 100 项限制。控件初始化加载颜色字典,按属性 UUID 保留已选文本,搜索、候选分页替换和草稿回填不再让首项退回编号;加载前使用既有俄文颜色名兜底,未知值提示待加载。字典 ID 继续作为提交值,新类目不沿用旧名称缓存。
共享契约和 API 须一起更新;无迁移。Contracts/API/Web 类型检查及构建、25 项后端编辑/发布回归通过。ego-browser TaskSpace 14 验证真实 Form.List 控件的回填、多选、搜索、重新展开和类目隔离;临时文件与浏览器已清理,未修改真实商品或手动启停服务,保留既有包体警告。
## 2026-10-06 产品描述复制保留换行
CopyTextButton 直接读取原始文本写入剪贴板,保留内部换行和空行。通用描述、SKU 描述、中俄对照与 SKU AI 描述预览均增加明确复制按钮;SKU 空白覆盖值按有效文案复制 SPU 描述,未复制 HTML。上报由 Worker 仅对简介属性 4191 转成 Ozon 支持的 br;表单、草稿与快照仍是纯文本。已导入商品不会自动更新。Web 类型检查/构建及 ego-browser TaskSpace 16 真实组件模拟剪贴板验证通过;临时文件和浏览器已清理,未修改真实商品或手动启停服务,保留既有包体警告。