feat(consignment): 自动匹配改为进入待抢单前一次性匹配
1) 配置改为开启自动匹配 + 匹配订单生效时间,移除内部匹配等待与定时轮询;2) 所有进入待抢单的路径统一先自动匹配一次,未命中进大厅;3) 手动匹配仅允许待抢单;4) 新增迁移 160 回填配置并迁移存量 internal_matching。
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
App,
|
||||
Button,
|
||||
Card,
|
||||
DatePicker,
|
||||
Empty,
|
||||
Form,
|
||||
Input,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd'
|
||||
import { useEffect, useMemo, useState, type CSSProperties } from 'react'
|
||||
import dayjs, { type Dayjs } from 'dayjs'
|
||||
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import ConsignmentTemplateCopyModal, {
|
||||
@@ -93,11 +95,11 @@ type ConfigFormValues = {
|
||||
serviceFee: { enabled: boolean; mode: 'percent' | 'fixed'; percent: number; amountYuan: number }
|
||||
inventoryLimit: { enabled: boolean; maxActiveQuantity: number }
|
||||
matching: {
|
||||
mode: 'off' | 'manual' | 'auto'
|
||||
autoMatchEnabled: boolean
|
||||
exactOnly: boolean
|
||||
preferLowReward: boolean
|
||||
orderEffectiveFrom: Dayjs
|
||||
}
|
||||
internalMatch: { delayMinutes: number }
|
||||
timeout: {
|
||||
hours: number
|
||||
policy: 'reopen' | 'cancel_release' | 'cancel_deduct' | 'rematch_release' | 'rematch_deduct'
|
||||
@@ -208,19 +210,10 @@ function toFormValues(profile: ConsignmentProfile): ConfigFormValues {
|
||||
},
|
||||
inventoryLimit: { ...config.inventoryLimit },
|
||||
matching: {
|
||||
mode: config.matching.mode || 'off',
|
||||
autoMatchEnabled: Boolean(config.matching.autoMatchEnabled),
|
||||
exactOnly: config.matching.exactOnly,
|
||||
preferLowReward: config.matching.preferLowReward,
|
||||
},
|
||||
internalMatch: {
|
||||
// 内部等待只属于手动匹配;非手动模式切回手动时给默认 30 分钟。
|
||||
// 兼容旧配置/旧缓存缺少 internalMatch 的情况,不能直接读嵌套字段。
|
||||
delayMinutes:
|
||||
config.matching.mode === 'manual'
|
||||
? Number(config.internalMatch?.delayMinutes || 0)
|
||||
: Number(config.internalMatch?.delayMinutes ?? 0) > 0
|
||||
? Number(config.internalMatch?.delayMinutes)
|
||||
: 30,
|
||||
orderEffectiveFrom: dayjs(config.matching.orderEffectiveFrom || undefined),
|
||||
},
|
||||
timeout: {
|
||||
hours: Math.max(0, Number(config.timeout.minutes ?? 30) / 60),
|
||||
@@ -257,11 +250,11 @@ function emptyFormValues(): ConfigFormValues {
|
||||
serviceFee: { enabled: false, mode: 'percent', percent: 0, amountYuan: 0 },
|
||||
inventoryLimit: { enabled: false, maxActiveQuantity: 0 },
|
||||
matching: {
|
||||
mode: 'off',
|
||||
autoMatchEnabled: false,
|
||||
exactOnly: true,
|
||||
preferLowReward: true,
|
||||
orderEffectiveFrom: dayjs(),
|
||||
},
|
||||
internalMatch: { delayMinutes: 30 },
|
||||
timeout: { hours: 0.5, policy: 'reopen' },
|
||||
priceDrop: { enabled: true, hours: 24, mode: 'percent', value: 10 },
|
||||
}
|
||||
@@ -338,14 +331,11 @@ function buildPayload(
|
||||
: 0,
|
||||
},
|
||||
matching: {
|
||||
mode: values.matching.mode,
|
||||
autoMatchEnabled: values.matching.autoMatchEnabled,
|
||||
exactOnly: values.matching.exactOnly,
|
||||
preferLowReward: values.matching.preferLowReward,
|
||||
},
|
||||
internalMatch: {
|
||||
// 内部等待只属于手动匹配:关闭匹配不再等待;自动匹配不使用等待窗口。
|
||||
delayMinutes:
|
||||
values.matching.mode === 'off' ? 0 : Number(values.internalMatch?.delayMinutes || 0),
|
||||
orderEffectiveFrom:
|
||||
values.matching.orderEffectiveFrom?.toISOString() || new Date().toISOString(),
|
||||
},
|
||||
timeout: {
|
||||
minutes: Math.max(0, Math.round(Number(values.timeout.hours || 0) * 60)),
|
||||
@@ -1036,7 +1026,7 @@ export default function ConsignmentConfigPanel() {
|
||||
const serviceFeeEnabled = Form.useWatch(['serviceFee', 'enabled'], form)
|
||||
const serviceFeeMode = Form.useWatch(['serviceFee', 'mode'], form)
|
||||
const inventoryLimitEnabled = Form.useWatch(['inventoryLimit', 'enabled'], form)
|
||||
const matchingMode = Form.useWatch(['matching', 'mode'], form)
|
||||
const autoMatchEnabled = Form.useWatch(['matching', 'autoMatchEnabled'], form)
|
||||
const priceDropEnabled = Form.useWatch(['priceDrop', 'enabled'], form)
|
||||
const priceDropMode = Form.useWatch(['priceDrop', 'mode'], form)
|
||||
const headerStatus: ProfileStatusInfo = selectedProfile
|
||||
@@ -1923,25 +1913,28 @@ export default function ConsignmentConfigPanel() {
|
||||
<ConsignmentSectionTitle
|
||||
index="08"
|
||||
title="匹配设置"
|
||||
description="匹配模式决定新单如何匹配库存;内部等待仅手动匹配使用"
|
||||
description="开启后订单进入待抢单前自动匹配一次;关闭时维持人工匹配"
|
||||
/>
|
||||
</div>
|
||||
<div style={gridStyle}>
|
||||
<Form.Item
|
||||
label="匹配模式"
|
||||
name={['matching', 'mode']}
|
||||
label="开启自动匹配"
|
||||
name={['matching', 'autoMatchEnabled']}
|
||||
valuePropName="checked"
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{ value: 'off', label: '关闭自动匹配(仍可人工指定)' },
|
||||
{ value: 'manual', label: '手动匹配' },
|
||||
{ value: 'auto', label: '自动匹配' },
|
||||
]}
|
||||
/>
|
||||
<Switch checkedChildren="开启" unCheckedChildren="关闭" />
|
||||
</Form.Item>
|
||||
{matchingMode !== 'off' ? (
|
||||
{autoMatchEnabled ? (
|
||||
<>
|
||||
<Form.Item
|
||||
label="匹配订单生效时间"
|
||||
name={['matching', 'orderEffectiveFrom']}
|
||||
extra="只自动匹配该时间之后创建的订单"
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<DatePicker showTime style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="仅精确匹配"
|
||||
name={['matching', 'exactOnly']}
|
||||
@@ -1951,45 +1944,30 @@ export default function ConsignmentConfigPanel() {
|
||||
<Switch checkedChildren="仅精确" unCheckedChildren="允许高配" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="低价订单优先"
|
||||
label="低价库存优先"
|
||||
name={['matching', 'preferLowReward']}
|
||||
valuePropName="checked"
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Switch checkedChildren="优先" unCheckedChildren="不优先" />
|
||||
</Form.Item>
|
||||
{matchingMode === 'manual' ? (
|
||||
<Form.Item
|
||||
label="手动匹配等待(分钟)"
|
||||
name={['internalMatch', 'delayMinutes']}
|
||||
extra="仅手动匹配生效:工单在内部池等待运营挑库存"
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<InputNumber
|
||||
min={0}
|
||||
precision={0}
|
||||
style={{ width: '100%' }}
|
||||
addonAfter="分钟"
|
||||
/>
|
||||
</Form.Item>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
{matchingMode === 'off' ? (
|
||||
{!autoMatchEnabled ? (
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
style={{ marginTop: 12 }}
|
||||
message="关闭自动匹配后:新单直接进入接单大厅,不等待内部库存、也不会自动匹配;运营仍可在后台手动指定寄卖库存。"
|
||||
message="关闭自动匹配后:订单直接进入待抢单,不等待内部库存、也不会自动匹配;运营仍可在后台对待抢单手动指定寄卖库存。"
|
||||
/>
|
||||
) : null}
|
||||
{matchingMode === 'auto' ? (
|
||||
{autoMatchEnabled ? (
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginTop: 12 }}
|
||||
message="自动匹配:发布/补资料时立即匹配,未命中直接进大厅,不使用内部等待窗口。"
|
||||
message="开启自动匹配后:订单进入待抢单前自动匹配一次,命中直接进行中,未命中才进大厅;不再后台定时补配,且只匹配生效时间之后创建的订单。"
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user