Wiki Product-Requirements-Overview 与 Delivery-Issues 已更新为「Stage A 原型 2026-08-19 已通过,Stage B 待实施」;镜像已导出并通过一致性检查。prototypes/README.md 标记四份原型均可作为实现依据。提交 80434ec。
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
基本信息
依赖与并行
pdd_products档案和规格结构;相关QuantUX页面经用户审核子项目影响
原始需求
Shopee商品ID全局唯一。一个Shopee商品当前只关联一个PDD商品;多个Shopee商品允许关联同一个PDD商品。Shopee与PDD的颜色、尺码名称可能不同,需要由采购人员维护明确映射,不能由Agent猜测。
做什么
shopee_products商品档案,shopee_item_id唯一。sale_price_cent(整数分,与 #31 的priceCent一致)与currency(ISO 4217 代码,不存显示符号;虾皮为跨境平台,币种必须与金额一起保存)。币种取自系统配置默认值(go-adminsys_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 明细时写入,同时允许人工覆盖;商品域不实时 joinsyb_products,保证 #40 可独立实施与验收。Content-Type、带Content-Disposition: attachment、无缓存头且单张约 2 秒,前端直连会导致整列裂图与长等待;代理需补正确 Content-Type、加缓存,列表用固定尺寸缩略图并懒加载。pdd_product_id;不得对该字段加唯一约束。shopee_products/shopee_item_id不变,术语对应关系写入业务规则术语表。deleted_at与操作人;列表默认不显示已删除,可筛选「已删除」并恢复。manual(人工)/exact_match(精确匹配)/ai_match(AI 匹配)。不做什么
Stage A:QuantUX 原型(当前唯一实施范围)
说明:#32 原型只覆盖采购流程内嵌的「未映射行跳转映射并返回」入口,不替代本工单的独立商品档案管理页原型。
使用 QuantUX MCP 创建 Shopee 商品档案管理端原型,至少覆盖:
shopee_item_id、标题、店铺、售价(金额 + 来源)、PDD 商品(商品ID 为链接,新标签打开 PDD 商品详情)和「可采购 / 待完善 / 未关联 / 已失效」状态标记;不设独立的映射完整度列,缺失项数量并入状态标记文案(例如「待完善 · 缺尺码 3 项」)。shopee_item_id的明确提示;同一页可选录入颜色值与尺码值(不涉及 PDD,可留空稍后补充),并可通过搜索选择器选填关联 PDD 商品(不提供手工输入 ID 的入口,选择时校验存在性、状态与共用情况)。原型审核门禁
6a83b708191a826306a7eeb1)Stage B:代码实现
仅在原型明确验收后开始,交付内容见上文「做什么」。
Stage B 代码验收标准
shopee_item_id唯一,重复创建返回明确提示。shopee_item_id唯一约束与软删除并存:已删除记录不得阻塞同一shopee_item_id的再次创建或导入。风险和回退
PDD规格变化可能让映射失效;只标记并等待人工修正,不自动修改。迁移和页面可独立回退,不影响现有采集任务。
规格映射维护位置与失效规则补充(2026-08-17)
按用户确认补充:
SYB商品列表对“颜色或尺码未映射”的行提供“去匹配”快捷入口,自动带入shopee_product_id并打开同一个 #40 映射页面;保存后返回原 SYB 列表、保留筛选/分页并重新检查该行。新增验收:
#40 交互设计证据已补入 #32 原型
#32 QuantUX App
6a827440191a826306a7eddd已展示:从 SYB 未映射行进入正确 Shopee 商品的 PDD 规格映射页、缺失项显示“待匹配”、保存和返回都回到 SYB 商品列表。映射仍按 Shopee 商品独立维护;生产实现继续由本工单负责并受原型审核门禁约束。提交:7df4546。Stage A 原型已完成,待用户审核
原型
6a83b708191a826306a7eeb1prototypes/quantux-shopee-product-6a83b708191a826306a7eeb1.html页面清单与 Stage A 覆盖点对应
shopee_item_id明确拒绝提示覆盖点 7(页面不出现采购任务、订单、物流字段)在列表、详情、失效复核三页写明边界说明,全部页面无采购字段。
已表达的关键规则
验证
quantux_verify_export:verdict=PASS,widgetCount 99、wiredCount 7、navigation=true、inputsEditable=true、toggleWorks=true、runtimeErrors=0、unsupportedTypes 无相关提交
38dbaeddocs(#40): add stage A shopee product prototype门禁状态
原型按用户反馈修订(第 2 版)
本次修改
参考图数据来源的实测结论(影响实现方式)
抓取用户提供的样例
https://www.shunyunbaoerp.com/api/p/file?id=193553649:结论与要求:
Content-Type: image/jpeg、加Cache-Control,可选生成缩略图。<a href>:带Content-Disposition: attachment,点击会触发下载而非预览。shopee_products.image_url由 #41 导入时写入并允许人工覆盖;列表不实时 joinsyb_products,避免 #40 反向依赖 #41(#41 的前置本就是 #40)。原型规模:7 个页面、534 个控件、40 条流程线。参考图第一行使用真实 SYB 样例图并以 data URI 内嵌,导出文件完全离线(已确认无外链请求)。
验证:
quantux_verify_export→verdict=PASS,wiredCount 13、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。仍待用户审核,门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
原型按用户反馈修订(第 3 版):术语改「虾皮」+ 批量软删除
已实现的修改
Shopee出现 0 次,shopee_item_id保留 3 处(程序标识符,未改)。术语边界(重要)
shopee_products、shopee_item_id、API 路径保持英文,未做任何改动。Business-Rules-and-Glossary增加术语条目:虾皮 = Shopee(展示名),代码与接口一律 shopee。否则后续 agent 和文档会出现两套说法。批量软删除的设计(原型已表达,需实施时遵守)
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。待确认的假设(原型按此表达,审核时请确认或推翻)
shopee_item_id时复活原记录(保留人工维护的映射),并在导入结果中提示"已恢复 N 条"。原型规模:9 个页面、611 个控件、44 条流程线。
验证:
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
原型第 4 版:补上虾皮规格值的人工添加能力
用户提问:虾皮商品详情页为什么没有颜色尺码等添加功能?
这是原型的真实缺口,不是有意省略。 前三版隐含假设「虾皮规格值只来自 #41 的 SYB 明细导入」,但这个假设有两个问题:
对照 #31 已确认的 PDD 商品档案模式:人工可全量维护 + 采集结果自动合并,两条来源并存。虾皮商品档案应沿用同一模式。
本次修改
因此确定的业务规则(已写入工单正文)
编辑位置的取舍:详情页保持只读总览,添加与编辑集中在「编辑映射」页,避免同一份数据出现两个编辑入口。若希望详情页直接可编辑,请在审核时说明。
原型规模:10 个页面、641 个控件、50 条流程线。
验证:
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界(映射编辑页高度调整为 1200)。相关提交:
1b6c83adocs(#40): add manual spec value creation to prototype门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
原型第 5 版:新建页支持录入规格值(修正一处结构性设计问题)
用户提问:为什么点击「新建」进入新建虾皮商品页时没有新增颜色尺码的功能?
这暴露的是划分错误,不只是缺功能。 前几版把「规格值」和「映射」当成一件事处理,所以添加入口只出现在「编辑映射」页。但两者的依赖完全不同:
把档案数据的录入挂在依赖 PDD 的页面下,导致新建出来的商品必然是空壳,用户也找不到入口。
修正后的职责划分
本次修改
由此确定的规则
原型规模:10 个页面、667 个控件、50 条流程线。
验证:
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。相关提交:
abd6984docs(#40): allow spec value entry on create page in prototype门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
原型第 6 版:新建页增加选填的 PDD 商品选择器
决策:加,但做成「搜索 + 选择」,不做成手打 PDD 商品ID 的输入框。
裸输入框会丢掉关联动作里四件必要的校验与知情提示,只能在保存时报错:
disabled的 PDD 商品不可关联);真要把输入框做对,就得加即时校验、防抖查询和候选列表——本质上又变回选择器,只是体验更差。
本次修改(新建虾皮商品页,屏幕高度 1080 → 1380)
PDD-88790(链接色)、标题「高腰阔腿裤 垂感直筒 · 轻风女装旗舰店 · 颜色 2 · 尺码 4」、active状态标记、「已被 1 个虾皮商品关联(允许共用)」,以及「更换」按钮(连线到关联 PDD 商品页)。明确不在新建页做的事
选中 PDD 商品后不展开规格映射。否则新建页变成「档案 + 规格值 + 关联 + 映射」四合一表单,一次提交写三张表,回滚与幂等语义显著复杂化。保存后跳详情页并提示「下一步:完成规格映射」。
关联页保留:改绑 PDD 商品是独立的高频操作,不能只在创建时可选。
原型规模:10 个页面、683 个控件、51 条流程线。
验证:
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。相关提交:
8551256docs(#40): add optional pdd product picker on create page门禁不变:明确回复「原型通过」前不修改数据库迁移、Go 服务端、Vue 页面和共享 API。
原型第 7 版:虾皮售价加入列表、详情与新建页
用户提问:虾皮商品是不是列表、详情、新建都没有价格?
确认:此前三处均无价格,价格只出现在「PDD商品详情(新标签)」屏的颜色价格;#40 与 #41 正文也从未提及价格。用户选择加入虾皮售价。
本次修改
必须在实施前确认的三点
sale_price_cent(整数分,与 #31 的priceCent保持一致)+currency(ISO 4217)。原型样例统一用 NT$,实际币种需要确认。毛利计算不在本工单范围:需要售价、采购价与汇率三者齐备,且只能在 SYB 明细级计算。本工单只做展示。
原型规模:10 个页面、704 个控件、63 条流程线。
验证:
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件;几何检查 0 越界。相关提交:
61e742ddocs(#40): add shopee sale price to prototype list, detail and create门禁不变:明确回复「原型通过」前不修改数据库迁移、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))。修正二:币种不逐商品选择,改为系统配置
虾皮店铺属于某个站点,站点决定币种,同一店铺所有商品币种必然相同。让采购员逐商品自由选,只会制造同店铺多币种的脏数据,且无业务价值。
三种归属层次的取舍:
shopee_products.shop_name从字符串改为外键,并补店铺管理页。超出 #40 当前范围。sys_config配置一个默认币种,新建页只读展示,不可逐商品修改。零新增基础设施,杜绝同店铺多币种。本次修改:新建页币种下拉改为只读展示「TWD (NT$)」+ 副标「系统默认 · 不可逐商品修改」;说明改为「币种由系统配置统一设置(sys_config),按 ISO 4217 存储,符号仅用于显示;需要变更请在管理端系统配置中调整」。右侧规则卡补充对应条目。
关于底座既有能力的核查结果
sys_dict_type/sys_dict_data/sys_config,前端已有web/src/api/admin/dict/{data,type}.js。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。
Stage A 原型验收通过
用户 2026-08-18 明确回复「虾皮商品模块的原型通过验收」。Stage A 门禁解除,Stage B 代码实施可以开始。
已确认的原型
6a83b708191a826306a7eeb1prototypes/quantux-shopee-product-6a83b708191a826306a7eeb1.htmlquantux_verify_export=PASS,runtimeErrors 0,几何检查 0 越界页面清单
虾皮商品列表 / 虾皮商品详情 / 新建虾皮商品 / 关联PDD商品 / 颜色尺码映射编辑 / 映射失效复核 / PDD商品详情(新标签) / 批量删除确认弹窗 / 批量删除结果 / 添加规格值弹窗
经过 8 轮修订确认的设计决策(Stage B 必须遵守)
shopee_products、shopee_item_id、API 路径等程序标识符保持英文。image_url(SYB 图片 URL),必须服务端代理:源接口无 Content-Type、带 Content-Disposition: attachment、无缓存头、单张约 2 秒。sale_price_cent+currency(ISO 4217 代码,不存符号);币种取系统配置默认值,不逐商品选择。deleted_at+ 操作人、可筛选「已删除」并恢复。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 实施前需要答复)
shopee_item_id时是否复活原记录并保留人工映射。未验证部分:无浏览器环境,未做人工视觉走查;原型观感以用户本次审核为准。
工单保持 open:Stage A 完成,Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。
SYB 明细数据实测(demo/shunyunbaoerp_stock_list.har)+ 四点确认回复
针对 Stage A 验收评论中列出的 4 项待确认假设逐一回复。
① SYB 是否有售价字段 —— 有,但粒度是订单明细行,不是商品档案
实测
POST /am/stock/detail/listByStock真实响应:字段确认:
productPrice:明细行级售价(该笔订单中该虾皮商品的成交单价),十进制,非整数分。不是商品档案级字段,同一个productId(虾皮商品ID)在不同订单里的productPrice可能不同(促销、时间差异)。这印证了此前定的语义——档案上只能存「最近一次导入的参考值」,不是权威成交价,真实成交价以明细为准。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,原型里的样例币种不用改。
结论:原型无需因这次实测再修改(图片拼接规则、币种不可推断两点都印证了已有设计),只更新工单正文里售价字段的取数说明。
原型第 9 版:按 #46 决策变更修订,需重新验收
背景:本工单 Stage A 原型于 2026-08-18 验收通过,但同日 #46 的决策变更使其中部分表述失效。已验收但内容过时的原型风险最高(会被当作可信的实现依据),故按 #46 阶段二优先修订。
失效并已改写的表述
导出文件中「不自动猜测替换值」出现 0 次。
映射编辑页重建
新增映射来源列,与既有的规格值来源区分开——两者是不同维度,此前混为一谈:
SYB 导入/人工添加人工/精确匹配/AI 建议表格列:虾皮规格值 + 值来源 / 映射到 PDD 规格值 / 映射来源 / 状态 / 操作。
状态新增
待确认。示例行覆盖全部组合:新增 「一键确认全部精确匹配 (3)」 入口,并明确限定:仅对「映射来源 = 精确匹配」且待确认的行生效,AI 建议不在此列,必须逐条确认。
新增警示条(
AGENTS.md风险提示要求):映射失效复核页重建
由「只标记」改为「AI 给候选、人工确认」:每个失效项给出 AI 候选下拉(含「(不采纳建议)」选项)、置信度与理由、「确认映射」按钮。规则卡写明:AI 候选只是建议,人工确认后才写入映射;未处理项不清除、不自动替换;若采购时仍未处理,由服务端 AI 按 #46 流程处理,不阻断采购。
商品详情页
映射表「来源 / 说明」列改为**「映射来源 / 状态」**,逐行标注(如「SYB 导入值 · 精确匹配待确认」「SYB 导入值 · AI 建议待确认」「人工添加值 · 未映射,采购时由 AI 匹配」);顶部提示改为「该商品有 3 项映射待确认」。
规模与验证
quantux_verify_export→verdict=PASS,wiredCount 14、navigation=true、runtimeErrors=0、无不支持控件88e4506docs(#40): revise prototype for AI matching per #46需要重新验收
本次修改涉及流程、状态与业务含义变化,不属于免原型的纯显示文案调整。请重新审核并明确回复「原型通过」;在此之前 Stage B 代码实施仍不得开始。
线上:http://124.222.27.183:8082/#/apps/6a83b708191a826306a7eeb1.html
搜索框改为支持多行批量查询
采用直接把原输入框改为多行文本域的方案,取代此前提议的「批量」按钮 + 弹窗。原方案是为了不占版面,但自适应高度能同时解决版面与交互层级两个问题,多一次点击没有必要。
交互定义
sys_config。第四、五点是批量查询最容易遗漏的部分:粘 50 个单号只出 47 条时,用户必须能知道缺的是哪 3 个,否则无法判断是没导入还是打错了。同时明确筛选器与批量搜索取交集且继续生效,避免「明明粘了 50 个怎么只出来 3 条」的困惑。
两个页面搜索内容不同
syb_products,会破坏 #40 已确认的「商品域独立于采购任务和 SYB 数据」该限制已写入 #40 列表页说明文字,避免实施时被误加。
规模与验证
verdict=PASSverdict=PASSTextArea属导出器完整支持类型25b160c两份原型仍待验收。
按钮重命名与「清空搜索 / 重置」冲突消解
1. 批量按钮重命名(#41)
批量重新解析 (2)→重新解析 (2)批量创建采购任务 (2)→创建采购 (2)计数已在标签内,「批量」二字冗余;缩短后第一排更紧凑。
2. 「清空搜索」与「重置」确实冲突,已消解
冲突性质:
重置清空全部查询条件(搜索框 + 所有筛选器),清空搜索只清搜索框——后者是前者的子集。两个按钮一个包含另一个,用户需停下判断该点哪个。位置问题更明显:
清空搜索此前被放在命中统计条最右端(x=1290),距搜索框极远。清除搜索的控件不挨着搜索框,交互上本身就不成立。改法:
两份原型同步处理(#40 的搜索框同样内置 ✕)。
验证
verdict=PASS、越界 0verdict=PASS、越界 0231a604T38 Shopee 商品档案、PDD 关联与规格映射to T38 虾皮商品档案、PDD 关联与规格映射Stage A 原型验收通过
用户 2026-08-19 明确回复「验收通过 SYB 商品和虾皮商品两个模块原型」。两个工单的 Stage A 门禁均已解除,Stage B 代码实施可以开始。
工单保持 open:本次通过的是 Stage A 原型门禁,非整单验收。Stage B(迁移、服务端、Admin 页面、测试与文档)尚未开始。
已确认的原型
6a83b708191a826306a7eeb1verdict=PASS,越界 06a83d7b4191a826306a7eebdverdict=PASS,越界 0离线导出均为零外链单文件,位于
prototypes/。本次验收覆盖的关键设计
shopee_*/syb_*。人工/精确匹配/AI 建议,均需人工确认;一键确认仅对精确匹配生效,AI 建议须逐条确认;附「名称相同不代表实物尺寸相同」警示。shopee_item_id唯一约束需与软删除并存。遗留项(Stage B 实施时处理,不阻塞本次验收)
details[].id全局唯一性未验证:现有 HAR 仅含一张货运单的两条明细,样本不足。唯一键当前保守取「货运单号 + 来源明细ID」组合,安全但索引偏宽。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 阶段进度
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。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-productsstatus=deleted筛选已删除)shopee_item_id重复返回 409)/:productId/:productId/:productId/link-pdd/:productId/restore/:productId/specs/values/:productId/specs/values/:productId/specs/mapping/:productId/specs/mapping/:productId/specs/mapping/confirm/:productId/specs/mapping/confirm-exact-matches/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 个测试,逐条覆盖工单硬规则:disabled的 PDD 商品不可关联exact_match,AI 建议保持 pendingshopee_item_id;多条已删除行不互相冲突;恢复后唯一性重新生效status=deleted筛选并恢复当前阶段的已知局限
批量删除的引用检查目前不拦截任何东西。
referencedBy检查syb_product(#41)与purchase_task(#33/#34)两张表,但它们尚未建立。实现已用HasTable做前向兼容:两张表建成后检查自动生效,无需回改本段代码。但在当前实施顺序下,「被引用不可删除」这条验收标准在 #41 与 #34 落地前处于空转状态,非缺陷,需知悉。剩余工作
工单保持待验收。
Stage B 待你验证的清单(我这边环境做不到)
我这边只能做到编译期验证:
go build/go vet/go test ./...全绿,eslint --fix干净,@vue/compiler-sfc编译通过。MySQL 在 Windows 侧、vite build在 WSL 里跑不动(rolldown 原生模块缺失)、浏览器交互完全没人验证过——下面这些必须你来确认。0. 环境跑起来
shopee_product迁移成功建表(昨天image_url的 MySQL DEFAULT 报错已修,提交45e8c12)web/能正常npm run dev起来,浏览器打开无报错1. 唯一性与共用
shopeeItemId重复时前端能看到明确报错(服务端返回SHOPEE_ITEM_ID_EXISTS)2. 规格与映射
exact_match来源,不影响 AI 建议行3. 软删除
shopeeItemId重新创建,能成功(不报重复)4. 页面边界
请把结果直接写回工单,我就不重复代跑了。
??? 2026-08-20 ???????????:Task-40-Shopee-product-archive;Wiki revision:a627417c412e44fbc6b0816f15395e131760522f??????