diff --git a/apps/admin/src/views/goods/GoodsView.vue b/apps/admin/src/views/goods/GoodsView.vue index 847aca4..898a356 100644 --- a/apps/admin/src/views/goods/GoodsView.vue +++ b/apps/admin/src/views/goods/GoodsView.vue @@ -418,18 +418,26 @@ function findOgNodeById(rawId: string | number): any { return found } +/** 链接名的款号段(第 2 段,如 BRTF004);同款号 = 同款 */ +function skuCodeOf(name: string | null | undefined): string { + return (name ?? '').split('-').map(s => s.trim())[1] ?? '' +} + function collectSiblings(ogNode: any): any[] { const result: any[] = [] + const myFamily = ogNode.familyId ? String(ogNode.familyId) : null + const mySku = skuCodeOf(ogNode.goodName ?? ogNode.label) function traverse(nodes: any[]) { for (const n of nodes) { - // 全局同款链接(跨分类):合并同名按名称组键匹配, - // 不局限于当前分类;含已配置的,勾选归族操作幂等 - if ( - n.isOG && - String(n.rawId) !== String(ogNode.rawId) && - sameOriginGroup(ogNode.goodName ?? ogNode.label, n.goodName ?? n.label) - ) { - result.push(n) + // 全局同款链接(跨分类/跨工艺/跨物流):族归属精确匹配,或款号一致; + // 含已配置的,勾选归族操作幂等 + if (n.isOG && String(n.rawId) !== String(ogNode.rawId)) { + const nFamily = n.familyId ? String(n.familyId) : null + const nSku = skuCodeOf(n.goodName ?? n.label) + const same = (myFamily && nFamily && myFamily === nFamily) + || (Boolean(mySku) && Boolean(nSku) && mySku === nSku) + || (!mySku && sameOriginGroup(ogNode.goodName ?? ogNode.label, n.goodName ?? n.label)) + if (same) result.push(n) } if (n.children?.length) traverse(n.children) } @@ -1566,7 +1574,14 @@ onMounted(() => loadAll()) font-size: 13px; line-height: 1.4; cursor: pointer; max-width: calc(100% - 40px); } -.good-name-col { flex: 1; min-width: 0; overflow: hidden; } +.good-name-col { + flex: 1; min-width: 0; overflow: hidden; + display: flex; align-items: center; gap: 6px; +} +.good-name-col > .el-tooltip__trigger { + min-width: 0; overflow: hidden; + display: inline-flex; align-items: center; gap: 4px; +} .gv-merged-badge { margin-left: 4px; padding: 0 5px; diff --git a/apps/admin/src/views/goods/components/GoodsConfigDialog.vue b/apps/admin/src/views/goods/components/GoodsConfigDialog.vue index cce5263..0326695 100644 --- a/apps/admin/src/views/goods/components/GoodsConfigDialog.vue +++ b/apps/admin/src/views/goods/components/GoodsConfigDialog.vue @@ -135,13 +135,13 @@ async function handleSubmit() { {{ dropTarget?.label }} - +
@@ -149,7 +149,9 @@ async function handleSubmit() { {{ s.goodName }} -
没有匹配的链接
+
+ {{ siblings.length ? '没有匹配的链接' : '未找到同款链接(同款号或同族)' }} +
diff --git a/docs/references/product-center.md b/docs/references/product-center.md index 69bfac8..251d880 100644 --- a/docs/references/product-center.md +++ b/docs/references/product-center.md @@ -154,8 +154,9 @@ pnpm --filter @inkreach/api backfill:product-families 归并(同组合取最低价,「链接数」列显示来源数,人工价带标签),无需额外请求; - 编辑弹窗商品「名称」预填解析后的「品名 型号」,保存即采用解析名;右侧原产品库与配置弹窗 始终显示**原始链接名**; -- 配置弹窗「合并同名」候选为**全局同款链接**(按名称 3 段组键跨分类匹配, - 含已配置链接),支持搜索过滤。 +- 配置弹窗「合并同名」区块**常显**,候选为**全局同款链接**:按 链接款号(名称第 2 段, + 如 BRTF004)或族归属跨分类匹配,同款不同工艺/物流/仓库均在列(含已配置链接), + 支持搜索过滤;无候选时显示空态提示。 - 右树徽标语义(**族感知**,公开契约一族一款):**已配置 N**(绿,本链接已配置为官网商品, N=国数)/ **已配置**(绿,本链接未单独建商品但所属族已配置)/ **成族**(蓝,已归族且全族 未配置)/ **未配置**(橙);「定位到官网商品」在自身或同族已配置时出现(按 主链接 → 同族 →