优化:SYB/虾皮商品页详情改为原地弹出抽屉,不再新开标签页 #186

Open
opened 2026-09-01 09:46:16 +08:00 by ila · 4 comments
Owner

Gitea MCP 未向当前会话暴露,按仓库规则回退项目根目录安全配置与 Gitea API 创建本工单;凭据未写入工单、代码或日志。

原始需求摘要

来源:用户于 2026-09-01 反馈,admin 里 SYB 商品页查看虾皮商品详情或 PDD 商品详情是新开浏览器标签页,使用起来麻烦。讨论后用户选择方案 B:把详情内容做成可以在原页面上原地弹出的抽屉,不新开标签页、不跳转路由,关闭后精确回到原来的位置(筛选、翻页状态不丢),并要求建单。

目的:消除"看一眼详情就要切标签页"的操作负担,尤其是 SYB 商品页需要来回对照虾皮商品和 PDD 商品信息的场景。

基线与已核实事实

代码基线:3aab1f0(2026-09-01,当前 main)。核验日期 2026-09-01。原工单使用的 5338dd0 已过期;其后 #182、#183 修改了本单涉及的三个页面,实施必须保留统一 createRequestId() 以及 SYB collectionEligible 判断,禁止从旧基线提取后覆盖这些修复。

  • PDD 商品详情、虾皮商品详情本来就是 el-drawer(pdd-products/index.vue:63 size="960px";shopee-products/index.vue:79 size="1080px"),且都已支持"打开页面时通过 ?productId= 直接展开抽屉"(各自 created() 读取 this.$route.query.productId)。现在的"新开标签页"只是拿这套现成能力包了一层 window.open(route.href, '_blank', 'noopener')。
  • 现有跨页跳转调用点:
    • syb-products/index.vue:273-284:openShopeeDetail(shopeeProductId, targetColor, action)、openPddDetail(pddProductId),各有 2 处模板调用 + purchaseActionRoute 按钮路由到这两个方法。
    • shopee-products/index.vue:287-289:openPddDetail(pddProductId),2 处模板调用(列表列 + 详情抽屉内的"关联 PDD 商品"链接)。
    • pdd-products/index.vue 当前没有反向链接到虾皮商品详情(关联虾皮商品列表只在自身抽屉内筛选,不跳转)。
  • 两个详情抽屉都不是简单的只读展示,而是完整的可编辑面板,本单必须原样保留全部行为:
    • PDD 商品详情(pdd-products/index.vue:63-85):编辑商品、创建备货采购、关联虾皮商品列表(含自身分页/筛选/多选)、"继续订单采购"批量动作。
    • 虾皮商品详情(shopee-products/index.vue:79-130):编辑档案、关联/更换 PDD 商品、#172 新增的颜色/尺码 AI 匹配(含低置信度不预填、AI 待确认的单独确认按钮)、添加规格值、未保存修改的关闭确认(beforeCloseDetail)、通过 ?targetColor= 高亮指定行、通过 ?action=link_pdd 自动弹出 PDD 选择器。
  • 虾皮商品详情抽屉内部本身就有一条到 PDD 详情的链接(openPddDetail),本单实施后这条链接需要变成"在当前已经打开的虾皮抽屉之上,再叠一层 PDD 抽屉",属于抽屉嵌套场景,Element Plus 的 el-drawer 原生支持层叠(append-to-body),机制上可行。
  • 风险提示:虾皮商品详情抽屉是 #172(AI 规格建议)、#175(置信度阈值,间接)刚落地不久的重点改动区域,提取重构存在真实回归风险,需要覆盖 #172 引入的全部交互点。

目标

  1. 把 PDD 商品详情抽屉、虾皮商品详情抽屉分别提取为可复用组件(如 PddProductDetailDrawer.vue、ShopeeProductDetailDrawer.vue),接收目标 id(及必要的可选参数如 targetColor/action)作为 prop,自身管理加载、展开状态。
  2. syb-products 页面的"查看虾皮商品详情""查看 PDD 商品详情"、shopee-products 页面的"查看关联 PDD 商品详情",全部从 window.open 改为挂载对应的抽屉组件,原地展开,不跳转路由、不新开标签页。
  3. pdd-products、shopee-products 页面自身原有的详情抽屉,改为直接使用同一份提取出来的组件(同源实现,不留两份重复代码)。
  4. 关闭详情抽屉后,来源页面的筛选、翻页、选中状态保持不变(因为不再发生路由跳转,天然满足,只需验证)。
  5. 详情抽屉内部原有的"未保存修改二次确认""高亮指定行""自动弹出 PDD 选择器"等既有行为,在新的组件化形态下继续正确工作。
  6. 虾皮商品详情抽屉内到 PDD 详情的跳转,改为叠加展示 PDD 抽屉,不再跳转。

非目标

  • 不改变两个详情抽屉的业务逻辑、可编辑内容、接口调用、数据校验规则,纯粹是"承载方式"从整页路由改为可嵌入组件。
  • 不新增 pdd-products 页面到虾皮商品详情的反向链接(目前没有这条链接,本单不主动加,如需要另评估)。
  • 不改变 ?productId=(及 targetColor/action)直接访问对应整页仍然可以打开详情抽屉的既有行为——两种打开方式(整页直达、从其他页面原地弹出)都要继续可用,互不冲突。
  • 不改变 #172 的 AI 建议逻辑、置信度判定、SetMapping/ConfirmMapping 等接口行为。
  • 不涉及权限、并发、迁移、订单、支付。

