feat(routing): 渠道配置页把 Rock 作为独立履约策略展示
最新的 Rock 商品之前被算进第一平台,配置里也无法单独选择 Rock 库存池。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
if (mode === 'rock') {
|
||||
return (
|
||||
<Tag color="magenta" icon={<ThunderboltOutlined />} style={{ fontWeight: 600, padding: '3px 8px' }}>
|
||||
仅走 Rock 库存池
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Tag color="orange" icon={<DesktopOutlined />} 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 (
|
||||
<Space direction="vertical" size={2} style={{ width: '100%', fontSize: 12 }}>
|
||||
<div>
|
||||
<Text type="secondary">Rock: </Text>
|
||||
<Tag color="magenta" style={{ fontSize: 11 }}>通用黑色库存池</Tag>
|
||||
</div>
|
||||
<Text type="secondary">不走第一平台 / 乐玩,库存不足时按自动补货策略采购</Text>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Space direction="vertical" size={2} style={{ width: '100%', fontSize: 12 }}>
|
||||
<div>
|
||||
@@ -665,6 +690,20 @@ export default function PlatformProducts() {
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Card className="metric-card" styles={{ body: { padding: '16px 20px' } }}>
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">仅 Rock 库存池</span>
|
||||
<div className="metric-card-icon metric-card-icon--purple">
|
||||
<ThunderboltOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<div className="metric-card-value">{metrics.rockOnlyCount}</div>
|
||||
<div className="metric-card-footer">
|
||||
<span>最新 Rock 发货,库存不足自动补货</span>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* 筛选与搜索工具条 */}
|
||||
@@ -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() {
|
||||
</div>
|
||||
</div>
|
||||
</Radio>
|
||||
<Radio value="rock" style={{ padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: 8, width: '100%' }}>
|
||||
<div>
|
||||
<strong style={{ color: '#0f172a' }}>仅 Rock 库存池 (Rock Only)</strong>
|
||||
<div style={{ color: '#64748b', fontSize: 12, marginTop: 2 }}>
|
||||
走 0666.pro 通用库存。可用 Token 低于安全水位时,按自动补货数量再采购一批。
|
||||
</div>
|
||||
</div>
|
||||
</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
@@ -820,6 +868,18 @@ export default function PlatformProducts() {
|
||||
}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.routing_mode !== cur.routing_mode}>
|
||||
{({ getFieldValue }) =>
|
||||
getFieldValue('routing_mode') === 'rock' ? (
|
||||
<Alert
|
||||
message="Rock 不需要上游商品 ID"
|
||||
description="这类商品走 Rock 通用黑色库存池。可用数量降到安全水位及以下时,会按「单次自动补货数量」再采购一批,不是把库存补到固定水位。"
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<Divider titlePlacement="start" style={{ margin: '16px 0', fontSize: 13, color: '#64748b' }}>
|
||||
渠道商品映射信息
|
||||
</Divider>
|
||||
@@ -885,6 +945,10 @@ export default function PlatformProducts() {
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user