feat(fulfillment): 增加统一渠道配置搜索与筛选

This commit is contained in:
yml2213
2026-11-03 14:32:44 +08:00
parent bcf5eb09ec
commit eeb9fada63
5 changed files with 154 additions and 14 deletions
@@ -10,6 +10,7 @@ import {
DeleteOutlined,
PlusOutlined,
ReloadOutlined,
SearchOutlined,
ThunderboltOutlined,
} from '@ant-design/icons'
import {
@@ -25,6 +26,7 @@ import {
Switch,
Tabs,
Tag,
Tooltip,
Typography,
message,
} from 'antd'
@@ -77,6 +79,16 @@ const CHANNEL_SOURCE_LABEL: Record<string, string> = {
backfill: '历史回填',
}
const CHANNEL_SOURCE_FILTER_OPTIONS = [
...Object.entries(CHANNEL_SOURCE_LABEL).map(([value, label]) => ({ value, label })),
{ value: 'rule', label: '规则迁移' },
]
const ENABLED_FILTER_OPTIONS = [
{ value: 'true', label: '启用' },
{ value: 'false', label: '停用' },
]
const MATCH_KEY_OPTIONS = [{ value: 'internal_sku', label: '内部 SKU' }]
const INTERNAL_SKU_MAPPING_TYPES: Array<{
@@ -509,13 +521,34 @@ function RulesPanel() {
const queryClient = useQueryClient()
const [open, setOpen] = useState(false)
const [selectedRuleIds, setSelectedRuleIds] = useState<number[]>([])
const [keyword, setKeyword] = useState('')
const [channelFilter, setChannelFilter] = useState('')
const [sourceFilter, setSourceFilter] = useState('')
const [enabledFilter, setEnabledFilter] = useState('')
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
const [form] = Form.useForm()
const hasActiveFilters = Boolean(keyword || channelFilter || sourceFilter || enabledFilter)
const query = useQuery({
queryKey: ['fulfillment-rules', page, pageSize],
queryFn: () => fetchChannelRules({ page, pageSize }),
queryKey: [
'fulfillment-rules',
keyword,
channelFilter,
sourceFilter,
enabledFilter,
page,
pageSize,
],
queryFn: () =>
fetchChannelRules({
keyword,
channel: channelFilter,
source: sourceFilter,
...(enabledFilter ? { enabled: enabledFilter === 'true' } : {}),
page,
pageSize,
}),
})
const ruleCount = query.data?.data?.total || 0
@@ -549,6 +582,15 @@ function RulesPanel() {
onError: (error) => message.error(error instanceof Error ? error.message : '删除规则失败'),
})
function resetFilters() {
setKeyword('')
setChannelFilter('')
setSourceFilter('')
setEnabledFilter('')
setPage(1)
setSelectedRuleIds([])
}
function confirmDeleteRules(ids: number[]) {
if (ids.length === 0) return
Modal.confirm({
@@ -603,17 +645,26 @@ function RulesPanel() {
{
title: '操作',
width: 100,
render: (_: unknown, row: ChannelRule) => (
<Button
danger
size="small"
loading={deleteMutation.isPending}
disabled={!canDeleteChannelRule(row)}
onClick={() => confirmDeleteRules([row.id])}
>
删除
</Button>
),
render: (_: unknown, row: ChannelRule) => {
const button = (
<Button
danger
size="small"
loading={deleteMutation.isPending}
disabled={!canDeleteChannelRule(row)}
onClick={() => confirmDeleteRules([row.id])}
>
删除
</Button>
)
return canDeleteChannelRule(row) ? (
button
) : (
<Tooltip title="系统生成或由来源配置维护,不能在统一渠道页直接删除;配置有误时请新增同 SKU 的正确规则覆盖。">
<span>{button}</span>
</Tooltip>
)
},
},
]
@@ -643,7 +694,62 @@ function RulesPanel() {
<Typography.Paragraph type="secondary">
配置按内部 SKU 全局生效,会同时影响所有平台和店铺。每条内部 SKU 只能有一个主渠道;
其他渠道请设置 90 以上优先级作为兜底。接单平台的具体模板由统一配置中的 workRuleKey 控制。
来源为商品能力迁移、人工配置、卡券或历史回填的系统规则受保护,配置有误时请新增同 SKU
的正确规则覆盖。
</Typography.Paragraph>
<Space wrap style={{ marginBottom: 12 }}>
<Input
allowClear
prefix={<SearchOutlined />}
placeholder="搜索内部 SKU、载体参数或备注"
value={keyword}
onChange={(event) => {
setKeyword(event.target.value)
setPage(1)
setSelectedRuleIds([])
}}
style={{ width: 280 }}
/>
<Select
allowClear
placeholder="全部渠道"
value={channelFilter || undefined}
onChange={(value) => {
setChannelFilter(value || '')
setPage(1)
setSelectedRuleIds([])
}}
options={CHANNEL_OPTIONS}
style={{ width: 160 }}
/>
<Select
allowClear
placeholder="全部来源"
value={sourceFilter || undefined}
onChange={(value) => {
setSourceFilter(value || '')
setPage(1)
setSelectedRuleIds([])
}}
options={CHANNEL_SOURCE_FILTER_OPTIONS}
style={{ width: 160 }}
/>
<Select
allowClear
placeholder="全部状态"
value={enabledFilter || undefined}
onChange={(value) => {
setEnabledFilter(value || '')
setPage(1)
setSelectedRuleIds([])
}}
options={ENABLED_FILTER_OPTIONS}
style={{ width: 120 }}
/>
<Button disabled={!hasActiveFilters} onClick={resetFilters}>
重置
</Button>
</Space>
<PercentTable
rowKey="id"
size="small"
@@ -165,7 +165,14 @@ export function switchChannelForItems(payload: {
}
export function fetchChannelRules(
params: { channel?: string; page?: number; pageSize?: number } = {},
params: {
channel?: string
source?: string
keyword?: string
enabled?: boolean
page?: number
pageSize?: number
} = {},
) {
return apiGet<ChannelRuleListResult>('/api/v1/admin/fulfillment/rules', params)
}