前置依赖与并行性

  • #182、#183 已完成并纳入当前基线;#183 曾修改 syb-products/index.vue,因此原“无代码重叠”判断不再适用,但不存在未完成依赖。
  • 与任何同时改动 syb-products/index.vue、shopee-products/index.vue、pdd-products/index.vue 抽屉内部逻辑的任务不可并行,避免同文件冲突。
  • 建议在修正后的 #187 完成并验证页面缓存后再实施本单,以便准确验收来源页筛选、分页和选中状态。

固定实施方案

  1. 新建 web/src/views/goauto/pdd-products/PddProductDetailDrawer.vue:把现有 pdd-products/index.vue:63-85 的抽屉内容、及其依赖的 detail/related/relatedPurchase/stock 相关 data、methods、computed 一并迁移进来,对外暴露 v-model:open、product-id prop,内部自行请求数据,不依赖外部注入状态。
  2. 新建 web/src/views/goauto/shopee-products/ShopeeProductDetailDrawer.vue:同样迁移 shopee-products/index.vue:79-130 及其配套的 detail/pddPicker/edit(是否一并内聚,视依赖紧密程度定)/#172 AI 建议相关状态与方法,对外暴露 v-model:open、product-id、可选 target-color、可选 action prop。
  3. pdd-products/index.vue、shopee-products/index.vue 自身改为引用各自新组件,原有内联抽屉模板与相关 data/methods 删除,不保留重复实现。
  4. ShopeeProductDetailDrawer.vue 内到 PDD 详情的跳转,改为挂载 PddProductDetailDrawer.vue 并原地展开,不再 window.open/路由跳转。
  5. syb-products/index.vue 引入这两个抽屉组件,openShopeeDetail/openPddDetail 改为设置对应组件的 open/product-id(及 targetColor/action)而不是 window.open;原有按钮路由(purchaseActionRoute 等)指向的目标方法同步改造。
  6. 保留 ?productId= 直达整页展开详情的既有能力:pdd-products、shopee-products 页面读取路由参数,给新抽屉组件传入初始 product-id/open=true;同时验证页面已被 keep-alive 缓存后再次收到 query 变化的行为,不能只依赖首次 created()。
  7. 明确组件事件契约:至少包含 update:modelValue、product-updated、mapping-updated、pdd-linked、purchase-created。父页面收到事件后采用局部更新或保持原列表不刷新;不得直接调用父页面 load() 导致筛选、分页或选中行丢失。
  8. 两个抽屉组件都增加请求代次/失效保护:快速连续打开不同商品、关闭后旧请求返回、重新打开时,旧响应不得覆盖当前商品或重新打开已关闭抽屉。
  9. 产品 ID 在抽屉打开期间发生变化且存在未保存草稿时,必须先执行与关闭抽屉相同的放弃确认;确认前不得切换商品。

设计证据

现有抽屉视觉规范继续复用,不需要完整高保真原型;但“虾皮详情之上叠加 PDD 详情”属于新的交互状态。实施前至少提供标注截图或低保真图并由用户确认,覆盖:SYB 页原地打开虾皮/PDD 详情、虾皮抽屉叠加 PDD 抽屉、存在未保存草稿时关闭/切换商品确认、加载失败四种状态。工单需记录确认时间与覆盖范围。

验收标准

  • 从 SYB 商品页点击虾皮商品/PDD 商品详情,原地弹出对应抽屉,不新开标签页、不跳转路由。
  • 关闭抽屉后,SYB 商品页的筛选条件、分页位置、已选中行保持不变。
  • 从虾皮商品详情抽屉点击"关联 PDD 商品"链接,在其上叠加展示 PDD 详情抽屉;关闭 PDD 抽屉回到虾皮商品详情抽屉,状态不丢失。
  • pdd-products、shopee-products 页面自身通过 ?productId= 直接访问,详情抽屉行为与改动前一致。
  • 虾皮商品详情抽屉内 #172 的颜色/尺码 AI 匹配(含低置信度不预填、AI 待确认按钮)在组件化后行为不变。
  • 虾皮商品详情抽屉的未保存修改二次确认(beforeCloseDetail)在组件化后行为不变。
  • ?targetColor= 高亮指定行、?action=link_pdd 自动弹出 PDD 选择器,在组件化后行为不变。
  • PDD 商品详情抽屉内"编辑商品""创建备货采购""关联虾皮商品列表及继续订单采购"在组件化后行为不变。
  • pdd-products、shopee-products 页面不再各自维护一份重复的详情抽屉实现。
  • 抽屉组件通过显式事件通知父页面;关闭或保存后不得无条件刷新父列表并清空筛选、分页、选中行。
  • 快速依次打开商品 A/B、关闭后等待旧请求返回,最终只显示当前商品且不会被旧响应重新打开。
  • 嵌套抽屉中 Esc、遮罩、焦点、滚动与 z-index 正确:一次只关闭最上层,关闭 PDD 后虾皮草稿仍存在。
  • #182 的 createRequestId() 和 #183 的 collectionEligible 行为完整保留。
  • Web 单元测试与既有 e2e 测试通过。

