优化订单履约分流与后台筛选

This commit is contained in:
yml2213
2026-09-02 11:59:38 +08:00
parent 50c526a855
commit de63daf1ac
19 changed files with 1269 additions and 162 deletions
@@ -2,14 +2,20 @@ import { SearchOutlined, ReloadOutlined } from '@ant-design/icons'
import { Button, Card, Form, Input, Select, Space, Table, Typography } from 'antd'
import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
import { useEffect, useMemo } from 'react'
import { useNavigate, useSearchParams } from 'react-router'
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
import PageHeader from '@/components/admin/PageHeader'
import StatusTag from '@/components/admin/StatusTag'
import dayjs from '@/lib/dayjs'
import { fetchAdminOrders } from '@/services/admin'
import type { AdminOrderListItem } from '@/types/admin'
import { adminPayStatusOptions } from '@/utils/admin-options'
import {
adminOrderExecutorOptions,
adminPayStatusOptions,
adminTaskStatusOptions,
} from '@/utils/admin-options'
import {
ADMIN_DEFAULT_PAGE_SIZE,
buildAdminTablePagination,
@@ -18,25 +24,40 @@ import {
import { formatAdminDateTime } from '@/utils/admin-time'
type OrderFilterForm = {
platformOrderId?: string
keyword?: string
executorKey?: string
payStatus?: string
skuCode?: string
taskStatus?: string
dateRange?: unknown
}
export default function AdminOrdersPage() {
const navigate = useNavigate()
const [form] = Form.useForm<OrderFilterForm>()
const [searchParams, setSearchParams] = useSearchParams()
const page = Number(searchParams.get('page') || 1) || 1
const pageSize = resolveAdminPageSize(searchParams.get('pageSize'), ADMIN_DEFAULT_PAGE_SIZE)
const filters = {
platformOrderId: searchParams.get('platformOrderId') || '',
keyword: searchParams.get('keyword') || '',
executorKey: searchParams.get('executorKey') || '',
payStatus: searchParams.get('payStatus') || '',
skuCode: searchParams.get('skuCode') || '',
taskStatus: searchParams.get('taskStatus') || '',
dateFrom: searchParams.get('dateFrom') || '',
dateTo: searchParams.get('dateTo') || '',
}
const queryParams = useMemo(
() => ({ page, pageSize, ...filters }),
[filters.platformOrderId, filters.payStatus, filters.skuCode, page, pageSize],
[
filters.dateFrom,
filters.dateTo,
filters.executorKey,
filters.keyword,
filters.payStatus,
filters.taskStatus,
page,
pageSize,
],
)
const query = useQuery({
queryKey: ['admin-orders', queryParams],
@@ -44,6 +65,27 @@ export default function AdminOrdersPage() {
})
const data = query.data?.data
useEffect(() => {
form.setFieldsValue({
keyword: filters.keyword || undefined,
executorKey: filters.executorKey || undefined,
payStatus: filters.payStatus || undefined,
taskStatus: filters.taskStatus || undefined,
dateRange:
filters.dateFrom && filters.dateTo
? [dayjs(filters.dateFrom), dayjs(filters.dateTo)]
: undefined,
})
}, [
filters.dateFrom,
filters.dateTo,
filters.executorKey,
filters.keyword,
filters.payStatus,
filters.taskStatus,
form,
])
const columns: TableColumnsType<AdminOrderListItem> = [
{
title: '订单信息',
@@ -96,10 +138,24 @@ export default function AdminOrdersPage() {
]
function applyFilters(values: OrderFilterForm) {
setSearchParams(cleanParams({ ...values, page: 1, pageSize }))
const { dateRange, ...restValues } = values
const [dateFrom, dateTo] = Array.isArray(dateRange)
? dateRange.map((item: { format?: (pattern: string) => string }) =>
item?.format ? item.format('YYYY-MM-DD') : '',
)
: ['', '']
setSearchParams(cleanParams({ ...restValues, dateFrom, dateTo, page: 1, pageSize }))
}
function resetFilters() {
form.setFieldsValue({
keyword: undefined,
executorKey: undefined,
payStatus: undefined,
taskStatus: undefined,
dateRange: undefined,
})
setSearchParams(cleanParams({ page: 1, pageSize }))
}
@@ -109,13 +165,25 @@ export default function AdminOrdersPage() {
<Card>
<Form<OrderFilterForm>
form={form}
layout="inline"
initialValues={filters}
onFinish={applyFilters}
className="filter-form"
>
<Form.Item name="platformOrderId">
<Input allowClear placeholder="平台订单号" />
<Form.Item name="keyword">
<Input
allowClear
placeholder="订单号 / 商品标题 / SKU 标题 / 买家 / 店铺"
style={{ width: 320 }}
/>
</Form.Item>
<Form.Item name="executorKey">
<Select
allowClear
placeholder="履约渠道"
options={adminOrderExecutorOptions}
style={{ minWidth: 150 }}
/>
</Form.Item>
<Form.Item name="payStatus">
<Select
@@ -125,8 +193,18 @@ export default function AdminOrdersPage() {
style={{ minWidth: 140 }}
/>
</Form.Item>
<Form.Item name="skuCode">
<Input allowClear placeholder="SKU 标识" />
<Form.Item name="taskStatus">
<Select
allowClear
showSearch
optionFilterProp="label"
placeholder="任务状态"
options={adminTaskStatusOptions}
style={{ minWidth: 170 }}
/>
</Form.Item>
<Form.Item name="dateRange">
<AdminRangePicker />
</Form.Item>
<Form.Item>
<Space>
@@ -21,7 +21,7 @@ import {
} from 'antd'
import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router'
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
@@ -37,7 +37,7 @@ import {
} from '@/services/admin'
import type { AdminTaskActionResponse, AdminTaskListItem } from '@/types/admin'
import { hasAdminRole } from '@/utils/admin-auth'
import { adminTaskStatusOptions } from '@/utils/admin-options'
import { adminOrderExecutorOptions, adminTaskStatusOptions } from '@/utils/admin-options'
import {
ADMIN_DEFAULT_PAGE_SIZE,
buildAdminTablePagination,
@@ -46,11 +46,9 @@ import {
import { formatAdminDateTime } from '@/utils/admin-time'
type TaskFilterForm = {
keyword?: string
executorKey?: string
status?: string
platformOrderId?: string
taskNo?: string
skuCode?: string
roleId?: string
dateRange?: unknown
}
@@ -67,6 +65,7 @@ type TaskListBlocker = {
export default function AdminTasksPage() {
const navigate = useNavigate()
const { message, modal } = App.useApp()
const [form] = Form.useForm<TaskFilterForm>()
const [searchParams, setSearchParams] = useSearchParams()
const [actionLoadingId, setActionLoadingId] = useState<number | null>(null)
const [lastClaimUrl, setLastClaimUrl] = useState('')
@@ -77,11 +76,15 @@ export default function AdminTasksPage() {
const canRebindRole = hasAdminRole('support')
const canCloseTasks = hasAdminRole('support')
const filters = {
keyword:
searchParams.get('keyword') ||
searchParams.get('taskNo') ||
searchParams.get('platformOrderId') ||
searchParams.get('skuCode') ||
searchParams.get('roleId') ||
'',
executorKey: searchParams.get('executorKey') || '',
status: searchParams.get('status') || '',
platformOrderId: searchParams.get('platformOrderId') || '',
taskNo: searchParams.get('taskNo') || '',
skuCode: searchParams.get('skuCode') || '',
roleId: searchParams.get('roleId') || '',
dateFrom: searchParams.get('dateFrom') || '',
dateTo: searchParams.get('dateTo') || '',
}
@@ -91,11 +94,9 @@ export default function AdminTasksPage() {
[
filters.dateFrom,
filters.dateTo,
filters.platformOrderId,
filters.roleId,
filters.skuCode,
filters.executorKey,
filters.keyword,
filters.status,
filters.taskNo,
page,
pageSize,
],
@@ -106,6 +107,18 @@ export default function AdminTasksPage() {
})
const data = query.data?.data
useEffect(() => {
form.setFieldsValue({
keyword: filters.keyword || undefined,
executorKey: filters.executorKey || undefined,
status: filters.status || undefined,
dateRange:
filters.dateFrom && filters.dateTo
? [dayjs(filters.dateFrom), dayjs(filters.dateTo)]
: undefined,
})
}, [filters.dateFrom, filters.dateTo, filters.executorKey, filters.keyword, filters.status, form])
const columns: TableColumnsType<AdminTaskListItem> = [
{
title: '任务 / 订单',
@@ -381,6 +394,12 @@ export default function AdminTasksPage() {
}
function resetFilters() {
form.setFieldsValue({
keyword: undefined,
executorKey: undefined,
status: undefined,
dateRange: undefined,
})
setSearchParams(cleanParams({ page: 1, pageSize }))
}
@@ -390,37 +409,36 @@ export default function AdminTasksPage() {
<Card>
<Form<TaskFilterForm>
form={form}
layout="inline"
initialValues={{
...filters,
dateRange:
filters.dateFrom && filters.dateTo
? [dayjs(filters.dateFrom), dayjs(filters.dateTo)]
: undefined,
}}
onFinish={applyFilters}
className="filter-form"
>
<Form.Item name="keyword">
<Input
allowClear
placeholder="任务号 / 订单号 / 商品标题 / SKU / 角色"
style={{ width: 330 }}
/>
</Form.Item>
<Form.Item name="executorKey">
<Select
allowClear
placeholder="履约渠道"
options={adminOrderExecutorOptions}
style={{ minWidth: 150 }}
/>
</Form.Item>
<Form.Item name="status">
<Select
allowClear
showSearch
optionFilterProp="label"
placeholder="任务状态"
options={adminTaskStatusOptions}
style={{ minWidth: 170 }}
/>
</Form.Item>
<Form.Item name="platformOrderId">
<Input allowClear placeholder="平台订单号" />
</Form.Item>
<Form.Item name="taskNo">
<Input allowClear placeholder="任务号" />
</Form.Item>
<Form.Item name="roleId">
<Input allowClear placeholder="角色 ID" />
</Form.Item>
<Form.Item name="skuCode">
<Input allowClear placeholder="商品名 / SKU" />
</Form.Item>
<Form.Item name="dateRange">
<AdminRangePicker />
</Form.Item>
+13
View File
@@ -6,17 +6,30 @@ export const adminPayStatusOptions = [
{ label: '已退款', value: 'refunded' },
]
export const adminOrderExecutorOptions = [
{ label: '乐玩云', value: 'kuaishou_ct_assisted' },
{ label: '飞飞', value: 'kuaishou_feifei' },
{ label: 'Affiliate Dash', value: 'affiliate_dash' },
{ label: '行业凭证', value: 'kuaishou-industry' },
{ label: '人工履约', value: 'manual_dispatch' },
]
export const adminTaskStatusOptions = [
{ label: '全部', value: '' },
{ label: '待支付', value: 'pending_payment' },
{ label: '已支付', value: 'paid' },
{ label: '已生成链接', value: 'link_generated' },
{ label: '已创建会话', value: 'claimed' },
{ label: '待准备绑定', value: 'pending_binding_prepare' },
{ label: '待客户绑定', value: 'waiting_binding' },
{ label: '已确认角色', value: 'role_confirmed' },
{ label: '兑换中', value: 'redeeming' },
{ label: '待退还号码', value: 'dispatched_pending_return' },
{ label: '已完成', value: 'completed' },
{ label: '已兑换', value: 'redeemed' },
{ label: '待重试', value: 'retry_pending' },
{ label: '人工处理', value: 'manual_review' },
{ label: '失败', value: 'failed' },
{ label: '已过期', value: 'expired' },
{ label: '已关闭', value: 'closed' },
]