From 4c6810321795181cca7ff8ca9a6e80c86382407e Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 5 Oct 2026 21:15:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(routing):=20=E6=B8=A0=E9=81=93=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=A1=B5=E6=8A=8A=20Rock=20=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E5=B1=A5=E7=BA=A6=E7=AD=96=E7=95=A5=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 最新的 Rock 商品之前被算进第一平台,配置里也无法单独选择 Rock 库存池。 Co-authored-by: Cursor --- backend/internal/service/merchant_catalog.go | 7 +- backend/internal/service/provider_test.go | 5 ++ frontend/src/pages/PlatformProducts.tsx | 74 ++++++++++++++++++-- frontend/src/types/index.ts | 4 +- 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/backend/internal/service/merchant_catalog.go b/backend/internal/service/merchant_catalog.go index 8f70af8..995ea79 100644 --- a/backend/internal/service/merchant_catalog.go +++ b/backend/internal/service/merchant_catalog.go @@ -271,9 +271,12 @@ func ensureProduct(tx *gorm.DB, in CreateMerchantProductInput) (*model.Product, // UpdateProductRouting 更新平台目录商品的履约渠道与优先级配置 func (s *MerchantService) UpdateProductRouting(catalogID uint, routing ProductRoutingConfig, actorUserID uint) error { switch routing.RoutingMode { - case RoutingModePriority, RoutingModeLewan, RoutingModeDLC: + case RoutingModePriority, RoutingModeLewan, RoutingModeDLC, RoutingModeRock: default: - return errors.New("routing_mode 仅支持 priority / lewan / dlc") + return errors.New("routing_mode 仅支持 priority / lewan / dlc / rock") + } + if routing.RoutingMode == RoutingModeRock { + routing.Priority = []string{ProviderRock} } if routing.RoutingMode == RoutingModePriority { if len(routing.Priority) == 0 { diff --git a/backend/internal/service/provider_test.go b/backend/internal/service/provider_test.go index 32dbd54..614ff96 100644 --- a/backend/internal/service/provider_test.go +++ b/backend/internal/service/provider_test.go @@ -55,6 +55,11 @@ func TestParseProductRoutingConfig(t *testing.T) { if cfg5.DLCGoodID != "682ef39ca8f40c4234c59f38" { t.Fatalf("expected builtin DLC good id, got %s", cfg5.DLCGoodID) } + + cfgRock := ParseProductRoutingConfig(`{"routing_mode":"rock","priority":["rock"],"delivery_type":"LINK_BINDING"}`, "rock_black_tshirt") + if cfgRock.RoutingMode != RoutingModeRock || len(cfgRock.Priority) != 1 || cfgRock.Priority[0] != ProviderRock { + t.Fatalf("expected rock-only routing, got %+v", cfgRock) + } } func TestFulfillmentRouterResolution(t *testing.T) { diff --git a/frontend/src/pages/PlatformProducts.tsx b/frontend/src/pages/PlatformProducts.tsx index 307b080..190ae31 100644 --- a/frontend/src/pages/PlatformProducts.tsx +++ b/frontend/src/pages/PlatformProducts.tsx @@ -32,6 +32,7 @@ import { SearchOutlined, SettingOutlined, SwapOutlined, + ThunderboltOutlined, } from '@ant-design/icons' import type { ColumnsType } from 'antd/es/table' import { lewanApi, platformApi } from '../api' @@ -79,7 +80,7 @@ export default function PlatformProducts() { setLoading(true) try { const list = await platformApi.productCatalog() - setCatalog(list || []) + setCatalog([...(list || [])].sort((a, b) => b.id - a.id)) } catch (e) { message.error(e instanceof Error ? e.message : '加载商品目录失败') } finally { @@ -117,11 +118,13 @@ export default function PlatformProducts() { let priorityCount = 0 let lewanOnlyCount = 0 let dlcOnlyCount = 0 + let rockOnlyCount = 0 catalog.forEach((item) => { const mode = item.routing?.routing_mode || 'dlc' if (mode === 'priority') priorityCount++ else if (mode === 'lewan') lewanOnlyCount++ + else if (mode === 'rock') rockOnlyCount++ else dlcOnlyCount++ }) @@ -130,6 +133,7 @@ export default function PlatformProducts() { priorityCount, lewanOnlyCount, dlcOnlyCount, + rockOnlyCount, } }, [catalog]) @@ -156,7 +160,8 @@ export default function PlatformProducts() { filterMode === 'all' || (filterMode === 'priority' && mode === 'priority') || (filterMode === 'lewan' && mode === 'lewan') || - (filterMode === 'dlc' && mode === 'dlc') + (filterMode === 'dlc' && mode === 'dlc') || + (filterMode === 'rock' && mode === 'rock') const matchCategory = filterCategory === 'all' || item.category === filterCategory @@ -196,14 +201,16 @@ export default function PlatformProducts() { : ['lewan', 'dlc'] : values.routing_mode === 'lewan' ? ['lewan'] + : values.routing_mode === 'rock' + ? ['rock'] : ['dlc'] const payload: UpdateProductRoutingInput = { routing_mode: values.routing_mode, priority, - dlc_good_id: values.dlc_good_id?.trim() || '', - lewan_product_id: values.lewan_product_id?.trim() || '', - lewan_name: values.lewan_name?.trim() || '', + dlc_good_id: values.routing_mode === 'rock' ? '' : values.dlc_good_id?.trim() || '', + lewan_product_id: values.routing_mode === 'rock' ? '' : values.lewan_product_id?.trim() || '', + lewan_name: values.routing_mode === 'rock' ? '' : values.lewan_name?.trim() || '', delivery_type: values.delivery_type || 'LINK_BINDING', } @@ -379,6 +386,13 @@ export default function PlatformProducts() { ) } + if (mode === 'rock') { + return ( + } style={{ fontWeight: 600, padding: '3px 8px' }}> + 仅走 Rock 库存池 + + ) + } return ( } style={{ fontWeight: 600, padding: '3px 8px' }}> 仅走第一平台 (DLC) @@ -456,6 +470,17 @@ export default function PlatformProducts() { const routing = r.routing const lewanId = routing?.lewan_product_id const dlcId = routing?.dlc_good_id + if (routing?.routing_mode === 'rock') { + return ( + +
+ Rock: + 通用黑色库存池 +
+ 不走第一平台 / 乐玩,库存不足时按自动补货策略采购 +
+ ) + } return (
@@ -665,6 +690,20 @@ export default function PlatformProducts() {
+ + +
+ 仅 Rock 库存池 +
+ +
+
+
{metrics.rockOnlyCount}
+
+ 最新 Rock 发货,库存不足自动补货 +
+
+ {/* 筛选与搜索工具条 */} @@ -692,6 +731,7 @@ export default function PlatformProducts() { { value: 'priority', label: '双平台优先 (Priority)' }, { value: 'lewan', label: '仅乐玩开放平台' }, { value: 'dlc', label: '仅第一平台 (DLC)' }, + { value: 'rock', label: '仅 Rock 库存池' }, ]} /> {categories.length > 0 && ( @@ -791,6 +831,14 @@ export default function PlatformProducts() { + +
+ 仅 Rock 库存池 (Rock Only) +
+ 走 0666.pro 通用库存。可用 Token 低于安全水位时,按自动补货数量再采购一批。 +
+
+
@@ -820,6 +868,18 @@ export default function PlatformProducts() { } + prev.routing_mode !== cur.routing_mode}> + {({ getFieldValue }) => + getFieldValue('routing_mode') === 'rock' ? ( + + ) : ( + <> 渠道商品映射信息 @@ -885,6 +945,10 @@ export default function PlatformProducts() { + + ) + } + diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 8337d86..e9e4582 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -85,7 +85,7 @@ export interface MerchantProduct { } export interface ProductRoutingConfig { - routing_mode: 'priority' | 'lewan' | 'dlc' + routing_mode: 'priority' | 'lewan' | 'dlc' | 'rock' priority?: string[] dlc_good_id?: string lewan_product_id?: string @@ -379,7 +379,7 @@ export interface LewanProductListResult { } export interface UpdateProductRoutingInput { - routing_mode: 'priority' | 'lewan' | 'dlc' + routing_mode: 'priority' | 'lewan' | 'dlc' | 'rock' priority?: string[] dlc_good_id?: string lewan_product_id?: string