T38 虾皮商品档案、PDD 关联与规格映射 #40

Closed
opened 2026-08-17 10:08:08 +08:00 by ila · 19 comments
Owner

基本信息

  • 类型:需求 / 独立商品档案
  • 所属总体设计:独立商品域;采购闭环仅作为下游消费者
  • 阶段:Stage A 原型 2026-08-19 重新验收通过(首次 2026-08-18,按 #46 修订后复审);Stage B 代码实施可以开始,仍受本工单范围与共享契约约束

依赖与并行

  • 前置工单:#31提供稳定的pdd_products档案和规格结构;相关QuantUX页面经用户审核
  • 是否允许并行:数据/API设计可与SYB商品工单并行;联调依赖#31
  • 原因:Shopee商品档案和规格映射本身可独立使用,不依赖采购任务存在

子项目影响

  • 交付单元:server / web / shared-docs
  • 是否跨子项目:是
  • 是否修改采购Agent契约:否
  • 验证:MySQL迁移、Go测试、Web lint/构建、Playwright管理流程

原始需求

Shopee商品ID全局唯一。一个Shopee商品当前只关联一个PDD商品;多个Shopee商品允许关联同一个PDD商品。Shopee与PDD的颜色、尺码名称可能不同,需要由采购人员维护明确映射,不能由Agent猜测。

做什么

  • 建立独立shopee_products商品档案,shopee_item_id唯一。
  • 保存必要的商品标题、店铺等可复用档案信息。
  • 保存虾皮参考售价:sale_price_cent(整数分,与 #31 的 priceCent 一致)与 currency(ISO 4217 代码,不存显示符号;虾皮为跨境平台,币种必须与金额一起保存)。币种取自系统配置默认值(go-admin sys_config,实测确认 SYB 接口不返回任何 currency 字段,无法从数据推断),不逐商品选择;服务端校验白名单 = 配置值 ∩ ISO 4217。若后续确认多站点经营,再单独建单把币种挂到店铺档案;sale_price_cent 取数规则:按 shopee_item_id 关联 SYB 明细的 details[].productPrice(订单行级字段,实测确认非商品档案字段),取该商品最近一次出现的值四舍五入 ×100 存分,语义为「最近一次导入/维护的参考售价」,非权威成交价,真实成交价以 SYB 明细为准。已软删除的 shopee_item_id 被 #41 重复导入命中时,清空 deleted_at 复活原记录并保留其人工映射,导入结果提示「已恢复 N 条」。批量软删除与恢复对采购员和管理员开放同一套流程,不做角色分支。
  • 保存参考图字段 image_url:值为 SYB(顺云宝 ERP)提供的图片 URL,由 #41 导入 SYB 明细时写入,同时允许人工覆盖;商品域不实时 join syb_products,保证 #40 可独立实施与验收。
  • 参考图必须经服务端代理后展示:SYB 图片接口实测无 Content-Type、带 Content-Disposition: attachment、无缓存头且单张约 2 秒,前端直连会导致整列裂图与长等待;代理需补正确 Content-Type、加缓存,列表用固定尺寸缩略图并懒加载。
  • 保存可为空的pdd_product_id;不得对该字段加唯一约束。
  • 关联 PDD 商品统一通过搜索选择器完成(新建页选填 + 关联页改绑),不提供手工输入商品ID 的入口;选择时校验商品存在、状态非 disabled,并展示已被几个虾皮商品共用。
  • 使用简化JSON维护虾皮颜色/尺码名称到PDD当前规格值的明确映射。
  • 虾皮规格值属于商品档案,可在创建时录入、稍后在详情/映射页补充,或由 #41 SYB 明细导入写入;每个规格值保存来源标记。录入规格值不要求已关联 PDD 商品。
  • 导入与人工值按「维度 + 规格值名称」合并,同名不重复创建;人工添加的值可删除,导入值不可人工删除,只能清除其映射。
  • 提供虾皮(Shopee)商品列表、详情、创建/更新、关联PDD商品和编辑规格映射的服务端接口与Admin页面。
  • 管理端展示术语统一为「虾皮」;数据库表名、字段名、API 路径和文档中的程序标识符保持 shopee_products / shopee_item_id 不变,术语对应关系写入业务规则术语表。
  • 支持批量软删除虾皮商品:勾选后确认弹窗、逐条引用检查、部分成功结果反馈,删除写入 deleted_at 与操作人;列表默认不显示已删除,可筛选「已删除」并恢复。
  • 关联或保存映射时校验PDD商品及规格存在;不完整映射可以保存,但明确显示“不可采购/待完善”。
  • 后续PDD规格覆盖更新导致映射失效时显示失效项。失效项可由 AI 匹配给出候选建议,但必须人工确认后生效,系统不自动替换。
  • 规格值名称完全相等时自动预填映射,标记来源为「自动匹配」并置于「待确认」状态;名称相同不代表实物尺寸相同(如台湾码与大陆码),必须人工确认后才生效,不得自动生效。
  • 映射来源需可区分:manual(人工)/ exact_match(精确匹配)/ ai_match(AI 匹配)。
  • 同步更新架构、业务规则和商品域接口文档。

不做什么

  • 不创建采购任务,不保存PDD订单号、快递单号或采购状态。
  • 不导入SYB货运单商品,不实现Android执行或货运宝回填。
  • 不保存原始控件树、截图或PDD账号信息。

Stage A:QuantUX 原型(当前唯一实施范围)

说明:#32 原型只覆盖采购流程内嵌的「未映射行跳转映射并返回」入口,不替代本工单的独立商品档案管理页原型。

使用 QuantUX MCP 创建 Shopee 商品档案管理端原型,至少覆盖:

  1. 虾皮商品列表:参考图缩略图、shopee_item_id、标题、店铺、售价(金额 + 来源)、PDD 商品(商品ID 为链接,新标签打开 PDD 商品详情)和「可采购 / 待完善 / 未关联 / 已失效」状态标记;不设独立的映射完整度列,缺失项数量并入状态标记文案(例如「待完善 · 缺尺码 3 项」)。
  2. Shopee 商品详情:档案字段、当前关联的 PDD 商品、颜色与尺码映射总览。
  3. 创建/更新虾皮商品:重复 shopee_item_id 的明确提示;同一页可选录入颜色值与尺码值(不涉及 PDD,可留空稍后补充),并可通过搜索选择器选填关联 PDD 商品(不提供手工输入 ID 的入口,选择时校验存在性、状态与共用情况)。
  4. 关联 PDD 商品:选择 PDD 商品,并展示多个 Shopee 商品共用同一个 PDD 商品的情形。
  5. 颜色/尺码映射编辑器:虾皮规格值到 PDD 当前规格值的明确映射,可独立创建、修改和覆盖;表格显示每个规格值的来源(SYB 导入 / 人工添加),并提供「+ 添加颜色值」「+ 添加尺码值」入口与添加弹窗。
  6. 不完整映射保存后的显示方式;PDD 规格覆盖更新导致映射失效时的失效项标记,不自动猜测替换值。
  7. 页面明确不出现采购任务、订单和物流字段。
  8. 批量删除:未勾选时删除按钮置灰;确认弹窗区分「可删除」与「被引用不可删除」两组并说明软删除语义;确认后逐条返回删除/跳过结果;提供恢复路径说明。

原型审核门禁

  • QuantUX MCP 原型已创建并提供可访问链接(App ID 6a83b708191a826306a7eeb1)
  • 已检查商品档案维护主流程、缺失映射与失效映射提示
  • 用户明确回复「原型通过」(2026-08-18 首次)
  • 按 #46 修订后重新回复「原型通过」(2026-08-19)
  • 原型通过前未修改数据库迁移、Go 服务端、Vue 页面或共享 API
  • 在工单中记录原型 App ID、链接和页面清单

Stage B:代码实现

仅在原型明确验收后开始,交付内容见上文「做什么」。

Stage B 代码验收标准

  • shopee_item_id唯一,重复创建返回明确提示。
  • 一个Shopee商品只能指向一个当前PDD商品,多个Shopee商品可以共用同一个PDD商品。
  • 颜色和尺码映射可独立创建、修改和覆盖。
  • 虾皮规格值支持人工添加,与 SYB 导入值按「维度 + 名称」合并且不重复创建;来源可见。
  • 缺失或失效映射可被采购人员清楚识别,不产生猜测结果。
  • 页面不展示采购任务、订单或物流字段。
  • shopee_item_id 唯一约束与软删除并存:已删除记录不得阻塞同一 shopee_item_id 的再次创建或导入。
  • 被 SYB 明细或采购任务引用的虾皮商品不可删除,批量删除支持部分成功并逐条反馈。
  • 已删除商品默认不出现在列表、不可被关联和映射,可筛选查看并恢复;恢复后原有 PDD 关联与映射保持不变。
  • MySQL、Go、Web构建及浏览器关键流程验证通过。

风险和回退

PDD规格变化可能让映射失效;只标记并等待人工修正,不自动修改。迁移和页面可独立回退,不影响现有采集任务。


2026-08-18 规则修订:本工单的规格匹配相关条款已按 #46 T44 采购规格 AI 匹配与实时规格回传(决策变更) 修订,以上文正文为准。#46 是该决策的唯一事实来源。

## 基本信息 - 类型:需求 / 独立商品档案 - 所属总体设计:独立商品域;采购闭环仅作为下游消费者 - 阶段:Stage A 原型 2026-08-19 重新验收通过(首次 2026-08-18,按 #46 修订后复审);Stage B 代码实施可以开始,仍受本工单范围与共享契约约束 ## 依赖与并行 - 前置工单:#31提供稳定的`pdd_products`档案和规格结构;相关QuantUX页面经用户审核 - 是否允许并行:数据/API设计可与SYB商品工单并行;联调依赖#31 - 原因:Shopee商品档案和规格映射本身可独立使用,不依赖采购任务存在 ## 子项目影响 - 交付单元:server / web / shared-docs - 是否跨子项目:是 - 是否修改采购Agent契约:否 - 验证:MySQL迁移、Go测试、Web lint/构建、Playwright管理流程 ## 原始需求 Shopee商品ID全局唯一。一个Shopee商品当前只关联一个PDD商品;多个Shopee商品允许关联同一个PDD商品。Shopee与PDD的颜色、尺码名称可能不同,需要由采购人员维护明确映射,不能由Agent猜测。 ## 做什么 - 建立独立`shopee_products`商品档案,`shopee_item_id`唯一。 - 保存必要的商品标题、店铺等可复用档案信息。 - 保存虾皮参考售价:`sale_price_cent`(整数分,与 #31 的 `priceCent` 一致)与 `currency`(ISO 4217 代码,不存显示符号;虾皮为跨境平台,币种必须与金额一起保存)。币种取自系统配置默认值(go-admin `sys_config`,实测确认 SYB 接口不返回任何 currency 字段,无法从数据推断),不逐商品选择;服务端校验白名单 = 配置值 ∩ ISO 4217。若后续确认多站点经营,再单独建单把币种挂到店铺档案;`sale_price_cent` 取数规则:按 `shopee_item_id` 关联 SYB 明细的 `details[].productPrice`(订单行级字段,实测确认非商品档案字段),取该商品最近一次出现的值四舍五入 ×100 存分,语义为「最近一次导入/维护的参考售价」,非权威成交价,真实成交价以 SYB 明细为准。已软删除的 `shopee_item_id` 被 #41 重复导入命中时,清空 `deleted_at` 复活原记录并保留其人工映射,导入结果提示「已恢复 N 条」。批量软删除与恢复对采购员和管理员开放同一套流程,不做角色分支。 - 保存参考图字段 `image_url`:值为 SYB(顺云宝 ERP)提供的图片 URL,由 #41 导入 SYB 明细时写入,同时允许人工覆盖;商品域不实时 join `syb_products`,保证 #40 可独立实施与验收。 - 参考图必须经服务端代理后展示:SYB 图片接口实测无 `Content-Type`、带 `Content-Disposition: attachment`、无缓存头且单张约 2 秒,前端直连会导致整列裂图与长等待;代理需补正确 Content-Type、加缓存,列表用固定尺寸缩略图并懒加载。 - 保存可为空的`pdd_product_id`;不得对该字段加唯一约束。 - 关联 PDD 商品统一通过搜索选择器完成(新建页选填 + 关联页改绑),不提供手工输入商品ID 的入口;选择时校验商品存在、状态非 disabled,并展示已被几个虾皮商品共用。 - 使用简化JSON维护虾皮颜色/尺码名称到PDD当前规格值的明确映射。 - 虾皮规格值属于商品档案,可在创建时录入、稍后在详情/映射页补充,或由 #41 SYB 明细导入写入;每个规格值保存来源标记。录入规格值不要求已关联 PDD 商品。 - 导入与人工值按「维度 + 规格值名称」合并,同名不重复创建;人工添加的值可删除,导入值不可人工删除,只能清除其映射。 - 提供虾皮(Shopee)商品列表、详情、创建/更新、关联PDD商品和编辑规格映射的服务端接口与Admin页面。 - 管理端展示术语统一为「虾皮」;数据库表名、字段名、API 路径和文档中的程序标识符保持 `shopee_products` / `shopee_item_id` 不变,术语对应关系写入业务规则术语表。 - 支持批量软删除虾皮商品:勾选后确认弹窗、逐条引用检查、部分成功结果反馈,删除写入 `deleted_at` 与操作人;列表默认不显示已删除,可筛选「已删除」并恢复。 - 关联或保存映射时校验PDD商品及规格存在;不完整映射可以保存,但明确显示“不可采购/待完善”。 - 后续PDD规格覆盖更新导致映射失效时显示失效项。失效项可由 AI 匹配给出候选建议,但必须人工确认后生效,系统不自动替换。 - 规格值名称完全相等时自动预填映射,标记来源为「自动匹配」并置于「待确认」状态;名称相同不代表实物尺寸相同(如台湾码与大陆码),必须人工确认后才生效,不得自动生效。 - 映射来源需可区分:`manual`(人工)/ `exact_match`(精确匹配)/ `ai_match`(AI 匹配)。 - 同步更新架构、业务规则和商品域接口文档。 ## 不做什么 - 不创建采购任务,不保存PDD订单号、快递单号或采购状态。 - 不导入SYB货运单商品,不实现Android执行或货运宝回填。 - 不保存原始控件树、截图或PDD账号信息。 ## Stage A:QuantUX 原型(当前唯一实施范围) 说明:#32 原型只覆盖采购流程内嵌的「未映射行跳转映射并返回」入口,不替代本工单的独立商品档案管理页原型。 使用 QuantUX MCP 创建 Shopee 商品档案管理端原型,至少覆盖: 1. 虾皮商品列表:参考图缩略图、`shopee_item_id`、标题、店铺、售价(金额 + 来源)、PDD 商品(商品ID 为链接,新标签打开 PDD 商品详情)和「可采购 / 待完善 / 未关联 / 已失效」状态标记;不设独立的映射完整度列,缺失项数量并入状态标记文案(例如「待完善 · 缺尺码 3 项」)。 2. Shopee 商品详情:档案字段、当前关联的 PDD 商品、颜色与尺码映射总览。 3. 创建/更新虾皮商品:重复 `shopee_item_id` 的明确提示;同一页可选录入颜色值与尺码值(不涉及 PDD,可留空稍后补充),并可通过搜索选择器选填关联 PDD 商品(不提供手工输入 ID 的入口,选择时校验存在性、状态与共用情况)。 4. 关联 PDD 商品:选择 PDD 商品,并展示多个 Shopee 商品共用同一个 PDD 商品的情形。 5. 颜色/尺码映射编辑器:虾皮规格值到 PDD 当前规格值的明确映射,可独立创建、修改和覆盖;表格显示每个规格值的来源(SYB 导入 / 人工添加),并提供「+ 添加颜色值」「+ 添加尺码值」入口与添加弹窗。 6. 不完整映射保存后的显示方式;PDD 规格覆盖更新导致映射失效时的失效项标记,不自动猜测替换值。 7. 页面明确不出现采购任务、订单和物流字段。 8. 批量删除:未勾选时删除按钮置灰;确认弹窗区分「可删除」与「被引用不可删除」两组并说明软删除语义;确认后逐条返回删除/跳过结果;提供恢复路径说明。 ### 原型审核门禁 - [x] QuantUX MCP 原型已创建并提供可访问链接(App ID `6a83b708191a826306a7eeb1`) - [x] 已检查商品档案维护主流程、缺失映射与失效映射提示 - [x] 用户明确回复「原型通过」(2026-08-18 首次) - [x] 按 #46 修订后重新回复「原型通过」(2026-08-19) - [x] 原型通过前未修改数据库迁移、Go 服务端、Vue 页面或共享 API - [x] 在工单中记录原型 App ID、链接和页面清单 ## Stage B:代码实现 仅在原型明确验收后开始,交付内容见上文「做什么」。 ## Stage B 代码验收标准 - [ ] `shopee_item_id`唯一,重复创建返回明确提示。 - [ ] 一个Shopee商品只能指向一个当前PDD商品,多个Shopee商品可以共用同一个PDD商品。 - [ ] 颜色和尺码映射可独立创建、修改和覆盖。 - [ ] 虾皮规格值支持人工添加,与 SYB 导入值按「维度 + 名称」合并且不重复创建;来源可见。 - [ ] 缺失或失效映射可被采购人员清楚识别,不产生猜测结果。 - [ ] 页面不展示采购任务、订单或物流字段。 - [ ] `shopee_item_id` 唯一约束与软删除并存:已删除记录不得阻塞同一 `shopee_item_id` 的再次创建或导入。 - [ ] 被 SYB 明细或采购任务引用的虾皮商品不可删除,批量删除支持部分成功并逐条反馈。 - [ ] 已删除商品默认不出现在列表、不可被关联和映射,可筛选查看并恢复;恢复后原有 PDD 关联与映射保持不变。 - [ ] MySQL、Go、Web构建及浏览器关键流程验证通过。 ## 风险和回退 PDD规格变化可能让映射失效;只标记并等待人工修正,不自动修改。迁移和页面可独立回退,不影响现有采集任务。 --- > **2026-08-18 规则修订**:本工单的规格匹配相关条款已按 [#46 T44 采购规格 AI 匹配与实时规格回传(决策变更)](https://git.ilapage.cn/OPC/goauto/issues/46) 修订,以上文正文为准。#46 是该决策的唯一事实来源。
Author
Owner

规格映射维护位置与失效规则补充(2026-08-17)

按用户确认补充:

  • Shopee 颜色、尺码到 PDD 颜色、尺码的主要维护入口固定在“Shopee商品 → PDD规格映射”页面,由 #40 实现;不在 SYB 商品详情、采购任务详情或创建任务确认页临时编辑。
  • SYB商品列表 对“颜色或尺码未映射”的行提供“去匹配”快捷入口,自动带入 shopee_product_id 并打开同一个 #40 映射页面;保存后返回原 SYB 列表、保留筛选/分页并重新检查该行。
  • 创建采购任务只读取和校验已保存映射,不允许临时修改,不完整或失效时禁止创建;Agent 仍不得猜测。
  • 映射按 Shopee 商品独立保存。多个 Shopee 商品即使关联同一个 PDD 商品,也不能共用或互相覆盖映射。
  • Shopee 商品更换当前关联 PDD 商品时,当前颜色/尺码映射直接清空,不保留更换历史,要求人工重新匹配。
  • 当前 PDD 商品规格被覆盖更新时,指向已不存在规格值的映射标记失效,不自动替换;采购人员修正后才能采购。
  • 不完整映射仍可保存为“待完善”,但页面必须列出缺失/失效项和“不可采购”原因。

新增验收:

  • Shopee 商品页可独立维护颜色和尺码映射。
  • 从 SYB 未映射行进入时自动定位到正确 Shopee 商品,保存返回后刷新该行状态。
  • 更换关联 PDD 商品后旧映射不可继续使用,当前映射被清空。
  • 多个 Shopee 商品共用一个 PDD 商品时,各自映射互不影响。
  • 采购创建页只校验映射,没有编辑映射入口。
## 规格映射维护位置与失效规则补充(2026-08-17) 按用户确认补充: - Shopee 颜色、尺码到 PDD 颜色、尺码的主要维护入口固定在“Shopee商品 → PDD规格映射”页面,由 #40 实现;不在 SYB 商品详情、采购任务详情或创建任务确认页临时编辑。 - `SYB商品列表` 对“颜色或尺码未映射”的行提供“去匹配”快捷入口,自动带入 `shopee_product_id` 并打开同一个 #40 映射页面;保存后返回原 SYB 列表、保留筛选/分页并重新检查该行。 - 创建采购任务只读取和校验已保存映射,不允许临时修改,不完整或失效时禁止创建;Agent 仍不得猜测。 - 映射按 Shopee 商品独立保存。多个 Shopee 商品即使关联同一个 PDD 商品,也不能共用或互相覆盖映射。 - Shopee 商品更换当前关联 PDD 商品时,当前颜色/尺码映射直接清空,不保留更换历史,要求人工重新匹配。 - 当前 PDD 商品规格被覆盖更新时,指向已不存在规格值的映射标记失效,不自动替换;采购人员修正后才能采购。 - 不完整映射仍可保存为“待完善”,但页面必须列出缺失/失效项和“不可采购”原因。 新增验收: - [ ] Shopee 商品页可独立维护颜色和尺码映射。 - [ ] 从 SYB 未映射行进入时自动定位到正确 Shopee 商品,保存返回后刷新该行状态。 - [ ] 更换关联 PDD 商品后旧映射不可继续使用,当前映射被清空。 - [ ] 多个 Shopee 商品共用一个 PDD 商品时,各自映射互不影响。 - [ ] 采购创建页只校验映射,没有编辑映射入口。
Author
Owner

#40 交互设计证据已补入 #32 原型

#32 QuantUX App 6a827440191a826306a7eddd 已展示:从 SYB 未映射行进入正确 Shopee 商品的 PDD 规格映射页、缺失项显示“待匹配”、保存和返回都回到 SYB 商品列表。映射仍按 Shopee 商品独立维护;生产实现继续由本工单负责并受原型审核门禁约束。提交:7df4546。

## #40 交互设计证据已补入 #32 原型 #32 QuantUX App `6a827440191a826306a7eddd` 已展示:从 SYB 未映射行进入正确 Shopee 商品的 PDD 规格映射页、缺失项显示“待匹配”、保存和返回都回到 SYB 商品列表。映射仍按 Shopee 商品独立维护;生产实现继续由本工单负责并受原型审核门禁约束。提交:`7df4546`。
Author
Owner

Stage A 原型已完成,待用户审核

原型

页面清单与 Stage A 覆盖点对应

页面 覆盖点
Shopee商品列表 1 列表:商品ID、标题、店铺、关联 PDD 商品、映射完整度、可采购/待完善/未关联/已失效标记
Shopee商品详情 2 档案字段、当前关联 PDD 商品、颜色与尺码映射总览;缺失 3 项清楚可见
新建Shopee商品 3 创建表单 + 重复 shopee_item_id 明确拒绝提示
关联PDD商品 4 选择 PDD 商品;候选行显示「已被 N 个 Shopee 商品关联」,disabled 商品不可选
颜色尺码映射编辑 5 颜色与尺码独立映射编辑器,可选择、覆盖、清除
映射失效复核 6 PDD 规格覆盖更新后的失效项标记与人工重新选择

覆盖点 7(页面不出现采购任务、订单、物流字段)在列表、详情、失效复核三页写明边界说明,全部页面无采购字段。

已表达的关键规则

  • 一个 Shopee 商品只关联一个 PDD 商品;多个 Shopee 商品可共用同一个 PDD 商品(列表第 3 行与关联页候选行均体现)
  • 不完整映射可以保存,商品标记「待完善 · 不可采购」,采购域不会创建任务
  • 失效映射只标记不自动替换;缺失值不猜测、不用相近值代替

验证

  • quantux_verify_export:verdict=PASS,widgetCount 99、wiredCount 7、navigation=true、inputsEditable=true、toggleWorks=true、runtimeErrors=0、unsupportedTypes 无
  • 几何检查:0 个越界控件,0 个超出内容区右边界的控件
  • 未验证部分:未在本机浏览器做人工视觉走查(无可用浏览器环境),页面观感与流程合理性以用户审核为准

相关提交

  • 38dbaed docs(#40): add stage A shopee product prototype

门禁状态

  • 待用户明确回复「原型通过」;在此之前不修改数据库迁移、Go 服务端、Vue 页面和共享 API
## Stage A 原型已完成,待用户审核 **原型** - QuantUX App ID `6a83b708191a826306a7eeb1` - 线上链接:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html - 离线导出:`prototypes/quantux-shopee-product-6a83b708191a826306a7eeb1.html` - 规模:6 个页面、468 个控件、27 条流程线,桌面 1440×900,沿用 #31/#32 的管理端样式 **页面清单与 Stage A 覆盖点对应** | 页面 | 覆盖点 | |---|---| | Shopee商品列表 | 1 列表:商品ID、标题、店铺、关联 PDD 商品、映射完整度、可采购/待完善/未关联/已失效标记 | | Shopee商品详情 | 2 档案字段、当前关联 PDD 商品、颜色与尺码映射总览;缺失 3 项清楚可见 | | 新建Shopee商品 | 3 创建表单 + 重复 `shopee_item_id` 明确拒绝提示 | | 关联PDD商品 | 4 选择 PDD 商品;候选行显示「已被 N 个 Shopee 商品关联」,disabled 商品不可选 | | 颜色尺码映射编辑 | 5 颜色与尺码独立映射编辑器,可选择、覆盖、清除 | | 映射失效复核 | 6 PDD 规格覆盖更新后的失效项标记与人工重新选择 | 覆盖点 7(页面不出现采购任务、订单、物流字段)在列表、详情、失效复核三页写明边界说明,全部页面无采购字段。 **已表达的关键规则** - 一个 Shopee 商品只关联一个 PDD 商品;多个 Shopee 商品可共用同一个 PDD 商品(列表第 3 行与关联页候选行均体现) - 不完整映射可以保存,商品标记「待完善 · 不可采购」,采购域不会创建任务 - 失效映射只标记不自动替换;缺失值不猜测、不用相近值代替 **验证** - `quantux_verify_export`:`verdict=PASS`,widgetCount 99、wiredCount 7、navigation=true、inputsEditable=true、toggleWorks=true、runtimeErrors=0、unsupportedTypes 无 - 几何检查:0 个越界控件,0 个超出内容区右边界的控件 - **未验证部分**:未在本机浏览器做人工视觉走查(无可用浏览器环境),页面观感与流程合理性以用户审核为准 **相关提交** - `38dbaed` docs(#40): add stage A shopee product prototype **门禁状态** - 待用户明确回复「原型通过」;在此之前不修改数据库迁移、Go 服务端、Vue 页面和共享 API
Author
Owner

原型按用户反馈修订(第 2 版)

本次修改

  1. 列头「关联PDD商品」改为「PDD商品」。
  2. PDD 商品ID 显示为链接,新标签打开 PDD 商品详情;新增第 7 屏「PDD商品详情(新标签)」作为跳转目标,页面写明它属于 PDD 商品档案模块(#31),Shopee 商品档案不重复实现商品维护。
  3. 「映射完整度」列删除,改为「参考图」列(56×56 缩略图)。缺失项数量并入状态标记文案:「待完善 · 缺尺码 3 项」「已失效 · 颜色映射 2 项」。
  4. 未关联行不再是死格子:显示「—」加「去关联 ↗」入口,直达关联 PDD 商品页。
  5. PDD 列采用两行:第一行 ID 链接,第二行灰色标题,保证可扫描性。

参考图数据来源的实测结论(影响实现方式)

抓取用户提供的样例 https://www.shunyunbaoerp.com/api/p/file?id=193553649:

HTTP/2 200
content-disposition: attachment;filename=40260586065-8568.jpg
access-control-allow-origin: *
(无 content-type,无 cache-control)
实际内容:JPEG 320x320,22959 字节,响应耗时 2.09 秒

结论与要求:

  • 必须走服务端代理:无 Content-Type 只能靠浏览器嗅探;无缓存头且单张约 2 秒,一屏 6 行直连即 10 秒级裂图。代理需补 Content-Type: image/jpeg、加 Cache-Control,可选生成缩略图。
  • 该 URL 不能用作 <a href>:带 Content-Disposition: attachment,点击会触发下载而非预览。
  • 匿名可访问且 CORS 放开:只需保存 URL,不需要保存任何 SYB 凭据,符合永久规则。
  • 字段归属:shopee_products.image_url 由 #41 导入时写入并允许人工覆盖;列表不实时 join syb_products,避免 #40 反向依赖 #41(#41 的前置本就是 #40)。
  • 多明细取图规则:同一 Shopee 商品可能出现在多条 SYB 明细中,档案主图取最近一次导入的商品主图;规格级图片不在本工单范围。

原型规模:7 个页面、534 个控件、40 条流程线。参考图第一行使用真实 SYB 样例图并以 data URI 内嵌,导出文件完全离线(已确认无外链请求)。

验证:quantux_verify_export → verdict=PASS,wiredCount 13、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。

仍待用户审核,门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型按用户反馈修订(第 2 版) **本次修改** 1. 列头「关联PDD商品」改为「PDD商品」。 2. PDD 商品ID 显示为链接,**新标签**打开 PDD 商品详情;新增第 7 屏「PDD商品详情(新标签)」作为跳转目标,页面写明它属于 PDD 商品档案模块(#31),Shopee 商品档案不重复实现商品维护。 3. 「映射完整度」列删除,改为「参考图」列(56×56 缩略图)。缺失项数量并入状态标记文案:「待完善 · 缺尺码 3 项」「已失效 · 颜色映射 2 项」。 4. 未关联行不再是死格子:显示「—」加「去关联 ↗」入口,直达关联 PDD 商品页。 5. PDD 列采用两行:第一行 ID 链接,第二行灰色标题,保证可扫描性。 **参考图数据来源的实测结论(影响实现方式)** 抓取用户提供的样例 `https://www.shunyunbaoerp.com/api/p/file?id=193553649`: ``` HTTP/2 200 content-disposition: attachment;filename=40260586065-8568.jpg access-control-allow-origin: * (无 content-type,无 cache-control) 实际内容:JPEG 320x320,22959 字节,响应耗时 2.09 秒 ``` 结论与要求: - **必须走服务端代理**:无 Content-Type 只能靠浏览器嗅探;无缓存头且单张约 2 秒,一屏 6 行直连即 10 秒级裂图。代理需补 `Content-Type: image/jpeg`、加 `Cache-Control`,可选生成缩略图。 - **该 URL 不能用作 `<a href>`**:带 `Content-Disposition: attachment`,点击会触发下载而非预览。 - **匿名可访问且 CORS 放开**:只需保存 URL,不需要保存任何 SYB 凭据,符合永久规则。 - **字段归属**:`shopee_products.image_url` 由 #41 导入时写入并允许人工覆盖;列表不实时 join `syb_products`,避免 #40 反向依赖 #41(#41 的前置本就是 #40)。 - **多明细取图规则**:同一 Shopee 商品可能出现在多条 SYB 明细中,档案主图取最近一次导入的商品主图;规格级图片不在本工单范围。 **原型规模**:7 个页面、534 个控件、40 条流程线。参考图第一行使用真实 SYB 样例图并以 data URI 内嵌,导出文件完全离线(已确认无外链请求)。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 13、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。 **仍待用户审核**,门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型按用户反馈修订(第 3 版):术语改「虾皮」+ 批量软删除

已实现的修改

  1. 侧栏「Shopee商品」→「虾皮商品」;页面标题「Shopee 商品档案」→「虾皮商品列表」。
  2. 新建按钮「+ 新建 Shopee 商品」→「+ 新建」,宽度缩到 92px 让位给删除按钮。
  3. 新建右侧新增「删除 (2)」按钮(danger 样式),下方标注「未勾选时按钮置灰不可点」。
  4. 新增第 8 屏「批量删除确认弹窗」和第 9 屏「批量删除结果」。
  5. 全部展示文案 Shopee → 虾皮:36 处控件文案、24 处控件名、3 个屏幕名、应用名和应用描述。导出文件中 Shopee 出现 0 次,shopee_item_id 保留 3 处(程序标识符,未改)。

术语边界(重要)

  • 只改展示文案。shopee_products、shopee_item_id、API 路径保持英文,未做任何改动。
  • 新建页仍然显示「shopee_item_id 全局唯一,创建后不可修改」,让采购员看到的中文术语能对应到接口字段。
  • 建议在 Business-Rules-and-Glossary 增加术语条目:虾皮 = Shopee(展示名),代码与接口一律 shopee。否则后续 agent 和文档会出现两套说法。
  • #32 采购原型中仍是「Shopee」文案,两个原型术语暂不一致;建议在各采购实施工单中按术语表统一,不单独回改已验收的 #32 原型。

批量软删除的设计(原型已表达,需实施时遵守)

  • 引用检查:被 SYB 货运单明细或采购任务引用的虾皮商品不可删除,避免悬空引用。弹窗分「可删除 2 条」「不可删除 1 条(被 5 条 SYB 明细引用)」两组展示。
  • 部分成功:确认后只删可删的,逐条返回「已删除 / 已跳过」和原因,与 #45 批量创建采集任务的结果反馈模式一致,不整批 rollback、不静默跳过。
  • 软删除语义:写 deleted_at,记录操作人与时间;默认列表不显示,筛选器新增「已删除」;恢复后原有 PDD 关联与规格映射保持不变。
  • 幂等:重复提交同一批次不重复删除;已是删除状态的返回「已跳过」而非报错。

必须在实施前解决的数据库问题(本项目首次遇到)
shopee_item_id 要求全局唯一,同时又要软删除。现有代码中:

  • collection_rule、collection_task 有 gorm.DeletedAt,但都没有业务唯一键;
  • pdd_product.goods_id 是单列唯一索引 ux_pdd_product_goods_id,且 PDDProduct 结构体没有 DeletedAt。

所以「唯一键 + 软删除」这个组合项目里还没有先例。若沿用单列唯一索引,软删除后的记录会继续占用 shopee_item_id,导致同一商品无法再次创建,#41 重复导入也会撞唯一键。建议改为复合唯一索引 (shopee_item_id, deleted_at):MySQL 唯一索引允许多个 NULL,deleted_at IS NULL 的存活记录同时只能有一条,已删除记录彼此不冲突。这一条需要在 #40 的迁移里定下来,不能留到 #41。

待确认的假设(原型按此表达,审核时请确认或推翻)

  1. 被引用的虾皮商品禁止删除,而不是"删除后保留引用只读"。
  2. #41 导入遇到已软删除的 shopee_item_id 时复活原记录(保留人工维护的映射),并在导入结果中提示"已恢复 N 条"。
  3. 删除与恢复的权限范围(采购员是否可删,还是仅管理员)尚未定义。

原型规模:9 个页面、611 个控件、44 条流程线。
验证:quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型按用户反馈修订(第 3 版):术语改「虾皮」+ 批量软删除 **已实现的修改** 1. 侧栏「Shopee商品」→「虾皮商品」;页面标题「Shopee 商品档案」→「虾皮商品列表」。 2. 新建按钮「+ 新建 Shopee 商品」→「+ 新建」,宽度缩到 92px 让位给删除按钮。 3. 新建右侧新增「删除 (2)」按钮(danger 样式),下方标注「未勾选时按钮置灰不可点」。 4. 新增第 8 屏「批量删除确认弹窗」和第 9 屏「批量删除结果」。 5. 全部展示文案 Shopee → 虾皮:36 处控件文案、24 处控件名、3 个屏幕名、应用名和应用描述。导出文件中 `Shopee` 出现 0 次,`shopee_item_id` 保留 3 处(程序标识符,未改)。 **术语边界(重要)** - 只改展示文案。`shopee_products`、`shopee_item_id`、API 路径保持英文,未做任何改动。 - 新建页仍然显示「shopee_item_id 全局唯一,创建后不可修改」,让采购员看到的中文术语能对应到接口字段。 - 建议在 `Business-Rules-and-Glossary` 增加术语条目:虾皮 = Shopee(展示名),代码与接口一律 shopee。否则后续 agent 和文档会出现两套说法。 - #32 采购原型中仍是「Shopee」文案,两个原型术语暂不一致;建议在各采购实施工单中按术语表统一,不单独回改已验收的 #32 原型。 **批量软删除的设计(原型已表达,需实施时遵守)** - **引用检查**:被 SYB 货运单明细或采购任务引用的虾皮商品不可删除,避免悬空引用。弹窗分「可删除 2 条」「不可删除 1 条(被 5 条 SYB 明细引用)」两组展示。 - **部分成功**:确认后只删可删的,逐条返回「已删除 / 已跳过」和原因,与 #45 批量创建采集任务的结果反馈模式一致,不整批 rollback、不静默跳过。 - **软删除语义**:写 `deleted_at`,记录操作人与时间;默认列表不显示,筛选器新增「已删除」;恢复后原有 PDD 关联与规格映射保持不变。 - **幂等**:重复提交同一批次不重复删除;已是删除状态的返回「已跳过」而非报错。 **必须在实施前解决的数据库问题(本项目首次遇到)** `shopee_item_id` 要求全局唯一,同时又要软删除。现有代码中: - `collection_rule`、`collection_task` 有 `gorm.DeletedAt`,但都没有业务唯一键; - `pdd_product.goods_id` 是单列唯一索引 `ux_pdd_product_goods_id`,且 `PDDProduct` 结构体没有 `DeletedAt`。 所以「唯一键 + 软删除」这个组合项目里还没有先例。若沿用单列唯一索引,软删除后的记录会继续占用 `shopee_item_id`,导致同一商品无法再次创建,#41 重复导入也会撞唯一键。建议改为复合唯一索引 `(shopee_item_id, deleted_at)`:MySQL 唯一索引允许多个 NULL,`deleted_at IS NULL` 的存活记录同时只能有一条,已删除记录彼此不冲突。这一条需要在 #40 的迁移里定下来,不能留到 #41。 **待确认的假设**(原型按此表达,审核时请确认或推翻) 1. 被引用的虾皮商品**禁止删除**,而不是"删除后保留引用只读"。 2. #41 导入遇到已软删除的 `shopee_item_id` 时**复活原记录**(保留人工维护的映射),并在导入结果中提示"已恢复 N 条"。 3. 删除与恢复的权限范围(采购员是否可删,还是仅管理员)尚未定义。 **原型规模**:9 个页面、611 个控件、44 条流程线。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。 **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型第 4 版:补上虾皮规格值的人工添加能力

用户提问:虾皮商品详情页为什么没有颜色尺码等添加功能?

这是原型的真实缺口,不是有意省略。 前三版隐含假设「虾皮规格值只来自 #41 的 SYB 明细导入」,但这个假设有两个问题:

  1. #40 无法独立使用,与本工单验收标准「虾皮商品档案和规格映射本身可独立使用,不依赖采购任务」冲突。按原设计,通过「新建」创建的虾皮商品没有任何规格值,进入映射编辑页是一张空表,#41 上线前整个模块空转。
  2. 只能被动响应。采购员无法提前准备映射;SYB 明细进来出现未见过的规格值时采购当场卡住,才回头补映射。

对照 #31 已确认的 PDD 商品档案模式:人工可全量维护 + 采集结果自动合并,两条来源并存。虾皮商品档案应沿用同一模式。

本次修改

  1. 映射编辑页新增「来源」列,取值「SYB 导入」或「人工添加」,人工添加以主色高亮。
  2. 新增「+ 添加颜色值」「+ 添加尺码值」入口,以及第 10 屏「添加规格值弹窗」(维度下拉 + 名称输入 + 校验说明 + 规则说明)。
  3. 尺码示例中 2XL 改为「人工添加」,演示提前准备映射但 PDD 暂无可匹配值的场景。
  4. 商品详情页表头「说明」改为「来源 / 说明」,每行标注来源;缺失提示补充「新增规格值请进入编辑映射」。
  5. 映射编辑页顶部说明改写为「虾皮规格值有两个来源:SYB 明细导入自动写入,以及采购员人工添加用于提前准备映射」。

因此确定的业务规则(已写入工单正文)

  • 导入值与人工值按「维度 + 规格值名称」合并,同名不重复创建,合并后来源标记为「SYB 导入」。
  • 人工添加的规格值可以删除;SYB 导入的值不可人工删除,只能清除其映射(保持与外部数据一致)。
  • 人工添加的规格值只用于本地映射查找,不写回 Shopee 平台,也不改变 SYB 明细中的原始数据。
  • 名称需与 SYB 明细写法一致,否则导入时会新增一条而非合并——弹窗中已明确提示该风险。

编辑位置的取舍:详情页保持只读总览,添加与编辑集中在「编辑映射」页,避免同一份数据出现两个编辑入口。若希望详情页直接可编辑,请在审核时说明。

原型规模:10 个页面、641 个控件、50 条流程线。
验证:quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界(映射编辑页高度调整为 1200)。
相关提交:1b6c83a docs(#40): add manual spec value creation to prototype
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型第 4 版:补上虾皮规格值的人工添加能力 **用户提问**:虾皮商品详情页为什么没有颜色尺码等添加功能? **这是原型的真实缺口,不是有意省略。** 前三版隐含假设「虾皮规格值只来自 #41 的 SYB 明细导入」,但这个假设有两个问题: 1. **#40 无法独立使用**,与本工单验收标准「虾皮商品档案和规格映射本身可独立使用,不依赖采购任务」冲突。按原设计,通过「新建」创建的虾皮商品没有任何规格值,进入映射编辑页是一张空表,#41 上线前整个模块空转。 2. **只能被动响应**。采购员无法提前准备映射;SYB 明细进来出现未见过的规格值时采购当场卡住,才回头补映射。 对照 #31 已确认的 PDD 商品档案模式:人工可全量维护 + 采集结果自动合并,两条来源并存。虾皮商品档案应沿用同一模式。 **本次修改** 1. 映射编辑页新增「来源」列,取值「SYB 导入」或「人工添加」,人工添加以主色高亮。 2. 新增「+ 添加颜色值」「+ 添加尺码值」入口,以及第 10 屏「添加规格值弹窗」(维度下拉 + 名称输入 + 校验说明 + 规则说明)。 3. 尺码示例中 2XL 改为「人工添加」,演示提前准备映射但 PDD 暂无可匹配值的场景。 4. 商品详情页表头「说明」改为「来源 / 说明」,每行标注来源;缺失提示补充「新增规格值请进入编辑映射」。 5. 映射编辑页顶部说明改写为「虾皮规格值有两个来源:SYB 明细导入自动写入,以及采购员人工添加用于提前准备映射」。 **因此确定的业务规则(已写入工单正文)** - 导入值与人工值按「维度 + 规格值名称」合并,同名不重复创建,合并后来源标记为「SYB 导入」。 - 人工添加的规格值可以删除;SYB 导入的值不可人工删除,只能清除其映射(保持与外部数据一致)。 - 人工添加的规格值只用于本地映射查找,不写回 Shopee 平台,也不改变 SYB 明细中的原始数据。 - 名称需与 SYB 明细写法一致,否则导入时会新增一条而非合并——弹窗中已明确提示该风险。 **编辑位置的取舍**:详情页保持只读总览,添加与编辑集中在「编辑映射」页,避免同一份数据出现两个编辑入口。若希望详情页直接可编辑,请在审核时说明。 **原型规模**:10 个页面、641 个控件、50 条流程线。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界(映射编辑页高度调整为 1200)。 **相关提交**:`1b6c83a` docs(#40): add manual spec value creation to prototype **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型第 5 版:新建页支持录入规格值(修正一处结构性设计问题)

用户提问:为什么点击「新建」进入新建虾皮商品页时没有新增颜色尺码的功能?

这暴露的是划分错误,不只是缺功能。 前几版把「规格值」和「映射」当成一件事处理,所以添加入口只出现在「编辑映射」页。但两者的依赖完全不同:

  • 虾皮规格值(浅蓝色、XL)是虾皮商品自己的档案数据,录入不需要任何 PDD 信息;
  • 映射(虾皮 XL → PDD XL)才依赖已关联的 PDD 商品,没有关联就没有可选目标。

把档案数据的录入挂在依赖 PDD 的页面下,导致新建出来的商品必然是空壳,用户也找不到入口。

修正后的职责划分

数据 维护位置 依赖
商品档案(ID / 标题 / 店铺) 新建页、详情页 无
虾皮规格值(颜色值、尺码值) 新建页、映射编辑页就地补录、#41 导入 无
规格映射(虾皮值 → PDD 值) 映射编辑页 必须先关联 PDD 商品

本次修改

  1. 新建页新增「规格值(可选)」区块:颜色值和尺码值各有输入框 + 「+ 添加」按钮,已添加值以可移除的标签展示(示例:浅蓝色、深灰色 / M、L、XL)。屏幕高度调整为 1080。
  2. 区块内写明「只录虾皮侧的颜色和尺码名称,不涉及 PDD。留空也可以保存,之后在详情页补充」,并提示名称需与 SYB 明细写法一致,否则导入会新增而不是合并。
  3. 顶部提示由「创建后再关联」改为「一次录完档案与规格值」,说明映射需先关联 PDD 商品。
  4. 右侧规则卡补充「规格值可在创建时录入,也可留空稍后补充;映射必须先关联 PDD 商品」。
  5. 映射编辑页文案调整,明确本页职责是映射,「+ 添加颜色值 / 尺码值」定位为就地补录,效果与新建页录入一致,不再是唯一入口。
  6. 详情页缺失提示改为「规格值可在本页或编辑映射页添加」。

由此确定的规则

  • 规格值属于虾皮商品档案,可在创建时录入、留空稍后补充、或由 #41 导入写入,三条路径写入同一份数据。
  • 创建时录入规格值不要求已关联 PDD 商品,保存后商品状态为「未关联 PDD 商品」,符合既有状态定义。
  • 无论从哪个入口添加,导入值与人工值仍按「维度 + 规格值名称」合并,同名不重复创建。

原型规模:10 个页面、667 个控件、50 条流程线。
验证:quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。
相关提交:abd6984 docs(#40): allow spec value entry on create page in prototype
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型第 5 版:新建页支持录入规格值(修正一处结构性设计问题) **用户提问**:为什么点击「新建」进入新建虾皮商品页时没有新增颜色尺码的功能? **这暴露的是划分错误,不只是缺功能。** 前几版把「规格值」和「映射」当成一件事处理,所以添加入口只出现在「编辑映射」页。但两者的依赖完全不同: - **虾皮规格值**(浅蓝色、XL)是虾皮商品自己的档案数据,录入不需要任何 PDD 信息; - **映射**(虾皮 XL → PDD XL)才依赖已关联的 PDD 商品,没有关联就没有可选目标。 把档案数据的录入挂在依赖 PDD 的页面下,导致新建出来的商品必然是空壳,用户也找不到入口。 **修正后的职责划分** | 数据 | 维护位置 | 依赖 | |---|---|---| | 商品档案(ID / 标题 / 店铺) | 新建页、详情页 | 无 | | 虾皮规格值(颜色值、尺码值) | **新建页**、映射编辑页就地补录、#41 导入 | 无 | | 规格映射(虾皮值 → PDD 值) | 映射编辑页 | 必须先关联 PDD 商品 | **本次修改** 1. 新建页新增「规格值(可选)」区块:颜色值和尺码值各有输入框 + 「+ 添加」按钮,已添加值以可移除的标签展示(示例:浅蓝色、深灰色 / M、L、XL)。屏幕高度调整为 1080。 2. 区块内写明「只录虾皮侧的颜色和尺码名称,不涉及 PDD。留空也可以保存,之后在详情页补充」,并提示名称需与 SYB 明细写法一致,否则导入会新增而不是合并。 3. 顶部提示由「创建后再关联」改为「一次录完档案与规格值」,说明映射需先关联 PDD 商品。 4. 右侧规则卡补充「规格值可在创建时录入,也可留空稍后补充;映射必须先关联 PDD 商品」。 5. 映射编辑页文案调整,明确本页职责是映射,「+ 添加颜色值 / 尺码值」定位为**就地补录**,效果与新建页录入一致,不再是唯一入口。 6. 详情页缺失提示改为「规格值可在本页或编辑映射页添加」。 **由此确定的规则** - 规格值属于虾皮商品档案,可在创建时录入、留空稍后补充、或由 #41 导入写入,三条路径写入同一份数据。 - 创建时录入规格值不要求已关联 PDD 商品,保存后商品状态为「未关联 PDD 商品」,符合既有状态定义。 - 无论从哪个入口添加,导入值与人工值仍按「维度 + 规格值名称」合并,同名不重复创建。 **原型规模**:10 个页面、667 个控件、50 条流程线。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。 **相关提交**:`abd6984` docs(#40): allow spec value entry on create page in prototype **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型第 6 版:新建页增加选填的 PDD 商品选择器

决策:加,但做成「搜索 + 选择」,不做成手打 PDD 商品ID 的输入框。

裸输入框会丢掉关联动作里四件必要的校验与知情提示,只能在保存时报错:

  1. 商品存在性;
  2. 状态校验(disabled 的 PDD 商品不可关联);
  3. 共用提示(已被 N 个虾皮商品关联,共用合法但需知情);
  4. 当前规格概览(决定接下来映射能否进行)。

真要把输入框做对,就得加即时校验、防抖查询和候选列表——本质上又变回选择器,只是体验更差。

本次修改(新建虾皮商品页,屏幕高度 1080 → 1380)

  1. 新增「PDD 商品(选填)」卡片,位于规格值区块之后:搜索框 + 搜索按钮 + 「已选择 1 个」计数。
  2. 选中后展示确认卡:PDD-88790(链接色)、标题「高腰阔腿裤 垂感直筒 · 轻风女装旗舰店 · 颜色 2 · 尺码 4」、active 状态标记、「已被 1 个虾皮商品关联(允许共用)」,以及「更换」按钮(连线到关联 PDD 商品页)。
  3. 卡片底部固定提示:选择 PDD 商品后仍需完成规格映射才能采购;保存后进入详情页继续。 避免采购员误以为填了 PDD 就完成了。
  4. 说明行写明「搜索并选择,不直接输入 ID:选择时即校验商品存在、状态可用,并显示是否已被其他虾皮商品共用」。
  5. 顶部提示与右侧规则卡同步:PDD 商品为选填,留空保存后状态为「未关联 PDD 商品」。

明确不在新建页做的事
选中 PDD 商品后不展开规格映射。否则新建页变成「档案 + 规格值 + 关联 + 映射」四合一表单,一次提交写三张表,回滚与幂等语义显著复杂化。保存后跳详情页并提示「下一步:完成规格映射」。

关联页保留:改绑 PDD 商品是独立的高频操作,不能只在创建时可选。

原型规模:10 个页面、683 个控件、51 条流程线。
验证:quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。
相关提交:8551256 docs(#40): add optional pdd product picker on create page
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型第 6 版:新建页增加选填的 PDD 商品选择器 **决策**:加,但做成「搜索 + 选择」,**不做成手打 PDD 商品ID 的输入框**。 裸输入框会丢掉关联动作里四件必要的校验与知情提示,只能在保存时报错: 1. 商品存在性; 2. 状态校验(`disabled` 的 PDD 商品不可关联); 3. 共用提示(已被 N 个虾皮商品关联,共用合法但需知情); 4. 当前规格概览(决定接下来映射能否进行)。 真要把输入框做对,就得加即时校验、防抖查询和候选列表——本质上又变回选择器,只是体验更差。 **本次修改**(新建虾皮商品页,屏幕高度 1080 → 1380) 1. 新增「PDD 商品(选填)」卡片,位于规格值区块之后:搜索框 + 搜索按钮 + 「已选择 1 个」计数。 2. 选中后展示确认卡:`PDD-88790`(链接色)、标题「高腰阔腿裤 垂感直筒 · 轻风女装旗舰店 · 颜色 2 · 尺码 4」、`active` 状态标记、「已被 1 个虾皮商品关联(允许共用)」,以及「更换」按钮(连线到关联 PDD 商品页)。 3. 卡片底部固定提示:**选择 PDD 商品后仍需完成规格映射才能采购;保存后进入详情页继续。** 避免采购员误以为填了 PDD 就完成了。 4. 说明行写明「搜索并选择,不直接输入 ID:选择时即校验商品存在、状态可用,并显示是否已被其他虾皮商品共用」。 5. 顶部提示与右侧规则卡同步:PDD 商品为选填,留空保存后状态为「未关联 PDD 商品」。 **明确不在新建页做的事** 选中 PDD 商品后不展开规格映射。否则新建页变成「档案 + 规格值 + 关联 + 映射」四合一表单,一次提交写三张表,回滚与幂等语义显著复杂化。保存后跳详情页并提示「下一步:完成规格映射」。 **关联页保留**:改绑 PDD 商品是独立的高频操作,不能只在创建时可选。 **原型规模**:10 个页面、683 个控件、51 条流程线。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。 **相关提交**:`8551256` docs(#40): add optional pdd product picker on create page **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型第 7 版:虾皮售价加入列表、详情与新建页

用户提问:虾皮商品是不是列表、详情、新建都没有价格?

确认:此前三处均无价格,价格只出现在「PDD商品详情(新标签)」屏的颜色价格;#40 与 #41 正文也从未提及价格。用户选择加入虾皮售价。

本次修改

  1. 列表页:新增「售价」列,重排列宽为 参考图 64 / 虾皮商品ID 116 / 标题 166 / 店铺 76 / 售价 104 / PDD商品 196 / 状态 206 / 操作 120(内容区 1120 内)。售价单元格两行:金额 + 来源(SYB 导入 / 未录入)。未录入行显示「—」。
  2. 详情页:档案卡增加「售价(参考)」行,显示「NT$ 559.00 · 来源:SYB 导入 2026-08-18」,下方注明参考语义。档案卡与关联卡高度 260 → 308,其余内容整体下移 48,屏幕高度 1120 → 1168。
  3. 新建页:店铺输入框收窄为 340,同一行右侧新增「售价(参考)· 选填」输入框与币种下拉(NT$ / RM / S$ / ฿ / ₱ / Rp),下方注明「参考售价,实际成交价以 SYB 明细为准;币种随虾皮站点」。页面未加高。

必须在实施前确认的三点

  1. SYB 明细是否真的提供售价字段。 参考图已实测确认(顺云宝 ERP 图片 URL),售价字段尚未验证。若明细中没有售价,则该字段退化为纯人工维护。
  2. 币种必须与金额一起保存。 虾皮是跨境平台,售价通常不是人民币,而 PDD 采购价是人民币。只存金额不存币种,数字会被误读,且无法与采购价比较。建议 sale_price_cent(整数分,与 #31 的 priceCent 保持一致)+ currency(ISO 4217)。原型样例统一用 NT$,实际币种需要确认。
  3. 语义是「参考售价」不是权威成交价。 同一虾皮商品在不同货运单、不同时间的成交价可能不同;档案上只能保存"最近一次导入或人工维护的值"。UI 三处均已标注该语义,避免被当作当前售价用于毛利计算。真实成交价以 SYB 明细为准(属 #41 数据域)。

毛利计算不在本工单范围:需要售价、采购价与汇率三者齐备,且只能在 SYB 明细级计算。本工单只做展示。

原型规模:10 个页面、704 个控件、63 条流程线。
验证:quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。
相关提交:61e742d docs(#40): add shopee sale price to prototype list, detail and create
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型第 7 版:虾皮售价加入列表、详情与新建页 **用户提问**:虾皮商品是不是列表、详情、新建都没有价格? 确认:此前三处均无价格,价格只出现在「PDD商品详情(新标签)」屏的颜色价格;#40 与 #41 正文也从未提及价格。**用户选择加入虾皮售价。** **本次修改** 1. **列表页**:新增「售价」列,重排列宽为 参考图 64 / 虾皮商品ID 116 / 标题 166 / 店铺 76 / 售价 104 / PDD商品 196 / 状态 206 / 操作 120(内容区 1120 内)。售价单元格两行:金额 + 来源(SYB 导入 / 未录入)。未录入行显示「—」。 2. **详情页**:档案卡增加「售价(参考)」行,显示「NT$ 559.00 · 来源:SYB 导入 2026-08-18」,下方注明参考语义。档案卡与关联卡高度 260 → 308,其余内容整体下移 48,屏幕高度 1120 → 1168。 3. **新建页**:店铺输入框收窄为 340,同一行右侧新增「售价(参考)· 选填」输入框与币种下拉(NT$ / RM / S$ / ฿ / ₱ / Rp),下方注明「参考售价,实际成交价以 SYB 明细为准;币种随虾皮站点」。页面未加高。 **必须在实施前确认的三点** 1. **SYB 明细是否真的提供售价字段。** 参考图已实测确认(顺云宝 ERP 图片 URL),售价字段尚未验证。若明细中没有售价,则该字段退化为纯人工维护。 2. **币种必须与金额一起保存。** 虾皮是跨境平台,售价通常不是人民币,而 PDD 采购价是人民币。只存金额不存币种,数字会被误读,且无法与采购价比较。建议 `sale_price_cent`(整数分,与 #31 的 `priceCent` 保持一致)+ `currency`(ISO 4217)。**原型样例统一用 NT$,实际币种需要确认。** 3. **语义是「参考售价」不是权威成交价。** 同一虾皮商品在不同货运单、不同时间的成交价可能不同;档案上只能保存"最近一次导入或人工维护的值"。UI 三处均已标注该语义,避免被当作当前售价用于毛利计算。真实成交价以 SYB 明细为准(属 #41 数据域)。 **毛利计算不在本工单范围**:需要售价、采购价与汇率三者齐备,且只能在 SYB 明细级计算。本工单只做展示。 **原型规模**:10 个页面、704 个控件、63 条流程线。 **验证**:`quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。 **相关提交**:`61e742d` docs(#40): add shopee sale price to prototype list, detail and create **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

原型第 8 版:币种改为系统配置,修正符号当数据存的错误

用户提问:价格单位列表是写死的还是可以配置的?

原型第 7 版是写死的,而且存在一个实质错误。本次一并修正。

修正一:不能把显示符号当数据存
第 7 版下拉里放的是 NT$ / RM / S$ 等显示符号。符号有歧义($ 可指 USD / SGD / HKD / TWD),不能作为存储值。改为 ISO 4217 代码:TWD / MYR / SGD / THB / PHP / IDR,符号仅用于渲染。列表与详情页的展示同步标注代码(NT$ 559.00(TWD))。

修正二:币种不逐商品选择,改为系统配置
虾皮店铺属于某个站点,站点决定币种,同一店铺所有商品币种必然相同。让采购员逐商品自由选,只会制造同店铺多币种的脏数据,且无业务价值。

三种归属层次的取舍:

  1. 挂店铺(语义最正确):需要新建店铺档案表,shopee_products.shop_name 从字符串改为外键,并补店铺管理页。超出 #40 当前范围。
  2. 系统默认币种(本次采用):用 go-admin 已有的 sys_config 配置一个默认币种,新建页只读展示,不可逐商品修改。零新增基础设施,杜绝同店铺多币种。
  3. 逐商品自由选:已否决。

本次修改:新建页币种下拉改为只读展示「TWD (NT$)」+ 副标「系统默认 · 不可逐商品修改」;说明改为「币种由系统配置统一设置(sys_config),按 ISO 4217 存储,符号仅用于显示;需要变更请在管理端系统配置中调整」。右侧规则卡补充对应条目。

关于底座既有能力的核查结果

  • go-admin 底座已自带 sys_dict_type / sys_dict_data / sys_config,前端已有 web/src/api/admin/dict/{data,type}.js。
  • 但 goauto 业务模块目前未使用任何字典(代码内零命中),config.yaml 也只有 database 与 ports,无业务配置。
  • 因此币种不需要新建表:默认值走 sys_config;若将来确需多站点,候选项再走 sys_dict_data 建 shopee_currency 字典。服务端校验白名单 = 配置值 ∩ ISO 4217。

遗留:若后续确认为多站点经营,应回到方案 1(币种挂店铺档案),届时单独建单,不在 #40 内扩张。

原型规模:10 个页面,verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0;几何检查 0 越界。
门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。

## 原型第 8 版:币种改为系统配置,修正符号当数据存的错误 **用户提问**:价格单位列表是写死的还是可以配置的? 原型第 7 版是写死的,而且存在一个实质错误。本次一并修正。 **修正一:不能把显示符号当数据存** 第 7 版下拉里放的是 `NT$` / `RM` / `S$` 等显示符号。符号有歧义(`$` 可指 USD / SGD / HKD / TWD),不能作为存储值。改为 **ISO 4217 代码**:`TWD` / `MYR` / `SGD` / `THB` / `PHP` / `IDR`,符号仅用于渲染。列表与详情页的展示同步标注代码(`NT$ 559.00(TWD)`)。 **修正二:币种不逐商品选择,改为系统配置** 虾皮店铺属于某个站点,站点决定币种,同一店铺所有商品币种必然相同。让采购员逐商品自由选,只会制造同店铺多币种的脏数据,且无业务价值。 三种归属层次的取舍: 1. **挂店铺**(语义最正确):需要新建店铺档案表,`shopee_products.shop_name` 从字符串改为外键,并补店铺管理页。超出 #40 当前范围。 2. **系统默认币种**(本次采用):用 go-admin 已有的 `sys_config` 配置一个默认币种,新建页只读展示,不可逐商品修改。零新增基础设施,杜绝同店铺多币种。 3. 逐商品自由选:已否决。 **本次修改**:新建页币种下拉改为只读展示「TWD (NT$)」+ 副标「系统默认 · 不可逐商品修改」;说明改为「币种由系统配置统一设置(sys_config),按 ISO 4217 存储,符号仅用于显示;需要变更请在管理端系统配置中调整」。右侧规则卡补充对应条目。 **关于底座既有能力的核查结果** - go-admin 底座已自带 `sys_dict_type` / `sys_dict_data` / `sys_config`,前端已有 `web/src/api/admin/dict/{data,type}.js`。 - **但 goauto 业务模块目前未使用任何字典**(代码内零命中),`config.yaml` 也只有 database 与 ports,无业务配置。 - 因此币种不需要新建表:默认值走 `sys_config`;若将来确需多站点,候选项再走 `sys_dict_data` 建 `shopee_currency` 字典。服务端校验白名单 = 配置值 ∩ ISO 4217。 **遗留**:若后续确认为多站点经营,应回到方案 1(币种挂店铺档案),届时单独建单,不在 #40 内扩张。 **原型规模**:10 个页面,`verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0;几何检查 0 越界。 **门禁不变**:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
Author
Owner

Stage A 原型验收通过

用户 2026-08-18 明确回复「虾皮商品模块的原型通过验收」。Stage A 门禁解除,Stage B 代码实施可以开始。

已确认的原型

  • QuantUX App ID 6a83b708191a826306a7eeb1
  • 线上:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html
  • 离线导出:prototypes/quantux-shopee-product-6a83b708191a826306a7eeb1.html
  • 规模:10 个页面、704+ 控件、63 条流程线;quantux_verify_export = PASS,runtimeErrors 0,几何检查 0 越界

页面清单
虾皮商品列表 / 虾皮商品详情 / 新建虾皮商品 / 关联PDD商品 / 颜色尺码映射编辑 / 映射失效复核 / PDD商品详情(新标签) / 批量删除确认弹窗 / 批量删除结果 / 添加规格值弹窗

经过 8 轮修订确认的设计决策(Stage B 必须遵守)

  1. 展示术语统一「虾皮」;shopee_products、shopee_item_id、API 路径等程序标识符保持英文。
  2. 列表列:参考图、虾皮商品ID、标题、店铺、售价、PDD商品(ID 链接,新标签打开)、状态、操作;不设映射完整度列,缺失项数量并入状态文案。
  3. 参考图存 image_url(SYB 图片 URL),必须服务端代理:源接口无 Content-Type、带 Content-Disposition: attachment、无缓存头、单张约 2 秒。
  4. 售价 sale_price_cent + currency(ISO 4217 代码,不存符号);币种取系统配置默认值,不逐商品选择。
  5. 规格值属于商品档案:新建页可录入、映射页可就地补录、#41 导入写入;按「维度 + 名称」合并;人工值可删,导入值不可删只能清除映射。
  6. 关联 PDD 商品统一走搜索选择器,不提供手工输入商品ID 的入口。
  7. 批量软删除:引用检查(被 SYB 明细或采购任务引用的不可删)、部分成功逐条反馈、deleted_at + 操作人、可筛选「已删除」并恢复。
  8. shopee_item_id 唯一约束需与软删除并存:建议复合唯一索引 (shopee_item_id, deleted_at),避免已删除记录阻塞重新创建与 #41 重复导入。这是本项目首次出现「业务唯一键 + 软删除」组合,须在 #40 迁移中定下。

文档同步(Wiki-first,镜像已导出并检查一致)

  • Product-Requirements-Overview:#40 状态改为「原型 2026-08-18 已确认,Stage B 代码待实施」
  • Delivery-Issues:T38 标注 Stage A 已通过、Stage B 待实施

仍待确认的假设(Stage B 实施前需要答复)

  1. SYB 明细是否真的提供售价字段(参考图已实测确认,售价未验证)。
  2. #41 导入遇到已软删除的 shopee_item_id 时是否复活原记录并保留人工映射。
  3. 删除与恢复的权限范围(采购员 / 仅管理员)。
  4. 售价样例币种为 TWD,实际站点币种待确认。

未验证部分:无浏览器环境,未做人工视觉走查;原型观感以用户本次审核为准。

工单保持 open:Stage A 完成,Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。

## Stage A 原型验收通过 用户 2026-08-18 明确回复「虾皮商品模块的原型通过验收」。Stage A 门禁解除,Stage B 代码实施可以开始。 **已确认的原型** - QuantUX App ID `6a83b708191a826306a7eeb1` - 线上:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html - 离线导出:`prototypes/quantux-shopee-product-6a83b708191a826306a7eeb1.html` - 规模:10 个页面、704+ 控件、63 条流程线;`quantux_verify_export` = `PASS`,runtimeErrors 0,几何检查 0 越界 **页面清单** 虾皮商品列表 / 虾皮商品详情 / 新建虾皮商品 / 关联PDD商品 / 颜色尺码映射编辑 / 映射失效复核 / PDD商品详情(新标签) / 批量删除确认弹窗 / 批量删除结果 / 添加规格值弹窗 **经过 8 轮修订确认的设计决策(Stage B 必须遵守)** 1. 展示术语统一「虾皮」;`shopee_products`、`shopee_item_id`、API 路径等程序标识符保持英文。 2. 列表列:参考图、虾皮商品ID、标题、店铺、售价、PDD商品(ID 链接,新标签打开)、状态、操作;不设映射完整度列,缺失项数量并入状态文案。 3. 参考图存 `image_url`(SYB 图片 URL),**必须服务端代理**:源接口无 Content-Type、带 Content-Disposition: attachment、无缓存头、单张约 2 秒。 4. 售价 `sale_price_cent` + `currency`(ISO 4217 代码,不存符号);币种取系统配置默认值,不逐商品选择。 5. 规格值属于商品档案:新建页可录入、映射页可就地补录、#41 导入写入;按「维度 + 名称」合并;人工值可删,导入值不可删只能清除映射。 6. 关联 PDD 商品统一走搜索选择器,不提供手工输入商品ID 的入口。 7. 批量软删除:引用检查(被 SYB 明细或采购任务引用的不可删)、部分成功逐条反馈、`deleted_at` + 操作人、可筛选「已删除」并恢复。 8. **`shopee_item_id` 唯一约束需与软删除并存**:建议复合唯一索引 `(shopee_item_id, deleted_at)`,避免已删除记录阻塞重新创建与 #41 重复导入。这是本项目首次出现「业务唯一键 + 软删除」组合,须在 #40 迁移中定下。 **文档同步(Wiki-first,镜像已导出并检查一致)** - `Product-Requirements-Overview`:#40 状态改为「原型 2026-08-18 已确认,Stage B 代码待实施」 - `Delivery-Issues`:T38 标注 Stage A 已通过、Stage B 待实施 **仍待确认的假设(Stage B 实施前需要答复)** 1. SYB 明细是否真的提供售价字段(参考图已实测确认,售价未验证)。 2. #41 导入遇到已软删除的 `shopee_item_id` 时是否复活原记录并保留人工映射。 3. 删除与恢复的权限范围(采购员 / 仅管理员)。 4. 售价样例币种为 TWD,实际站点币种待确认。 **未验证部分**:无浏览器环境,未做人工视觉走查;原型观感以用户本次审核为准。 **工单保持 open**:Stage A 完成,Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。
Author
Owner

SYB 明细数据实测(demo/shunyunbaoerp_stock_list.har)+ 四点确认回复

针对 Stage A 验收评论中列出的 4 项待确认假设逐一回复。

① SYB 是否有售价字段 —— 有,但粒度是订单明细行,不是商品档案

实测 POST /am/stock/detail/listByStock 真实响应:

"details": [
  {"productId": 50209124255, "productPrice": 239.0, "productSpec": "白色,L【建議50-60公斤】", "productTitle": "蕾絲花邊拼接背心女..."},
  {"productId": 50712076553, "productPrice": 439.0, "productSpec": "黑色+白色【純棉兩件裝】 簡約親膚,L【建議52.5-60公斤】", "productTitle": "不規則T恤女..."}
]

字段确认:

  • productPrice:明细行级售价(该笔订单中该虾皮商品的成交单价),十进制,非整数分。不是商品档案级字段,同一个 productId(虾皮商品ID)在不同订单里的 productPrice 可能不同(促销、时间差异)。这印证了此前定的语义——档案上只能存「最近一次导入的参考值」,不是权威成交价,真实成交价以明细为准。
  • 无任何 currency 字段:整份响应、所有接口、所有 header(含 accept-language: zh-CN)都没有币种标识。台币场景下 239.0 就是台币元的整数金额,没有小数位。这印证了「币种从系统配置读,不从 SYB 数据推断」是唯一可行方案——数据源本身给不出币种,这条设计不用改。
  • 订单级还有 amtOrder(整单金额)和 escrowAmount(托收金额),这两个是订单维度,跟单件商品售价无关,不要跟 productPrice 混用。

连带发现(超出 #40 范围,记录给 #41):productSpec 是颜色和尺码合并在一起的自由文本,例如 "白色,L【建議50-60公斤】",不是分离的颜色字段和尺码字段。#41 做 SYB 明细解析时,颜色/尺码拆分需要一层文本解析规则(而且备注信息夹在中括号里),不能假设逗号分隔就是可靠的规则。这会直接影响 #41 Stage A 原型怎么画导入结果页,先记在这里。

图片字段确认:详情响应里 productThumb: 190639637 是一个 ID,不是完整 URL。此前实测的图片地址 https://www.shunyunbaoerp.com/api/p/file?id=<id> 中的 id 就是这个 productThumb,两次实测互相印证,拼接规则确认无误。

对 #40 字段设计的修正:sale_price_cent 的取数逻辑应描述为「按 shopee_item_id 关联 SYB 明细,取该商品最近一次出现的 productPrice(四舍五入取整后 ×100 存分)」,而不是笼统的「最近一次导入」。已更新到工单正文。

② 已软删除的 shopee_item_id 遇到 #41 重复导入——复活

采纳。#41 导入时若命中已软删除的 shopee_item_id,清空 deleted_at 复活原记录,保留其人工维护的规格映射与关联的 PDD 商品,导入结果中明确提示「已恢复 N 条」。已写入 #40 正文。

③ 删除与恢复权限——采购员和管理员都可以

原型里未画角色区分是对的,不用改。#40 的批量删除、软删除恢复对采购员和管理员开放同一套流程,不额外做权限分支。

④ 币种——TWD,且已验证确实无法从数据自动判定

与上面 ① 的实测结论一致:系统配置默认值 = TWD,原型里的样例币种不用改。

结论:原型无需因这次实测再修改(图片拼接规则、币种不可推断两点都印证了已有设计),只更新工单正文里售价字段的取数说明。

## SYB 明细数据实测(demo/shunyunbaoerp_stock_list.har)+ 四点确认回复 针对 Stage A 验收评论中列出的 4 项待确认假设逐一回复。 ### ① SYB 是否有售价字段 —— 有,但粒度是订单明细行,不是商品档案 实测 `POST /am/stock/detail/listByStock` 真实响应: ```json "details": [ {"productId": 50209124255, "productPrice": 239.0, "productSpec": "白色,L【建議50-60公斤】", "productTitle": "蕾絲花邊拼接背心女..."}, {"productId": 50712076553, "productPrice": 439.0, "productSpec": "黑色+白色【純棉兩件裝】 簡約親膚,L【建議52.5-60公斤】", "productTitle": "不規則T恤女..."} ] ``` 字段确认: - **`productPrice`**:明细行级售价(该笔订单中该虾皮商品的成交单价),十进制,非整数分。**不是**商品档案级字段,同一个 `productId`(虾皮商品ID)在不同订单里的 `productPrice` 可能不同(促销、时间差异)。这印证了此前定的语义——档案上只能存「最近一次导入的参考值」,不是权威成交价,真实成交价以明细为准。 - **无任何 currency 字段**:整份响应、所有接口、所有 header(含 `accept-language: zh-CN`)都没有币种标识。台币场景下 `239.0` 就是台币元的整数金额,没有小数位。这**印证了「币种从系统配置读,不从 SYB 数据推断」是唯一可行方案**——数据源本身给不出币种,这条设计不用改。 - 订单级还有 `amtOrder`(整单金额)和 `escrowAmount`(托收金额),这两个是订单维度,跟单件商品售价无关,不要跟 `productPrice` 混用。 **连带发现(超出 #40 范围,记录给 #41)**:`productSpec` 是**颜色和尺码合并在一起的自由文本**,例如 `"白色,L【建議50-60公斤】"`,不是分离的颜色字段和尺码字段。#41 做 SYB 明细解析时,颜色/尺码拆分需要一层文本解析规则(而且备注信息夹在中括号里),不能假设逗号分隔就是可靠的规则。这会直接影响 #41 Stage A 原型怎么画导入结果页,先记在这里。 **图片字段确认**:详情响应里 `productThumb: 190639637` 是一个 ID,不是完整 URL。此前实测的图片地址 `https://www.shunyunbaoerp.com/api/p/file?id=<id>` 中的 `id` 就是这个 `productThumb`,两次实测互相印证,拼接规则确认无误。 **对 #40 字段设计的修正**:`sale_price_cent` 的取数逻辑应描述为「按 `shopee_item_id` 关联 SYB 明细,取该商品最近一次出现的 `productPrice`(四舍五入取整后 ×100 存分)」,而不是笼统的「最近一次导入」。已更新到工单正文。 ### ② 已软删除的 `shopee_item_id` 遇到 #41 重复导入——复活 采纳。#41 导入时若命中已软删除的 `shopee_item_id`,**清空 `deleted_at` 复活原记录**,保留其人工维护的规格映射与关联的 PDD 商品,导入结果中明确提示「已恢复 N 条」。已写入 #40 正文。 ### ③ 删除与恢复权限——采购员和管理员都可以 原型里未画角色区分是对的,不用改。#40 的批量删除、软删除恢复对采购员和管理员开放同一套流程,不额外做权限分支。 ### ④ 币种——TWD,且已验证确实无法从数据自动判定 与上面 ① 的实测结论一致:系统配置默认值 = TWD,原型里的样例币种不用改。 **结论:原型无需因这次实测再修改**(图片拼接规则、币种不可推断两点都印证了已有设计),只更新工单正文里售价字段的取数说明。
Author
Owner

原型第 9 版:按 #46 决策变更修订,需重新验收

背景:本工单 Stage A 原型于 2026-08-18 验收通过,但同日 #46 的决策变更使其中部分表述失效。已验收但内容过时的原型风险最高(会被当作可信的实现依据),故按 #46 阶段二优先修订。

失效并已改写的表述

位置 原表述 现表述
列表页提示 「PDD 规格更新导致映射失效时只标记,不自动猜测替换值」 标记待复核,系统给出候选但不自动替换;缺失或失效的映射在采购时由服务端 AI 匹配处理,不阻断采购
映射编辑页提示 「系统不会猜测或自动填充缺失映射」 映射由人工确认,系统只给候选;名称完全相等时自动预填并置于「待确认」
映射失效复核页 「只标记,不自动替换」 AI 给出候选建议 + 置信度 + 理由,人工确认后才写入

导出文件中「不自动猜测替换值」出现 0 次。

映射编辑页重建

新增映射来源列,与既有的规格值来源区分开——两者是不同维度,此前混为一谈:

  • 规格值来源(该规格值哪来的):SYB 导入 / 人工添加
  • 映射来源(该映射谁定的):人工 / 精确匹配 / AI 建议

表格列:虾皮规格值 + 值来源 / 映射到 PDD 规格值 / 映射来源 / 状态 / 操作。

状态新增 待确认。示例行覆盖全部组合:

  • 浅蓝色(SYB 导入)→ 浅蓝 · 精确匹配 · 待确认
  • 深灰色(SYB 导入)→ 深灰 · 人工 · 已确认
  • M、L(SYB 导入)→ 精确匹配 · 待确认
  • XL(SYB 导入)→ AI 建议 · 待确认,附「置信度 0.86 · 理由:名称完全一致且同为尺码维度」
  • 2XL(人工添加)→ 未映射,注明「采购时若 PDD 已补充规格,由服务端 AI 匹配处理,不阻断采购」

新增 「一键确认全部精确匹配 (3)」 入口,并明确限定:仅对「映射来源 = 精确匹配」且待确认的行生效,AI 建议不在此列,必须逐条确认。

新增警示条(AGENTS.md 风险提示要求):

名称相同不代表实物尺寸相同 —— 台湾虾皮尺码与大陆 PDD 尺码标准可能相差一号(如虾皮「L【建議52.5-60公斤】」与 PDD「L」)。确认前请核对尺寸表。

映射失效复核页重建

由「只标记」改为「AI 给候选、人工确认」:每个失效项给出 AI 候选下拉(含「(不采纳建议)」选项)、置信度与理由、「确认映射」按钮。规则卡写明:AI 候选只是建议,人工确认后才写入映射;未处理项不清除、不自动替换;若采购时仍未处理,由服务端 AI 按 #46 流程处理,不阻断采购。

商品详情页

映射表「来源 / 说明」列改为**「映射来源 / 状态」**,逐行标注(如「SYB 导入值 · 精确匹配待确认」「SYB 导入值 · AI 建议待确认」「人工添加值 · 未映射,采购时由 AI 匹配」);顶部提示改为「该商品有 3 项映射待确认」。

规模与验证

  • 10 个页面、721 个控件、71 条流程线(上一版 683 / 51)
  • quantux_verify_export → verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件
  • 几何检查 0 越界;过时文案扫描 0 残留
  • 离线导出无外链请求
  • 相关提交:88e4506 docs(#40): revise prototype for AI matching per #46

需要重新验收

本次修改涉及流程、状态与业务含义变化,不属于免原型的纯显示文案调整。请重新审核并明确回复「原型通过」;在此之前 Stage B 代码实施仍不得开始。

线上:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html

## 原型第 9 版:按 #46 决策变更修订,需重新验收 **背景**:本工单 Stage A 原型于 2026-08-18 验收通过,但同日 [#46](https://git.ilapage.cn/OPC/goauto/issues/46) 的决策变更使其中部分表述失效。**已验收但内容过时的原型风险最高**(会被当作可信的实现依据),故按 #46 阶段二优先修订。 ### 失效并已改写的表述 | 位置 | 原表述 | 现表述 | |---|---|---| | 列表页提示 | 「PDD 规格更新导致映射失效时只标记,**不自动猜测替换值**」 | 标记待复核,系统给出候选但不自动替换;缺失或失效的映射在采购时由服务端 AI 匹配处理,不阻断采购 | | 映射编辑页提示 | 「**系统不会猜测或自动填充缺失映射**」 | 映射由人工确认,系统只给候选;名称完全相等时自动预填并置于「待确认」 | | 映射失效复核页 | 「只标记,不自动替换」 | AI 给出候选建议 + 置信度 + 理由,人工确认后才写入 | 导出文件中「不自动猜测替换值」出现 0 次。 ### 映射编辑页重建 新增**映射来源**列,与既有的**规格值来源**区分开——两者是不同维度,此前混为一谈: - **规格值来源**(该规格值哪来的):`SYB 导入` / `人工添加` - **映射来源**(该映射谁定的):`人工` / `精确匹配` / `AI 建议` 表格列:虾皮规格值 + 值来源 / 映射到 PDD 规格值 / 映射来源 / 状态 / 操作。 状态新增 **`待确认`**。示例行覆盖全部组合: - 浅蓝色(SYB 导入)→ 浅蓝 · 精确匹配 · **待确认** - 深灰色(SYB 导入)→ 深灰 · 人工 · 已确认 - M、L(SYB 导入)→ 精确匹配 · **待确认** - XL(SYB 导入)→ AI 建议 · **待确认**,附「置信度 0.86 · 理由:名称完全一致且同为尺码维度」 - 2XL(人工添加)→ 未映射,注明「采购时若 PDD 已补充规格,由服务端 AI 匹配处理,不阻断采购」 新增 **「一键确认全部精确匹配 (3)」** 入口,并明确限定:仅对「映射来源 = 精确匹配」且待确认的行生效,**AI 建议不在此列,必须逐条确认**。 新增**警示条**(`AGENTS.md` 风险提示要求): > **名称相同不代表实物尺寸相同** —— 台湾虾皮尺码与大陆 PDD 尺码标准可能相差一号(如虾皮「L【建議52.5-60公斤】」与 PDD「L」)。确认前请核对尺寸表。 ### 映射失效复核页重建 由「只标记」改为「AI 给候选、人工确认」:每个失效项给出 AI 候选下拉(含「(不采纳建议)」选项)、置信度与理由、「确认映射」按钮。规则卡写明:**AI 候选只是建议,人工确认后才写入映射**;未处理项不清除、不自动替换;若采购时仍未处理,由服务端 AI 按 #46 流程处理,不阻断采购。 ### 商品详情页 映射表「来源 / 说明」列改为**「映射来源 / 状态」**,逐行标注(如「SYB 导入值 · 精确匹配待确认」「SYB 导入值 · AI 建议待确认」「人工添加值 · 未映射,采购时由 AI 匹配」);顶部提示改为「该商品有 3 项映射待确认」。 ### 规模与验证 - 10 个页面、**721 个控件、71 条流程线**(上一版 683 / 51) - `quantux_verify_export` → `verdict=PASS`,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件 - 几何检查 0 越界;过时文案扫描 0 残留 - 离线导出无外链请求 - 相关提交:`88e4506` docs(#40): revise prototype for AI matching per #46 ### 需要重新验收 本次修改涉及流程、状态与业务含义变化,不属于免原型的纯显示文案调整。**请重新审核并明确回复「原型通过」**;在此之前 Stage B 代码实施仍不得开始。 线上:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html
Author
Owner

搜索框改为支持多行批量查询

采用直接把原输入框改为多行文本域的方案,取代此前提议的「批量」按钮 + 弹窗。原方案是为了不占版面,但自适应高度能同时解决版面与交互层级两个问题,多一次点击没有必要。

交互定义

  • 默认单行高度,粘贴多行时自动增高,超过 5 行内部滚动。
  • Enter 提交搜索,Shift+Enter 换行。真实用法是粘贴而非手打换行,保持 Enter 提交可让单条搜索的操作习惯不变。
  • 分隔符宽容:换行 / 逗号 / 空格 / 制表符均可,自动去空去重(从 Excel、聊天记录粘贴的格式各不相同)。
  • 上限 200 条,超出明确提示而非静默截断;上限值放 sys_config。
  • 命中统计条:显示「输入 N · 命中 M · 未找到 K」,未找到项可展开查看。

第四、五点是批量查询最容易遗漏的部分:粘 50 个单号只出 47 条时,用户必须能知道缺的是哪 3 个,否则无法判断是没导入还是打错了。同时明确筛选器与批量搜索取交集且继续生效,避免「明明粘了 50 个怎么只出来 3 条」的困惑。

两个页面搜索内容不同

页面 多行搜索内容 说明
#41 货运宝商品明细 货运单号 / 虾皮订单号 一行即一条订单明细,订单号天然属于本域
#40 虾皮商品列表 虾皮商品ID 商品档案不含订单数据,不支持按订单号搜索;按订单号反查商品需经 syb_products,会破坏 #40 已确认的「商品域独立于采购任务和 SYB 数据」

该限制已写入 #40 列表页说明文字,避免实施时被误加。

规模与验证

  • #41:8 个页面、543 个控件、38 条流程线,verdict=PASS
  • #40:10 个页面、727 个控件、71 条流程线,verdict=PASS
  • 两者 runtimeErrors 0、无不支持控件、几何检查 0 越界;TextArea 属导出器完整支持类型
  • 页面高度相应调整:#41 列表 1000 → 1140,#40 列表 900 → 1010
  • 相关提交:25b160c

两份原型仍待验收。

## 搜索框改为支持多行批量查询 采用直接把原输入框改为多行文本域的方案,**取代此前提议的「批量」按钮 + 弹窗**。原方案是为了不占版面,但自适应高度能同时解决版面与交互层级两个问题,多一次点击没有必要。 ### 交互定义 - **默认单行高度**,粘贴多行时自动增高,超过 5 行内部滚动。 - **Enter 提交搜索,Shift+Enter 换行**。真实用法是粘贴而非手打换行,保持 Enter 提交可让单条搜索的操作习惯不变。 - **分隔符宽容**:换行 / 逗号 / 空格 / 制表符均可,自动去空去重(从 Excel、聊天记录粘贴的格式各不相同)。 - **上限 200 条**,超出明确提示而非静默截断;上限值放 `sys_config`。 - **命中统计条**:显示「输入 N · 命中 M · 未找到 K」,未找到项可展开查看。 第四、五点是批量查询最容易遗漏的部分:粘 50 个单号只出 47 条时,用户必须能知道**缺的是哪 3 个**,否则无法判断是没导入还是打错了。同时明确筛选器与批量搜索取交集且继续生效,避免「明明粘了 50 个怎么只出来 3 条」的困惑。 ### 两个页面搜索内容不同 | 页面 | 多行搜索内容 | 说明 | |---|---|---| | **#41 货运宝商品明细** | 货运单号 / 虾皮订单号 | 一行即一条订单明细,订单号天然属于本域 | | **#40 虾皮商品列表** | 虾皮商品ID | 商品档案不含订单数据,**不支持按订单号搜索**;按订单号反查商品需经 `syb_products`,会破坏 #40 已确认的「商品域独立于采购任务和 SYB 数据」 | 该限制已写入 #40 列表页说明文字,避免实施时被误加。 ### 规模与验证 - **#41**:8 个页面、543 个控件、38 条流程线,`verdict=PASS` - **#40**:10 个页面、727 个控件、71 条流程线,`verdict=PASS` - 两者 runtimeErrors 0、无不支持控件、几何检查 0 越界;`TextArea` 属导出器完整支持类型 - 页面高度相应调整:#41 列表 1000 → 1140,#40 列表 900 → 1010 - 相关提交:`25b160c` 两份原型仍待验收。
Author
Owner

按钮重命名与「清空搜索 / 重置」冲突消解

1. 批量按钮重命名(#41)

  • 批量重新解析 (2) → 重新解析 (2)
  • 批量创建采购任务 (2) → 创建采购 (2)

计数已在标签内,「批量」二字冗余;缩短后第一排更紧凑。

2. 「清空搜索」与「重置」确实冲突,已消解

冲突性质:重置 清空全部查询条件(搜索框 + 所有筛选器),清空搜索 只清搜索框——后者是前者的子集。两个按钮一个包含另一个,用户需停下判断该点哪个。

位置问题更明显:清空搜索 此前被放在命中统计条最右端(x=1290),距搜索框极远。清除搜索的控件不挨着搜索框,交互上本身就不成立。

改法:

操作 位置 作用范围
✕ 搜索框内右上角 只清搜索内容,筛选器保留
重置 工具栏原位 清空全部条件(搜索 + 所有筛选器)
  • 搜索框内置 ✕ 是标准交互,粘贴多行后想重来点右上角即可,且不占工具栏位置;
  • 独立的「清空搜索」按钮已删除,命中统计条回归单一职责,只显示统计;
  • 作用范围区别已写入搜索框下方说明文字。

两份原型同步处理(#40 的搜索框同样内置 ✕)。

验证

  • #40:10 个页面、133 控件(起始屏)、verdict=PASS、越界 0
  • #41:10 个页面、152 控件(起始屏)、verdict=PASS、越界 0
  • 提交 231a604
## 按钮重命名与「清空搜索 / 重置」冲突消解 ### 1. 批量按钮重命名(#41) - `批量重新解析 (2)` → **`重新解析 (2)`** - `批量创建采购任务 (2)` → **`创建采购 (2)`** 计数已在标签内,「批量」二字冗余;缩短后第一排更紧凑。 ### 2. 「清空搜索」与「重置」确实冲突,已消解 **冲突性质**:`重置` 清空全部查询条件(搜索框 + 所有筛选器),`清空搜索` 只清搜索框——后者是前者的**子集**。两个按钮一个包含另一个,用户需停下判断该点哪个。 **位置问题更明显**:`清空搜索` 此前被放在命中统计条最右端(x=1290),距搜索框极远。清除搜索的控件不挨着搜索框,交互上本身就不成立。 **改法**: | 操作 | 位置 | 作用范围 | |---|---|---| | **✕** | 搜索框内右上角 | 只清搜索内容,筛选器保留 | | **重置** | 工具栏原位 | 清空全部条件(搜索 + 所有筛选器) | - 搜索框内置 ✕ 是标准交互,粘贴多行后想重来点右上角即可,且不占工具栏位置; - 独立的「清空搜索」按钮已删除,命中统计条回归单一职责,只显示统计; - 作用范围区别已写入搜索框下方说明文字。 两份原型同步处理(#40 的搜索框同样内置 ✕)。 ### 验证 - **#40**:10 个页面、133 控件(起始屏)、`verdict=PASS`、越界 0 - **#41**:10 个页面、152 控件(起始屏)、`verdict=PASS`、越界 0 - 提交 `231a604`
ila changed title from T38 Shopee 商品档案、PDD 关联与规格映射 to T38 虾皮商品档案、PDD 关联与规格映射 2026-08-19 08:52:09 +08:00
Author
Owner

Stage A 原型验收通过

用户 2026-08-19 明确回复「验收通过 SYB 商品和虾皮商品两个模块原型」。两个工单的 Stage A 门禁均已解除,Stage B 代码实施可以开始。

工单保持 open:本次通过的是 Stage A 原型门禁,非整单验收。Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。

已确认的原型

工单 App ID 规模 验证
#40 虾皮商品档案 6a83b708191a826306a7eeb1 10 页 / 727 控件 / 71 条流程线 verdict=PASS,越界 0
#41 SYB 商品导入 6a83d7b4191a826306a7eebd 10 页 / 674 控件 / 44 条流程线 verdict=PASS,越界 0

离线导出均为零外链单文件,位于 prototypes/。

本次验收覆盖的关键设计

  • 展示术语:虾皮(Shopee)、SYB(顺云宝 ERP)、货运单(SYB 内单据)三者边界清晰;程序标识符保持 shopee_* / syb_*。
  • 规格映射三种来源:人工 / 精确匹配 / AI 建议,均需人工确认;一键确认仅对精确匹配生效,AI 建议须逐条确认;附「名称相同不代表实物尺寸相同」警示。
  • 采购在 SYB 商品列表发起:勾选 → 创建采购 → 逐条校验确认 → 批量结果;一条明细 = 一个独立任务,不合并不拆单;相关页面标注由 #35 实现。
  • 解析状态只如实标记:存疑不阻断采购(AI 直接用 SYB 原始颜色尺码匹配 PDD 实际规格),仅解析失败阻断。
  • 批量软删除含引用检查与部分成功反馈;shopee_item_id 唯一约束需与软删除并存。
  • 搜索框支持粘贴多行批量查询,附命中/未找到统计;✕ 只清搜索、重置清全部条件。

遗留项(Stage B 实施时处理,不阻塞本次验收)

  1. 「重新解析」的范围提示:该按钮可勾选到已成功解析的行,规则变更后重跑存在把原本正确的结果改错的风险,需在实施时补充范围提示或限定为仅对失败/存疑行生效。
  2. 「重新解析」缺结果反馈:当前直接跳转解析错误清单,未返回「成功 / 仍失败 / 跳过(人工已修正)」的逐条统计,与本项目既有的批量操作反馈模式(#45、#40 批量删除、#41 导入结果)不一致。
  3. details[].id 全局唯一性未验证:现有 HAR 仅含一张货运单的两条明细,样本不足。唯一键当前保守取「货运单号 + 来源明细ID」组合,安全但索引偏宽。
  4. #35 原型缺口:#46 引入的 spec_source、AI 匹配快照、两趟执行的 attempt 历史需在采购任务详情页展示,#32 原型仅有框架版,#35 实施前需评估是否补 Stage A 原型。

文档同步

Wiki Product-Requirements-Overview 与 Delivery-Issues 已更新为「Stage A 原型 2026-08-19 已通过,Stage B 待实施」;镜像已导出并通过一致性检查。prototypes/README.md 标记四份原型均可作为实现依据。提交 80434ec。

同时将 #40 标题由「T38 Shopee 商品档案、PDD 关联与规格映射」改为「T38 虾皮商品档案、PDD 关联与规格映射」,与术语决策一致。

#46 阶段进度

  • 阶段一 规则修订:已完成
  • 阶段二 原型更新与验收:已完成(第 7 项 #35 原型缺口评估留待 #35 实施前)
  • 阶段三 代码实施:可以开始
## Stage A 原型验收通过 用户 2026-08-19 明确回复「验收通过 SYB 商品和虾皮商品两个模块原型」。两个工单的 Stage A 门禁均已解除,Stage B 代码实施可以开始。 **工单保持 open**:本次通过的是 Stage A 原型门禁,非整单验收。Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。 ### 已确认的原型 | 工单 | App ID | 规模 | 验证 | |---|---|---|---| | #40 虾皮商品档案 | `6a83b708191a826306a7eeb1` | 10 页 / 727 控件 / 71 条流程线 | `verdict=PASS`,越界 0 | | #41 SYB 商品导入 | `6a83d7b4191a826306a7eebd` | 10 页 / 674 控件 / 44 条流程线 | `verdict=PASS`,越界 0 | 离线导出均为零外链单文件,位于 `prototypes/`。 ### 本次验收覆盖的关键设计 - 展示术语:**虾皮**(Shopee)、**SYB**(顺云宝 ERP)、**货运单**(SYB 内单据)三者边界清晰;程序标识符保持 `shopee_*` / `syb_*`。 - 规格映射三种来源:`人工` / `精确匹配` / `AI 建议`,均需人工确认;一键确认仅对精确匹配生效,AI 建议须逐条确认;附「名称相同不代表实物尺寸相同」警示。 - 采购在 SYB 商品列表发起:勾选 → 创建采购 → 逐条校验确认 → 批量结果;**一条明细 = 一个独立任务**,不合并不拆单;相关页面标注由 #35 实现。 - 解析状态只如实标记:**存疑不阻断采购**(AI 直接用 SYB 原始颜色尺码匹配 PDD 实际规格),仅解析失败阻断。 - 批量软删除含引用检查与部分成功反馈;`shopee_item_id` 唯一约束需与软删除并存。 - 搜索框支持粘贴多行批量查询,附命中/未找到统计;✕ 只清搜索、重置清全部条件。 ### 遗留项(Stage B 实施时处理,不阻塞本次验收) 1. **「重新解析」的范围提示**:该按钮可勾选到已成功解析的行,规则变更后重跑存在把原本正确的结果改错的风险,需在实施时补充范围提示或限定为仅对失败/存疑行生效。 2. **「重新解析」缺结果反馈**:当前直接跳转解析错误清单,未返回「成功 / 仍失败 / 跳过(人工已修正)」的逐条统计,与本项目既有的批量操作反馈模式(#45、#40 批量删除、#41 导入结果)不一致。 3. **`details[].id` 全局唯一性未验证**:现有 HAR 仅含一张货运单的两条明细,样本不足。唯一键当前保守取「货运单号 + 来源明细ID」组合,安全但索引偏宽。 4. **#35 原型缺口**:#46 引入的 `spec_source`、AI 匹配快照、两趟执行的 attempt 历史需在采购任务详情页展示,#32 原型仅有框架版,#35 实施前需评估是否补 Stage A 原型。 ### 文档同步 Wiki `Product-Requirements-Overview` 与 `Delivery-Issues` 已更新为「Stage A 原型 2026-08-19 已通过,Stage B 待实施」;镜像已导出并通过一致性检查。`prototypes/README.md` 标记四份原型均可作为实现依据。提交 `80434ec`。 同时将 #40 标题由「T38 Shopee 商品档案、PDD 关联与规格映射」改为「T38 虾皮商品档案、PDD 关联与规格映射」,与术语决策一致。 ### #46 阶段进度 - 阶段一 规则修订:**已完成** - 阶段二 原型更新与验收:**已完成**(第 7 项 #35 原型缺口评估留待 #35 实施前) - 阶段三 代码实施:**可以开始**
Author
Owner

Stage B 进度:迁移、模型与管理端 API 已完成

已交付

1. 数据表与模型(提交 f9cb194)

  • shopee_product 表:shopee_item_id、title、shop_name、可空且非唯一的 pdd_product_id、image_url、sale_price_cent + currency、specs_json、软删除三件套(deleted_at / deleted_flag / deleted_by)、创建与更新的幂等 request id。
  • CLI 迁移 1786700600000_shopee_product_archive.go(追加型,不改动既有表)。
  • shopeeproduct 包的规格类型与校验:值来源 import/manual,映射来源 manual/exact_match/ai_match,映射状态 pending/confirmed,以及 Validate / Merge / Marshal / Unmarshal / SoftDelete / Revive。

2. 管理端 API(提交 658ffd5),挂载于 /api/admin/v1/shopee-products

方法 路径 作用
GET `` 列表(关键词搜索、status=deleted 筛选已删除)
POST `` 创建(requestId 幂等;shopee_item_id 重复返回 409)
GET /:productId 详情
PATCH /:productId 编辑档案字段(标题、店铺、参考图、售价)
POST /:productId/link-pdd 关联/改绑 PDD 商品
POST /:productId/restore 恢复已软删除商品
POST /:productId/specs/values 新增规格值(来源恒为 manual)
DELETE /:productId/specs/values 删除规格值(仅限 manual)
PUT /:productId/specs/mapping 设置映射
DELETE /:productId/specs/mapping 清除映射
POST /:productId/specs/mapping/confirm 单条确认映射
POST /:productId/specs/mapping/confirm-exact-matches 一键确认全部精确匹配
POST /batch-delete 批量软删除(逐条结果)

错误码:INVALID_REQUEST / SHOPEE_ITEM_ID_EXISTS / SHOPEE_PRODUCT_NOT_FOUND / PDD_PRODUCT_NOT_FOUND / PDD_PRODUCT_DISABLED / SPEC_MAPPING_NOT_FOUND / SPEC_VALUE_NOT_FOUND / SPEC_VALUE_NOT_MANUAL / INTERNAL_ERROR。

实施中发现并修正的三个问题

① 工单原定的复合唯一索引方案不成立(设计层面)

原方案为 (shopee_item_id, deleted_at) 复合唯一索引,理由记为「MySQL 唯一索引允许多个 NULL,因此存活行同时只有一条」。该推理是反的:唯一索引把每个 NULL 视为互不相同,所以两条 deleted_at = NULL 的存活行永远不会冲突,约束完全失效。TestShopeeItemIDUniqueAmongLiveRowsOnly 首次运行即实测到重复创建被接受。

用户 2026-08-19 选定哨兵值方案。最终实现:新增 deleted_flag 辅助列参与唯一索引,存活时恒为 0(存活行之间真正比较唯一),软删除时置为该行自身 ID(行 ID 天然唯一,任意多条同 shopee_item_id 的已删除行互不冲突)。deleted_at 保留 GORM 标准语义用于查询自动过滤。软删除与恢复必须走 SoftDelete / Revive 辅助函数,db.Delete() 不会维护 deleted_flag,代码注释已写明。

② Merge 会把人工添加的规格值降级为导入值

原实现无条件将已存在值的来源改写为 import,导致 #41 重复导入后人工添加的值变得不可删除,违反「人工添加的值可删除,导入值不可人工删除」。已修正为仅在原来源非 manual 时才提升,由 TestMergeNeverDowngradesManualValueToImport 覆盖。

③ sys_config 表可能不存在

币种默认值读取 sys_config,但该表属于 go-admin 核心 schema,不在 migrations.Migrate() 范围内,仅跑模块迁移的数据库中不存在。已改为先 HasTable 判断,缺表视为「未配置覆盖值」并回退到 TWD,不再报错。

测试

go test ./... 全仓库 0 失败。新增 28 个测试,逐条覆盖工单硬规则:

  • 多个虾皮商品共用同一 PDD 商品;disabled 的 PDD 商品不可关联
  • 导入值不可人工删除,仅可清除映射
  • 精确匹配与 AI 匹配写入时一律置为 pending,即使调用方传入 confirmed 也被强制改写
  • 一键确认只作用于 exact_match,AI 建议保持 pending
  • 软删除后可重建同 shopee_item_id;多条已删除行不互相冲突;恢复后唯一性重新生效
  • 批量删除部分成功;已删除商品不出现在默认列表,可用 status=deleted 筛选并恢复

当前阶段的已知局限

批量删除的引用检查目前不拦截任何东西。 referencedBy 检查 syb_product(#41)与 purchase_task(#33/#34)两张表,但它们尚未建立。实现已用 HasTable 做前向兼容:两张表建成后检查自动生效,无需回改本段代码。但在当前实施顺序下,「被引用不可删除」这条验收标准在 #41 与 #34 落地前处于空转状态,非缺陷,需知悉。

剩余工作

  • Admin Vue 页面(列表、详情、新建、关联 PDD、映射编辑、批量删除)
  • 架构、业务规则与商品域接口文档同步

工单保持待验收。

## Stage B 进度:迁移、模型与管理端 API 已完成 ### 已交付 **1. 数据表与模型**(提交 `f9cb194`) - `shopee_product` 表:`shopee_item_id`、`title`、`shop_name`、可空且非唯一的 `pdd_product_id`、`image_url`、`sale_price_cent` + `currency`、`specs_json`、软删除三件套(`deleted_at` / `deleted_flag` / `deleted_by`)、创建与更新的幂等 request id。 - CLI 迁移 `1786700600000_shopee_product_archive.go`(追加型,不改动既有表)。 - `shopeeproduct` 包的规格类型与校验:值来源 `import`/`manual`,映射来源 `manual`/`exact_match`/`ai_match`,映射状态 `pending`/`confirmed`,以及 `Validate` / `Merge` / `Marshal` / `Unmarshal` / `SoftDelete` / `Revive`。 **2. 管理端 API**(提交 `658ffd5`),挂载于 `/api/admin/v1/shopee-products` | 方法 | 路径 | 作用 | |---|---|---| | GET | `` | 列表(关键词搜索、`status=deleted` 筛选已删除) | | POST | `` | 创建(requestId 幂等;`shopee_item_id` 重复返回 409) | | GET | `/:productId` | 详情 | | PATCH | `/:productId` | 编辑档案字段(标题、店铺、参考图、售价) | | POST | `/:productId/link-pdd` | 关联/改绑 PDD 商品 | | POST | `/:productId/restore` | 恢复已软删除商品 | | POST | `/:productId/specs/values` | 新增规格值(来源恒为 manual) | | DELETE | `/:productId/specs/values` | 删除规格值(仅限 manual) | | PUT | `/:productId/specs/mapping` | 设置映射 | | DELETE | `/:productId/specs/mapping` | 清除映射 | | POST | `/:productId/specs/mapping/confirm` | 单条确认映射 | | POST | `/:productId/specs/mapping/confirm-exact-matches` | 一键确认全部精确匹配 | | POST | `/batch-delete` | 批量软删除(逐条结果) | 错误码:`INVALID_REQUEST` / `SHOPEE_ITEM_ID_EXISTS` / `SHOPEE_PRODUCT_NOT_FOUND` / `PDD_PRODUCT_NOT_FOUND` / `PDD_PRODUCT_DISABLED` / `SPEC_MAPPING_NOT_FOUND` / `SPEC_VALUE_NOT_FOUND` / `SPEC_VALUE_NOT_MANUAL` / `INTERNAL_ERROR`。 ### 实施中发现并修正的三个问题 **① 工单原定的复合唯一索引方案不成立(设计层面)** 原方案为 `(shopee_item_id, deleted_at)` 复合唯一索引,理由记为「MySQL 唯一索引允许多个 NULL,因此存活行同时只有一条」。**该推理是反的**:唯一索引把每个 NULL 视为互不相同,所以两条 `deleted_at = NULL` 的存活行永远不会冲突,约束完全失效。`TestShopeeItemIDUniqueAmongLiveRowsOnly` 首次运行即实测到重复创建被接受。 用户 2026-08-19 选定哨兵值方案。最终实现:新增 `deleted_flag` 辅助列参与唯一索引,存活时恒为 0(存活行之间真正比较唯一),软删除时置为该行自身 ID(行 ID 天然唯一,任意多条同 `shopee_item_id` 的已删除行互不冲突)。`deleted_at` 保留 GORM 标准语义用于查询自动过滤。软删除与恢复必须走 `SoftDelete` / `Revive` 辅助函数,`db.Delete()` 不会维护 `deleted_flag`,代码注释已写明。 **② `Merge` 会把人工添加的规格值降级为导入值** 原实现无条件将已存在值的来源改写为 `import`,导致 #41 重复导入后人工添加的值变得不可删除,违反「人工添加的值可删除,导入值不可人工删除」。已修正为仅在原来源非 `manual` 时才提升,由 `TestMergeNeverDowngradesManualValueToImport` 覆盖。 **③ `sys_config` 表可能不存在** 币种默认值读取 `sys_config`,但该表属于 go-admin 核心 schema,不在 `migrations.Migrate()` 范围内,仅跑模块迁移的数据库中不存在。已改为先 `HasTable` 判断,缺表视为「未配置覆盖值」并回退到 `TWD`,不再报错。 ### 测试 `go test ./...` 全仓库 0 失败。新增 28 个测试,逐条覆盖工单硬规则: - 多个虾皮商品共用同一 PDD 商品;`disabled` 的 PDD 商品不可关联 - 导入值不可人工删除,仅可清除映射 - 精确匹配与 AI 匹配写入时**一律置为 pending**,即使调用方传入 confirmed 也被强制改写 - 一键确认只作用于 `exact_match`,AI 建议保持 pending - 软删除后可重建同 `shopee_item_id`;多条已删除行不互相冲突;恢复后唯一性重新生效 - 批量删除部分成功;已删除商品不出现在默认列表,可用 `status=deleted` 筛选并恢复 ### 当前阶段的已知局限 **批量删除的引用检查目前不拦截任何东西。** `referencedBy` 检查 `syb_product`(#41)与 `purchase_task`(#33/#34)两张表,但它们尚未建立。实现已用 `HasTable` 做前向兼容:两张表建成后检查自动生效,无需回改本段代码。但在当前实施顺序下,「被引用不可删除」这条验收标准在 #41 与 #34 落地前处于空转状态,非缺陷,需知悉。 ### 剩余工作 - Admin Vue 页面(列表、详情、新建、关联 PDD、映射编辑、批量删除) - 架构、业务规则与商品域接口文档同步 工单保持待验收。
Author
Owner

Stage B 待你验证的清单(我这边环境做不到)

我这边只能做到编译期验证:go build/go vet/go test ./... 全绿,eslint --fix 干净,@vue/compiler-sfc 编译通过。MySQL 在 Windows 侧、vite build 在 WSL 里跑不动(rolldown 原生模块缺失)、浏览器交互完全没人验证过——下面这些必须你来确认。

0. 环境跑起来

  • Windows 侧重启服务端,shopee_product 迁移成功建表(昨天 image_url 的 MySQL DEFAULT 报错已修,提交 45e8c12)
  • web/ 能正常 npm run dev 起来,浏览器打开无报错

1. 唯一性与共用

  • 新建虾皮商品,shopeeItemId 重复时前端能看到明确报错(服务端返回 SHOPEE_ITEM_ID_EXISTS)
  • 两个虾皮商品关联同一个 PDD 商品,详情页能看到「已被 N 个虾皮商品共用」提示

2. 规格与映射

  • 详情页能新增/删除人工规格值(SYB 导入值应该没有删除按钮)
  • 设置映射后状态显示「待确认」,点「确认」后变「已确认」
  • 一键确认精确匹配只影响 exact_match 来源,不影响 AI 建议行

3. 软删除

  • 软删除一个商品,回列表默认看不到;筛选「已删除」能看到并点「恢复」
  • 恢复后原有 PDD 关联与映射还在(不是空的)
  • 软删除后用同一个 shopeeItemId 重新创建,能成功(不报重复)

4. 页面边界

  • 全程没有出现采购任务、PDD 订单号、快递单号、支付相关字段

请把结果直接写回工单,我就不重复代跑了。

## Stage B 待你验证的清单(我这边环境做不到) 我这边只能做到编译期验证:`go build`/`go vet`/`go test ./...` 全绿,`eslint --fix` 干净,`@vue/compiler-sfc` 编译通过。**MySQL 在 Windows 侧、`vite build` 在 WSL 里跑不动(rolldown 原生模块缺失)、浏览器交互完全没人验证过**——下面这些必须你来确认。 ### 0. 环境跑起来 - [ ] Windows 侧重启服务端,`shopee_product` 迁移成功建表(昨天 `image_url` 的 MySQL DEFAULT 报错已修,提交 `45e8c12`) - [ ] `web/` 能正常 `npm run dev` 起来,浏览器打开无报错 ### 1. 唯一性与共用 - [ ] 新建虾皮商品,`shopeeItemId` 重复时前端能看到明确报错(服务端返回 `SHOPEE_ITEM_ID_EXISTS`) - [ ] 两个虾皮商品关联同一个 PDD 商品,详情页能看到「已被 N 个虾皮商品共用」提示 ### 2. 规格与映射 - [ ] 详情页能新增/删除人工规格值(SYB 导入值应该没有删除按钮) - [ ] 设置映射后状态显示「待确认」,点「确认」后变「已确认」 - [ ] 一键确认精确匹配只影响 `exact_match` 来源,不影响 AI 建议行 ### 3. 软删除 - [ ] 软删除一个商品,回列表默认看不到;筛选「已删除」能看到并点「恢复」 - [ ] 恢复后原有 PDD 关联与映射还在(不是空的) - [ ] 软删除后用同一个 `shopeeItemId` 重新创建,能成功(不报重复) ### 4. 页面边界 - [ ] 全程没有出现采购任务、PDD 订单号、快递单号、支付相关字段 请把结果直接写回工单,我就不重复代跑了。
Author
Owner

??? 2026-08-20 ???????????:Task-40-Shopee-product-archive;Wiki revision:a627417c412e44fbc6b0816f15395e131760522f??????

??? 2026-08-20 ???????????:Task-40-Shopee-product-archive;Wiki revision:a627417c412e44fbc6b0816f15395e131760522f??????
ila closed this issue 2026-08-20 16:34:10 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#40