必测场景

  • SYB 商品页:查看已关联虾皮商品详情、查看未关联时的"去关联"入口、查看已关联 PDD 商品详情,均原地展开。
  • 虾皮商品详情抽屉内修改规格映射未保存直接关闭,二次确认弹窗正确出现;确认放弃后回到 SYB 商品页原筛选状态。
  • 虾皮商品详情抽屉内点击"关联 PDD 商品"→ 叠加打开 PDD 详情抽屉 → 关闭 → 虾皮商品详情抽屉的未保存草稿仍保留(不因嵌套抽屉的开关而丢失)。
  • 直接在浏览器地址栏访问 pdd-products/index?productId=X、shopee-products/index?productId=X&targetColor=Y,行为与改动前一致。
  • PDD 商品详情抽屉内"创建备货采购""继续订单采购"完整走一遍,确认组件化后功能不变。
  • AI 匹配(#172)颜色/尺码建议、低置信度不预填、AI 待确认按钮,在从 SYB 商品页原地打开的虾皮详情抽屉里同样正常工作。
  • 快速打开商品 A 后立即打开商品 B,模拟 A 请求晚于 B 返回;页面不得回退显示 A。
  • 虾皮草稿未保存时尝试切换到另一商品,确认弹窗、取消与确认放弃三条路径均正确。
  • 嵌套抽屉分别用关闭按钮、Esc 和遮罩退出,验证只关闭顶层且焦点/滚动恢复。

风险与安全门禁

  • 回归风险集中在虾皮商品详情抽屉:该抽屉是 #172 刚落地的重点区域,提取重构必须完整回归其全部交互点(AI 建议、置信度预填、待确认、未保存确认、URL 参数驱动的高亮/自动弹窗),不能只验证"抽屉能不能原地弹出"这一件事。
  • 抽屉嵌套(虾皮详情内叠加 PDD 详情)需要验证不产生焦点、滚动、Esc、遮罩和 z-index 层级问题。
  • 从页面级状态迁移到组件后,原有 this.load() 等父页面副作用必须改为事件契约;否则可能直接破坏本单“来源页状态不丢”的核心目标。
  • 组件复用新增异步竞态:旧详情请求、AI 建议和关联请求返回时必须校验当前 productId/请求代次。
  • 不涉及权限、安全、并发、数据库结构、接口契约变化;纯前端结构性重构。

文档影响

无长期文档影响。 未新增或修改接口、参数、数据结构;只是前端展示层的承载方式调整(页面级路由展示 → 可复用组件嵌入展示),业务规则、启动、测试、部署、排错方式均未变化。因此跳过 Wiki 更新与同步。

状态

待确认(2026-09-01 已按评审意见更新;等待用户确认标注截图/低保真交互证据及上述组件契约后方可实施)。

> Gitea MCP 未向当前会话暴露,按仓库规则回退项目根目录安全配置与 Gitea API 创建本工单;凭据未写入工单、代码或日志。 ## 原始需求摘要 来源:用户于 2026-09-01 反馈,admin 里 SYB 商品页查看虾皮商品详情或 PDD 商品详情是新开浏览器标签页,使用起来麻烦。讨论后用户选择方案 B:把详情内容做成可以在原页面上原地弹出的抽屉,不新开标签页、不跳转路由,关闭后精确回到原来的位置(筛选、翻页状态不丢),并要求建单。 目的:消除"看一眼详情就要切标签页"的操作负担,尤其是 SYB 商品页需要来回对照虾皮商品和 PDD 商品信息的场景。 ## 基线与已核实事实 代码基线:`3aab1f0`(2026-09-01,当前 `main`)。核验日期 2026-09-01。原工单使用的 `5338dd0` 已过期;其后 #182、#183 修改了本单涉及的三个页面,实施必须保留统一 `createRequestId()` 以及 SYB `collectionEligible` 判断,禁止从旧基线提取后覆盖这些修复。 - PDD 商品详情、虾皮商品详情**本来就是 `el-drawer`**(`pdd-products/index.vue:63` `size="960px"`;`shopee-products/index.vue:79` `size="1080px"`),且都已支持"打开页面时通过 `?productId=` 直接展开抽屉"(各自 `created()` 读取 `this.$route.query.productId`)。现在的"新开标签页"只是拿这套现成能力包了一层 `window.open(route.href, '_blank', 'noopener')`。 - 现有跨页跳转调用点: - `syb-products/index.vue:273-284`:`openShopeeDetail(shopeeProductId, targetColor, action)`、`openPddDetail(pddProductId)`,各有 2 处模板调用 + `purchaseActionRoute` 按钮路由到这两个方法。 - `shopee-products/index.vue:287-289`:`openPddDetail(pddProductId)`,2 处模板调用(列表列 + 详情抽屉内的"关联 PDD 商品"链接)。 - `pdd-products/index.vue` 当前**没有**反向链接到虾皮商品详情(关联虾皮商品列表只在自身抽屉内筛选,不跳转)。 - **两个详情抽屉都不是简单的只读展示,而是完整的可编辑面板**,本单必须原样保留全部行为: - PDD 商品详情(`pdd-products/index.vue:63-85`):编辑商品、创建备货采购、关联虾皮商品列表(含自身分页/筛选/多选)、"继续订单采购"批量动作。 - 虾皮商品详情(`shopee-products/index.vue:79-130`):编辑档案、关联/更换 PDD 商品、**#172 新增的颜色/尺码 AI 匹配**(含低置信度不预填、AI 待确认的单独确认按钮)、添加规格值、未保存修改的关闭确认(`beforeCloseDetail`)、通过 `?targetColor=` 高亮指定行、通过 `?action=link_pdd` 自动弹出 PDD 选择器。 - 虾皮商品详情抽屉内部本身就有一条到 PDD 详情的链接(`openPddDetail`),本单实施后这条链接需要变成"在当前已经打开的虾皮抽屉之上,再叠一层 PDD 抽屉",属于抽屉嵌套场景,Element Plus 的 `el-drawer` 原生支持层叠(`append-to-body`),机制上可行。 - **风险提示**:虾皮商品详情抽屉是 #172(AI 规格建议)、#175(置信度阈值,间接)刚落地不久的重点改动区域,提取重构存在真实回归风险,需要覆盖 #172 引入的全部交互点。 ## 目标 1. 把 PDD 商品详情抽屉、虾皮商品详情抽屉分别提取为可复用组件(如 `PddProductDetailDrawer.vue`、`ShopeeProductDetailDrawer.vue`),接收目标 id(及必要的可选参数如 `targetColor`/`action`)作为 prop,自身管理加载、展开状态。 2. `syb-products` 页面的"查看虾皮商品详情""查看 PDD 商品详情"、`shopee-products` 页面的"查看关联 PDD 商品详情",全部从 `window.open` 改为挂载对应的抽屉组件,原地展开,不跳转路由、不新开标签页。 3. `pdd-products`、`shopee-products` 页面自身原有的详情抽屉,改为直接使用同一份提取出来的组件(同源实现,不留两份重复代码)。 4. 关闭详情抽屉后,来源页面的筛选、翻页、选中状态保持不变(因为不再发生路由跳转,天然满足,只需验证)。 5. 详情抽屉内部原有的"未保存修改二次确认""高亮指定行""自动弹出 PDD 选择器"等既有行为,在新的组件化形态下继续正确工作。 6. 虾皮商品详情抽屉内到 PDD 详情的跳转,改为叠加展示 PDD 抽屉,不再跳转。 ## 非目标 - 不改变两个详情抽屉的业务逻辑、可编辑内容、接口调用、数据校验规则,纯粹是"承载方式"从整页路由改为可嵌入组件。 - 不新增 `pdd-products` 页面到虾皮商品详情的反向链接(目前没有这条链接,本单不主动加,如需要另评估)。 - 不改变 `?productId=`(及 `targetColor`/`action`)直接访问对应整页仍然可以打开详情抽屉的既有行为——两种打开方式(整页直达、从其他页面原地弹出)都要继续可用,互不冲突。 - 不改变 #172 的 AI 建议逻辑、置信度判定、`SetMapping`/`ConfirmMapping` 等接口行为。 - 不涉及权限、并发、迁移、订单、支付。 ## 前置依赖与并行性 - #182、#183 已完成并纳入当前基线;#183 曾修改 `syb-products/index.vue`,因此原“无代码重叠”判断不再适用,但不存在未完成依赖。 - 与任何同时改动 `syb-products/index.vue`、`shopee-products/index.vue`、`pdd-products/index.vue` 抽屉内部逻辑的任务不可并行,避免同文件冲突。 - 建议在修正后的 #187 完成并验证页面缓存后再实施本单,以便准确验收来源页筛选、分页和选中状态。 ## 固定实施方案 1. 新建 `web/src/views/goauto/pdd-products/PddProductDetailDrawer.vue`:把现有 `pdd-products/index.vue:63-85` 的抽屉内容、及其依赖的 `detail`/`related`/`relatedPurchase`/`stock` 相关 data、methods、computed 一并迁移进来,对外暴露 `v-model:open`、`product-id` prop,内部自行请求数据,不依赖外部注入状态。 2. 新建 `web/src/views/goauto/shopee-products/ShopeeProductDetailDrawer.vue`:同样迁移 `shopee-products/index.vue:79-130` 及其配套的 `detail`/`pddPicker`/`edit`(是否一并内聚,视依赖紧密程度定)/#172 AI 建议相关状态与方法,对外暴露 `v-model:open`、`product-id`、可选 `target-color`、可选 `action` prop。 3. `pdd-products/index.vue`、`shopee-products/index.vue` 自身改为引用各自新组件,原有内联抽屉模板与相关 data/methods 删除,不保留重复实现。 4. `ShopeeProductDetailDrawer.vue` 内到 PDD 详情的跳转,改为挂载 `PddProductDetailDrawer.vue` 并原地展开,不再 `window.open`/路由跳转。 5. `syb-products/index.vue` 引入这两个抽屉组件,`openShopeeDetail`/`openPddDetail` 改为设置对应组件的 `open`/`product-id`(及 `targetColor`/`action`)而不是 `window.open`;原有按钮路由(`purchaseActionRoute` 等)指向的目标方法同步改造。 6. 保留 `?productId=` 直达整页展开详情的既有能力:`pdd-products`、`shopee-products` 页面读取路由参数,给新抽屉组件传入初始 `product-id`/`open=true`;同时验证页面已被 keep-alive 缓存后再次收到 query 变化的行为,不能只依赖首次 `created()`。 7. 明确组件事件契约:至少包含 `update:modelValue`、`product-updated`、`mapping-updated`、`pdd-linked`、`purchase-created`。父页面收到事件后采用局部更新或保持原列表不刷新;不得直接调用父页面 `load()` 导致筛选、分页或选中行丢失。 8. 两个抽屉组件都增加请求代次/失效保护:快速连续打开不同商品、关闭后旧请求返回、重新打开时,旧响应不得覆盖当前商品或重新打开已关闭抽屉。 9. 产品 ID 在抽屉打开期间发生变化且存在未保存草稿时,必须先执行与关闭抽屉相同的放弃确认;确认前不得切换商品。 ## 设计证据 现有抽屉视觉规范继续复用,不需要完整高保真原型;但“虾皮详情之上叠加 PDD 详情”属于新的交互状态。实施前至少提供标注截图或低保真图并由用户确认,覆盖:SYB 页原地打开虾皮/PDD 详情、虾皮抽屉叠加 PDD 抽屉、存在未保存草稿时关闭/切换商品确认、加载失败四种状态。工单需记录确认时间与覆盖范围。 ## 验收标准 - [ ] 从 SYB 商品页点击虾皮商品/PDD 商品详情,原地弹出对应抽屉,不新开标签页、不跳转路由。 - [ ] 关闭抽屉后,SYB 商品页的筛选条件、分页位置、已选中行保持不变。 - [ ] 从虾皮商品详情抽屉点击"关联 PDD 商品"链接,在其上叠加展示 PDD 详情抽屉;关闭 PDD 抽屉回到虾皮商品详情抽屉,状态不丢失。 - [ ] `pdd-products`、`shopee-products` 页面自身通过 `?productId=` 直接访问,详情抽屉行为与改动前一致。 - [ ] 虾皮商品详情抽屉内 #172 的颜色/尺码 AI 匹配(含低置信度不预填、AI 待确认按钮)在组件化后行为不变。 - [ ] 虾皮商品详情抽屉的未保存修改二次确认(`beforeCloseDetail`)在组件化后行为不变。 - [ ] `?targetColor=` 高亮指定行、`?action=link_pdd` 自动弹出 PDD 选择器,在组件化后行为不变。 - [ ] PDD 商品详情抽屉内"编辑商品""创建备货采购""关联虾皮商品列表及继续订单采购"在组件化后行为不变。 - [ ] `pdd-products`、`shopee-products` 页面不再各自维护一份重复的详情抽屉实现。 - [ ] 抽屉组件通过显式事件通知父页面;关闭或保存后不得无条件刷新父列表并清空筛选、分页、选中行。 - [ ] 快速依次打开商品 A/B、关闭后等待旧请求返回,最终只显示当前商品且不会被旧响应重新打开。 - [ ] 嵌套抽屉中 Esc、遮罩、焦点、滚动与 z-index 正确:一次只关闭最上层,关闭 PDD 后虾皮草稿仍存在。 - [ ] #182 的 `createRequestId()` 和 #183 的 `collectionEligible` 行为完整保留。 - [ ] Web 单元测试与既有 e2e 测试通过。 ## 必测场景 - SYB 商品页:查看已关联虾皮商品详情、查看未关联时的"去关联"入口、查看已关联 PDD 商品详情,均原地展开。 - 虾皮商品详情抽屉内修改规格映射未保存直接关闭,二次确认弹窗正确出现;确认放弃后回到 SYB 商品页原筛选状态。 - 虾皮商品详情抽屉内点击"关联 PDD 商品"→ 叠加打开 PDD 详情抽屉 → 关闭 → 虾皮商品详情抽屉的未保存草稿仍保留(不因嵌套抽屉的开关而丢失)。 - 直接在浏览器地址栏访问 `pdd-products/index?productId=X`、`shopee-products/index?productId=X&targetColor=Y`,行为与改动前一致。 - PDD 商品详情抽屉内"创建备货采购""继续订单采购"完整走一遍,确认组件化后功能不变。 - AI 匹配(#172)颜色/尺码建议、低置信度不预填、AI 待确认按钮,在从 SYB 商品页原地打开的虾皮详情抽屉里同样正常工作。 - 快速打开商品 A 后立即打开商品 B,模拟 A 请求晚于 B 返回;页面不得回退显示 A。 - 虾皮草稿未保存时尝试切换到另一商品,确认弹窗、取消与确认放弃三条路径均正确。 - 嵌套抽屉分别用关闭按钮、Esc 和遮罩退出,验证只关闭顶层且焦点/滚动恢复。 ## 风险与安全门禁 - **回归风险集中在虾皮商品详情抽屉**:该抽屉是 #172 刚落地的重点区域,提取重构必须完整回归其全部交互点(AI 建议、置信度预填、待确认、未保存确认、URL 参数驱动的高亮/自动弹窗),不能只验证"抽屉能不能原地弹出"这一件事。 - 抽屉嵌套(虾皮详情内叠加 PDD 详情)需要验证不产生焦点、滚动、Esc、遮罩和 z-index 层级问题。 - 从页面级状态迁移到组件后,原有 `this.load()` 等父页面副作用必须改为事件契约;否则可能直接破坏本单“来源页状态不丢”的核心目标。 - 组件复用新增异步竞态:旧详情请求、AI 建议和关联请求返回时必须校验当前 productId/请求代次。 - 不涉及权限、安全、并发、数据库结构、接口契约变化;纯前端结构性重构。 ## 文档影响 **无长期文档影响。** 未新增或修改接口、参数、数据结构;只是前端展示层的承载方式调整(页面级路由展示 → 可复用组件嵌入展示),业务规则、启动、测试、部署、排错方式均未变化。因此跳过 Wiki 更新与同步。 ## 状态 待确认(2026-09-01 已按评审意见更新;等待用户确认标注截图/低保真交互证据及上述组件契约后方可实施)。
Author
Owner

实施前低保真交互证据(待用户确认)

Gitea MCP 当前会话未提供,按项目规则回退 Gitea API。以下证据复用现有 Element Plus 抽屉视觉,不改变颜色、字体、表格或业务按钮,只确认新的承载与层级行为。

状态 A:SYB 页面原地打开详情

┌──────────── SYB 商品列表(筛选 / 页码 / 勾选保持原值)────────────┐
│ 商品行 …                      [查看虾皮] [查看 PDD]             │
│                                                               │
│                 ┌──── 虾皮详情抽屉 1080px ───────────────────┐ │
│                 │ 标题 / 编辑 / PDD 关联 / AI 匹配 / 规格表  │ │
│                 │                                      [关闭]│ │
│                 └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
  • URL 与标签页不变化,不调用父列表 load。
  • 关闭后焦点回到触发按钮,筛选、页码和勾选不变。
  • 直接查看 PDD 时同样原地打开现有 960px PDD 详情抽屉。

状态 B:虾皮详情上叠加 PDD 详情

SYB 列表(背景锁定)
        ┌──── 虾皮详情 1080px(保留草稿)───────────────────────┐
        │ 关联 PDD 商品 [查看详情]                              │
        │       ┌──── PDD 详情 960px(顶层)─────────────────┐ │
        │       │ 编辑 / 备货采购 / 关联虾皮 / 继续订单采购  │ │
        │       │                                     [关闭] │ │
        │       └────────────────────────────────────────────┘ │
        └───────────────────────────────────────────────────────┘
  • 两层都 append-to-body,PDD 是唯一顶层;遮罩、Esc、关闭按钮一次只关闭 PDD。
  • 关闭 PDD 后恢复虾皮抽屉焦点与滚动位置,虾皮未保存草稿保持不变。
  • 再关闭虾皮抽屉才返回 SYB 列表。

状态 C:未保存草稿时关闭或切换商品

┌────────────── 放弃未保存修改? ──────────────┐
│ 当前规格映射尚未保存。                       │
│ [继续编辑]                     [放弃并关闭/切换] │
└──────────────────────────────────────────────┘
  • 关闭虾皮抽屉、遮罩、Esc,以及把 productId 从 A 切到 B,统一经过同一确认。
  • 取消:保留 A 和草稿;确认:先失效 A 的异步请求,再关闭或加载 B。
  • 仅关闭顶层 PDD 抽屉不会触发虾皮草稿确认。

状态 D:详情加载失败

┌──── 商品详情抽屉 ────────────────────────────┐
│ [!] 商品详情加载失败,请稍后重试             │
│                         [重新加载] [关闭]     │
└──────────────────────────────────────────────┘
  • 抽屉保持打开,错误可感知且有恢复入口;来源列表状态不变。
  • 快速打开 A/B 或关闭后旧请求返回时,以请求代次 + 当前 productId + open 状态共同判定,旧响应不得覆盖或重新打开抽屉。

组件交互契约

  • 输入:modelValue/open、productId;虾皮另有 targetColor、action。
  • 输出:update:modelValue、product-updated、mapping-updated、pdd-linked、purchase-created。
  • 父页面只做必要的局部行更新,不无条件刷新列表。
  • 保留 ?productId=、?targetColor=、?action=link_pdd 的整页直达能力,并处理 keep-alive 后 query 变化。
  • 保留 #182 createRequestId() 与 #183 collectionEligible。

UX 校验结论:复用现有视觉;新增部分重点遵循状态保持、明确关闭路径、未保存 sheet dismissal 确认、可恢复错误、可见焦点和受控 z-index。请用户确认以上四种状态和组件契约后再实施生产代码。

## 实施前低保真交互证据(待用户确认) Gitea MCP 当前会话未提供,按项目规则回退 Gitea API。以下证据复用现有 Element Plus 抽屉视觉,不改变颜色、字体、表格或业务按钮,只确认新的承载与层级行为。 ### 状态 A:SYB 页面原地打开详情 ┌──────────── SYB 商品列表(筛选 / 页码 / 勾选保持原值)────────────┐ │ 商品行 … [查看虾皮] [查看 PDD] │ │ │ │ ┌──── 虾皮详情抽屉 1080px ───────────────────┐ │ │ │ 标题 / 编辑 / PDD 关联 / AI 匹配 / 规格表 │ │ │ │ [关闭]│ │ │ └────────────────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────┘ - URL 与标签页不变化,不调用父列表 load。 - 关闭后焦点回到触发按钮,筛选、页码和勾选不变。 - 直接查看 PDD 时同样原地打开现有 960px PDD 详情抽屉。 ### 状态 B:虾皮详情上叠加 PDD 详情 SYB 列表(背景锁定) ┌──── 虾皮详情 1080px(保留草稿)───────────────────────┐ │ 关联 PDD 商品 [查看详情] │ │ ┌──── PDD 详情 960px(顶层)─────────────────┐ │ │ │ 编辑 / 备货采购 / 关联虾皮 / 继续订单采购 │ │ │ │ [关闭] │ │ │ └────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────┘ - 两层都 append-to-body,PDD 是唯一顶层;遮罩、Esc、关闭按钮一次只关闭 PDD。 - 关闭 PDD 后恢复虾皮抽屉焦点与滚动位置,虾皮未保存草稿保持不变。 - 再关闭虾皮抽屉才返回 SYB 列表。 ### 状态 C:未保存草稿时关闭或切换商品 ┌────────────── 放弃未保存修改? ──────────────┐ │ 当前规格映射尚未保存。 │ │ [继续编辑] [放弃并关闭/切换] │ └──────────────────────────────────────────────┘ - 关闭虾皮抽屉、遮罩、Esc,以及把 productId 从 A 切到 B,统一经过同一确认。 - 取消:保留 A 和草稿;确认:先失效 A 的异步请求,再关闭或加载 B。 - 仅关闭顶层 PDD 抽屉不会触发虾皮草稿确认。 ### 状态 D:详情加载失败 ┌──── 商品详情抽屉 ────────────────────────────┐ │ [!] 商品详情加载失败,请稍后重试 │ │ [重新加载] [关闭] │ └──────────────────────────────────────────────┘ - 抽屉保持打开,错误可感知且有恢复入口;来源列表状态不变。 - 快速打开 A/B 或关闭后旧请求返回时,以请求代次 + 当前 productId + open 状态共同判定,旧响应不得覆盖或重新打开抽屉。 ### 组件交互契约 - 输入:modelValue/open、productId;虾皮另有 targetColor、action。 - 输出:update:modelValue、product-updated、mapping-updated、pdd-linked、purchase-created。 - 父页面只做必要的局部行更新,不无条件刷新列表。 - 保留 ?productId=、?targetColor=、?action=link_pdd 的整页直达能力,并处理 keep-alive 后 query 变化。 - 保留 #182 createRequestId() 与 #183 collectionEligible。 UX 校验结论:复用现有视觉;新增部分重点遵循状态保持、明确关闭路径、未保存 sheet dismissal 确认、可恢复错误、可见焦点和受控 z-index。请用户确认以上四种状态和组件契约后再实施生产代码。
Author
Owner

用户于 2026-09-01 明确回复“确认 #186 低保真方案”。确认范围:SYB 原地打开虾皮/PDD 详情、虾皮详情上叠加 PDD 详情、未保存草稿关闭/切换确认、加载失败与重试,以及评论中列明的组件事件契约、请求代次保护、焦点/遮罩/Esc/滚动层级规则。现开始实施;基线 b31896e(已包含 #187),保留 #172、#182、#183 行为。Gitea MCP 当前会话未提供,继续回退 Gitea API。

用户于 2026-09-01 明确回复“确认 #186 低保真方案”。确认范围:SYB 原地打开虾皮/PDD 详情、虾皮详情上叠加 PDD 详情、未保存草稿关闭/切换确认、加载失败与重试,以及评论中列明的组件事件契约、请求代次保护、焦点/遮罩/Esc/滚动层级规则。现开始实施;基线 b31896e(已包含 #187),保留 #172、#182、#183 行为。Gitea MCP 当前会话未提供,继续回退 Gitea API。
Author
Owner

实施完成,待验收

已按 2026-09-01 用户确认的 #186 低保真方案完成实现并推送。

实现

  • 抽取 PddProductDetailDrawer.vue,承载 PDD 详情、编辑、关联订单采购和备货采购能力。
  • 抽取 ShopeeProductDetailDrawer.vue,承载虾皮详情、PDD 关联、规格编辑及 #172 AI 匹配,并在其上层嵌套 PDD 抽屉。
  • SYB、虾皮、PDD 三个列表页统一复用上述抽屉;SYB/虾皮入口不再调用 window.open。
  • 保留 productId、targetColor、action=link_pdd 和 keep-alive 查询变化处理。
  • 保留 #182 createRequestId、#183 collectionEligible;低置信度 AI 建议仍只展示原因、不预填。
  • 增加顶层抽屉 Esc/遮罩关闭边界、虾皮未保存映射关闭/切换确认、加载失败重试及请求 generation/current-product/open 竞态保护。
  • 组件通过显式事件通知实际变更,详情内部刷新不再无条件刷新父列表。

验证

  • pnpm exec eslint(5 个受影响 Vue 文件):通过。
  • pnpm run test:unit:11 suites / 39 tests 全部通过。
  • Playwright 受影响回归:15 tests 全部通过(PDD 商品、PDD 关联订单、虾皮 PDD 选择器、SYB 商品布局与下一步动作)。
  • 新增回归覆盖:SYB 原地打开抽屉、不产生 popup;虾皮叠加 PDD 时 Esc 只关闭顶层;低置信度 AI 建议不预填。
  • pnpm run build:prod:通过。
  • git diff --check:通过。
  • 仓库级 scripts/verify.ps1 -Component web:被本工单范围外 web/src/views/goauto/purchase-tasks/index.vue 既存混合空格/Tab 的 24 个 lint error 阻断;本次未修改该文件,目标文件 lint 与构建均通过。

交付

  • 提交:6ab2f62 feat(web): 内联展示商品详情抽屉 (#186)
  • 已推送:origin/main
  • 长期文档影响:无。此次仅改变现有页面详情的呈现/导航方式,不改变 API、数据结构、业务规则、安全边界或运维方式,因此按工单方案跳过 Wiki 更新与同步。
  • 未执行线上发布;发布属于独立高风险动作,等待单独明确授权。

工单保持开启,等待人工验收。

## 实施完成,待验收 已按 2026-09-01 用户确认的 #186 低保真方案完成实现并推送。 ### 实现 - 抽取 `PddProductDetailDrawer.vue`,承载 PDD 详情、编辑、关联订单采购和备货采购能力。 - 抽取 `ShopeeProductDetailDrawer.vue`,承载虾皮详情、PDD 关联、规格编辑及 #172 AI 匹配,并在其上层嵌套 PDD 抽屉。 - SYB、虾皮、PDD 三个列表页统一复用上述抽屉;SYB/虾皮入口不再调用 `window.open`。 - 保留 `productId`、`targetColor`、`action=link_pdd` 和 keep-alive 查询变化处理。 - 保留 #182 `createRequestId`、#183 `collectionEligible`;低置信度 AI 建议仍只展示原因、不预填。 - 增加顶层抽屉 Esc/遮罩关闭边界、虾皮未保存映射关闭/切换确认、加载失败重试及请求 generation/current-product/open 竞态保护。 - 组件通过显式事件通知实际变更,详情内部刷新不再无条件刷新父列表。 ### 验证 - `pnpm exec eslint`(5 个受影响 Vue 文件):通过。 - `pnpm run test:unit`:11 suites / 39 tests 全部通过。 - Playwright 受影响回归:15 tests 全部通过(PDD 商品、PDD 关联订单、虾皮 PDD 选择器、SYB 商品布局与下一步动作)。 - 新增回归覆盖:SYB 原地打开抽屉、不产生 popup;虾皮叠加 PDD 时 Esc 只关闭顶层;低置信度 AI 建议不预填。 - `pnpm run build:prod`:通过。 - `git diff --check`:通过。 - 仓库级 `scripts/verify.ps1 -Component web`:被本工单范围外 `web/src/views/goauto/purchase-tasks/index.vue` 既存混合空格/Tab 的 24 个 lint error 阻断;本次未修改该文件,目标文件 lint 与构建均通过。 ### 交付 - 提交:`6ab2f62 feat(web): 内联展示商品详情抽屉 (#186)` - 已推送:`origin/main` - 长期文档影响:无。此次仅改变现有页面详情的呈现/导航方式,不改变 API、数据结构、业务规则、安全边界或运维方式,因此按工单方案跳过 Wiki 更新与同步。 - 未执行线上发布;发布属于独立高风险动作,等待单独明确授权。 工单保持开启,等待人工验收。
Author
Owner

线上发布完成

经用户明确授权,已将 #186 最新提交发布到线上。

  • 提交:6ab2f62
  • 发布标识:20260901-112853-6ab2f62
  • 发布目录:/home/goauto/releases/20260901-112853-6ab2f62
  • 发布包 SHA-256:d0b0bfe0fd0d56b382728eeba6daee4708749eec872c450a646ae907e19e4205
  • 上一发布(回滚点):/home/goauto/releases/20260901-102000-3aab1f0
  • 变更范围:从当前发布复制形成新版本,仅替换提交 6ab2f62 的生产 Web dist;未执行数据库迁移,未修改服务端配置、Agent APK 或当前 Agent 版本。
  • 原子切换后已重启 goauto.service 并重载 Nginx;服务状态 active,进程工作目录指向新发布。
  • 外部验证:/ 200、/api/v1/app-config 200、Shopee/PDD 新详情抽屉分包均为 200。
  • Agent 私有目录仍保留 3 个 APK;旧发布目录仍存在,可按既有流程回滚。
  • 最近服务错误日志复核:无错误条目。

工单继续保持待验收。

## 线上发布完成 经用户明确授权,已将 #186 最新提交发布到线上。 - 提交:`6ab2f62` - 发布标识:`20260901-112853-6ab2f62` - 发布目录:`/home/goauto/releases/20260901-112853-6ab2f62` - 发布包 SHA-256:`d0b0bfe0fd0d56b382728eeba6daee4708749eec872c450a646ae907e19e4205` - 上一发布(回滚点):`/home/goauto/releases/20260901-102000-3aab1f0` - 变更范围:从当前发布复制形成新版本,仅替换提交 `6ab2f62` 的生产 Web `dist`;未执行数据库迁移,未修改服务端配置、Agent APK 或当前 Agent 版本。 - 原子切换后已重启 `goauto.service` 并重载 Nginx;服务状态 `active`,进程工作目录指向新发布。 - 外部验证:`/` 200、`/api/v1/app-config` 200、Shopee/PDD 新详情抽屉分包均为 200。 - Agent 私有目录仍保留 3 个 APK;旧发布目录仍存在,可按既有流程回滚。 - 最近服务错误日志复核:无错误条目。 工单继续保持待验收。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#186