feat(admin): 收口人工履约入口并修复履约筛选
This commit is contained in:
@@ -1,343 +0,0 @@
|
||||
/**
|
||||
* 人工履约待办页:客服确认履约。
|
||||
*
|
||||
* 口径(2026-10-24 确认):
|
||||
* * 渠道与消耗积分在成本中心提前配好,客服不选、不填;
|
||||
* * 固定成本 → 点「确认履约」零输入;
|
||||
* * 成本不固定(消耗积分 = 0)→ 只填本次实际成本;
|
||||
* * 确认后自动扣对应平台的积分并写成本快照。
|
||||
*/
|
||||
import { CheckOutlined, ReloadOutlined } from '@ant-design/icons'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import {
|
||||
Alert,
|
||||
App,
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Modal,
|
||||
Space,
|
||||
Statistic,
|
||||
Tag,
|
||||
Typography,
|
||||
} from 'antd'
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import type { TableColumnsType } from 'antd'
|
||||
import { useState } from 'react'
|
||||
|
||||
import PageHeader from '@/components/admin/PageHeader'
|
||||
import { confirmAdminManualFulfillment, fetchAdminManualFulfillmentPending } from '@/services/admin'
|
||||
import type { ManualFulfillmentPendingItem } from '@/types/admin'
|
||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
|
||||
type ConfirmFormValues = {
|
||||
costYuan?: number
|
||||
payeeName?: string
|
||||
note?: string
|
||||
}
|
||||
|
||||
const PLATFORM_TAG_COLORS: Record<string, string> = {
|
||||
nanhang: 'blue',
|
||||
lewan: 'purple',
|
||||
rock: 'cyan',
|
||||
fund_cash: 'orange',
|
||||
}
|
||||
|
||||
export default function AdminManualFulfillmentPage() {
|
||||
const { message } = App.useApp()
|
||||
const queryClient = useQueryClient()
|
||||
const [form] = Form.useForm<ConfirmFormValues>()
|
||||
|
||||
const [status, setStatus] = useState<'pending' | 'fulfilled' | ''>('pending')
|
||||
const [keyword, setKeyword] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||
const [confirming, setConfirming] = useState<ManualFulfillmentPendingItem | null>(null)
|
||||
const [showCostInput, setShowCostInput] = useState(false)
|
||||
|
||||
const listQuery = useQuery({
|
||||
queryKey: ['admin-manual-fulfillment-pending', status, keyword, page, pageSize],
|
||||
queryFn: () =>
|
||||
fetchAdminManualFulfillmentPending({
|
||||
status: status || undefined,
|
||||
keyword: keyword || undefined,
|
||||
page,
|
||||
pageSize,
|
||||
}),
|
||||
})
|
||||
|
||||
const confirmMutation = useMutation({
|
||||
mutationFn: (values: ConfirmFormValues) =>
|
||||
confirmAdminManualFulfillment({
|
||||
orderItemId: confirming?.orderItemId || 0,
|
||||
costFen: values.costYuan === undefined ? undefined : Math.round(values.costYuan * 100),
|
||||
payeeName: values.payeeName || '',
|
||||
note: values.note || '',
|
||||
}),
|
||||
onSuccess: (response) => {
|
||||
const result = response.data
|
||||
message.success(
|
||||
`履约已确认,扣 ${result.creditQuantity} 积分,成本 ¥${(result.costFen / 100).toFixed(2)}`,
|
||||
)
|
||||
setConfirming(null)
|
||||
setShowCostInput(false)
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: ['admin-manual-fulfillment-pending'],
|
||||
})
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin-fund-my'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin-fund-accounts'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin-platform-credit-accounts'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin-platform-credit-entries'] })
|
||||
},
|
||||
onError: (error) => {
|
||||
message.error(error instanceof Error ? error.message : '确认履约失败')
|
||||
},
|
||||
})
|
||||
|
||||
function openConfirm(item: ManualFulfillmentPendingItem) {
|
||||
setConfirming(item)
|
||||
setShowCostInput(item.costFen === null)
|
||||
form.resetFields()
|
||||
}
|
||||
|
||||
const columns: TableColumnsType<ManualFulfillmentPendingItem> = [
|
||||
{
|
||||
title: '商品',
|
||||
key: 'sku',
|
||||
width: 260,
|
||||
render: (_, row) => (
|
||||
<div className="cell-stack">
|
||||
<Typography.Text strong ellipsis={{ tooltip: row.skuName }}>
|
||||
{row.skuName || row.skuCode}
|
||||
</Typography.Text>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{row.internalSku || row.skuCode}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '平台单号',
|
||||
dataIndex: 'platformOrderId',
|
||||
width: 170,
|
||||
render: (value: string) => (
|
||||
<Typography.Text copyable={{ text: value }} style={{ fontSize: 12 }}>
|
||||
{value}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '履约渠道',
|
||||
key: 'platform',
|
||||
width: 110,
|
||||
render: (_, row) => (
|
||||
<Tag color={PLATFORM_TAG_COLORS[row.platformKey] || 'default'}>{row.platformLabel}</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '消耗',
|
||||
key: 'credit',
|
||||
width: 120,
|
||||
render: (_, row) =>
|
||||
row.isFundCash ? (
|
||||
<Typography.Text type="secondary">—</Typography.Text>
|
||||
) : (
|
||||
<Typography.Text>{row.creditQuantity} 积分</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '成本',
|
||||
key: 'cost',
|
||||
width: 120,
|
||||
align: 'right',
|
||||
render: (_, row) =>
|
||||
row.costFen === null ? (
|
||||
<Tag color="orange">待填写</Tag>
|
||||
) : (
|
||||
<Typography.Text strong>¥{(row.costFen / 100).toFixed(2)}</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
key: 'revenue',
|
||||
width: 100,
|
||||
align: 'right',
|
||||
render: (_, row) => `¥${(row.revenueFen / 100).toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '支付时间',
|
||||
dataIndex: 'paidAt',
|
||||
width: 150,
|
||||
render: (value: string) => formatAdminDateTime(value),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 110,
|
||||
fixed: 'right',
|
||||
render: (_, row) =>
|
||||
row.fulfilled ? (
|
||||
<Tag color="green">已履约</Tag>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon={<CheckOutlined />}
|
||||
onClick={() => openConfirm(row)}
|
||||
>
|
||||
确认履约
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
const total = listQuery.data?.data.pagination.total ?? 0
|
||||
|
||||
return (
|
||||
<section>
|
||||
<PageHeader
|
||||
title="人工履约待办"
|
||||
description="渠道与消耗积分已提前配好,确认即扣额度并计入成本。"
|
||||
/>
|
||||
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: 14 }}
|
||||
message="确认履约会从对应平台的积分钱包扣减,并写入成本快照"
|
||||
description="固定成本的商品直接确认即可;成本不固定的商品需要填写本次实际成本。"
|
||||
/>
|
||||
|
||||
<Space wrap style={{ marginBottom: 12 }}>
|
||||
<Button icon={<ReloadOutlined />} onClick={() => void listQuery.refetch()}>
|
||||
刷新
|
||||
</Button>
|
||||
<Button
|
||||
type={status === 'pending' ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
setStatus('pending')
|
||||
setPage(1)
|
||||
}}
|
||||
>
|
||||
待确认
|
||||
</Button>
|
||||
<Button
|
||||
type={status === 'fulfilled' ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
setStatus('fulfilled')
|
||||
setPage(1)
|
||||
}}
|
||||
>
|
||||
已履约
|
||||
</Button>
|
||||
<Button
|
||||
type={status === '' ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
setStatus('')
|
||||
setPage(1)
|
||||
}}
|
||||
>
|
||||
全部
|
||||
</Button>
|
||||
</Space>
|
||||
|
||||
<Card bordered={false}>
|
||||
<PercentTable
|
||||
rowKey="orderItemId"
|
||||
size="small"
|
||||
columns={columns}
|
||||
dataSource={listQuery.data?.data.items || []}
|
||||
loading={listQuery.isLoading}
|
||||
scroll={{ x: 1080 }}
|
||||
pagination={buildAdminTablePagination({
|
||||
page,
|
||||
pageSize,
|
||||
total,
|
||||
onChange: (nextPage, nextPageSize) => {
|
||||
setPage(nextPage)
|
||||
if (nextPageSize !== pageSize) setPageSize(nextPageSize)
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
open={Boolean(confirming)}
|
||||
title="确认履约"
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
confirmLoading={confirmMutation.isPending}
|
||||
onOk={() => {
|
||||
void form.validateFields().then((values) => confirmMutation.mutate(values))
|
||||
}}
|
||||
onCancel={() => {
|
||||
setConfirming(null)
|
||||
setShowCostInput(false)
|
||||
}}
|
||||
destroyOnHidden
|
||||
width={520}
|
||||
>
|
||||
{confirming ? (
|
||||
<Space direction="vertical" size={12} style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Typography.Text type="secondary">商品:</Typography.Text>
|
||||
<Typography.Text strong>{confirming.skuName || confirming.skuCode}</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text type="secondary">内部 SKU:</Typography.Text>
|
||||
<Typography.Text copyable={{ text: confirming.internalSku }}>
|
||||
{confirming.internalSku}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text type="secondary">履约渠道:</Typography.Text>
|
||||
<Tag color={PLATFORM_TAG_COLORS[confirming.platformKey] || 'default'}>
|
||||
{confirming.platformLabel}
|
||||
</Tag>
|
||||
{!confirming.isFundCash ? (
|
||||
<Typography.Text>消耗 {confirming.creditQuantity} 积分</Typography.Text>
|
||||
) : null}
|
||||
</div>
|
||||
{showCostInput ? (
|
||||
<Alert type="warning" showIcon message="该商品成本不固定,请填写本次实际成本" />
|
||||
) : (
|
||||
<Statistic
|
||||
title="本次成本"
|
||||
value={(confirming.costFen || 0) / 100}
|
||||
precision={2}
|
||||
prefix="¥"
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
) : null}
|
||||
|
||||
<Form<ConfirmFormValues> form={form} layout="vertical">
|
||||
{showCostInput ? (
|
||||
<Form.Item
|
||||
name="costYuan"
|
||||
label="实际成本(元)"
|
||||
rules={[{ required: true, message: '请填写实际成本' }]}
|
||||
>
|
||||
<InputNumber
|
||||
min={0.01}
|
||||
precision={2}
|
||||
style={{ width: '100%' }}
|
||||
placeholder="例如 12.50"
|
||||
prefix="¥"
|
||||
/>
|
||||
</Form.Item>
|
||||
) : null}
|
||||
<Form.Item name="payeeName" label="收款方 / 处理人">
|
||||
<Input placeholder="例如:客服小王、上游商家" maxLength={120} />
|
||||
</Form.Item>
|
||||
<Form.Item name="note" label="备注">
|
||||
<Input.TextArea rows={2} maxLength={300} showCount />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
CheckOutlined,
|
||||
CopyOutlined,
|
||||
FileTextOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlayCircleOutlined,
|
||||
RollbackOutlined,
|
||||
@@ -23,19 +23,20 @@ import {
|
||||
Skeleton,
|
||||
Space,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd'
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import type { TableColumnsType } from 'antd'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router'
|
||||
|
||||
import dayjs from '@/lib/dayjs'
|
||||
|
||||
import JsonPreview from '@/components/admin/JsonPreview'
|
||||
import ManualOrderCostModal from '@/components/admin/ManualOrderCostModal'
|
||||
import { ManualFulfillmentConfirmModal } from '@/components/admin/ManualFulfillmentConfirmModal'
|
||||
import PageHeader from '@/components/admin/PageHeader'
|
||||
import StatusTag from '@/components/admin/StatusTag'
|
||||
import {
|
||||
@@ -57,9 +58,8 @@ export default function AdminOrderDetailPage() {
|
||||
const queryClient = useQueryClient()
|
||||
const { message, modal } = App.useApp()
|
||||
const { orderId = '' } = useParams()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const [statusModalVisible, setStatusModalVisible] = useState(false)
|
||||
const [manualCostOpen, setManualCostOpen] = useState(false)
|
||||
const [fulfillOpen, setFulfillOpen] = useState(false)
|
||||
const [costPreviewItemId, setCostPreviewItemId] = useState<number | null>(null)
|
||||
const [refundModalOpen, setRefundModalOpen] = useState(false)
|
||||
const [refundScope, setRefundScope] = useState<'order' | 'item'>('order')
|
||||
@@ -75,21 +75,6 @@ export default function AdminOrderDetailPage() {
|
||||
const [targetStatus, setTargetStatus] = useState<'active' | 'paused' | 'closed'>('active')
|
||||
const [statusReason, setStatusReason] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.get('manualCost') === '1') {
|
||||
setManualCostOpen(true)
|
||||
}
|
||||
}, [searchParams])
|
||||
|
||||
function closeManualCost() {
|
||||
setManualCostOpen(false)
|
||||
if (searchParams.get('manualCost')) {
|
||||
const next = new URLSearchParams(searchParams)
|
||||
next.delete('manualCost')
|
||||
setSearchParams(next, { replace: true })
|
||||
}
|
||||
}
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ['admin-order-detail', orderId],
|
||||
queryFn: () => fetchAdminOrderDetail(orderId),
|
||||
@@ -314,9 +299,19 @@ export default function AdminOrderDetailPage() {
|
||||
退款登记
|
||||
</Button>
|
||||
) : null}
|
||||
<Button icon={<FileTextOutlined />} onClick={() => setManualCostOpen(true)}>
|
||||
人工录单
|
||||
</Button>
|
||||
{Number(detail.order.manualPendingCount || 0) > 0 ? (
|
||||
<Button icon={<CheckOutlined />} onClick={() => setFulfillOpen(true)}>
|
||||
确认履约
|
||||
</Button>
|
||||
) : Number(detail.order.manualUnconfiguredCount || 0) > 0 ? (
|
||||
<Tooltip
|
||||
title={`有 ${detail.order.manualUnconfiguredCount} 个人工商品未配置履约渠道,请先到「商品与成本 → 人工 SKU 配置」补全`}
|
||||
>
|
||||
<Tag color="orange" style={{ margin: 0 }}>
|
||||
待补全履约
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{isAutoClaimOrder ? (
|
||||
<>
|
||||
<Button icon={<CopyOutlined />} onClick={handleCopyH5Link}>
|
||||
@@ -620,18 +615,13 @@ export default function AdminOrderDetailPage() {
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<ManualOrderCostModal
|
||||
open={manualCostOpen}
|
||||
<ManualFulfillmentConfirmModal
|
||||
open={fulfillOpen}
|
||||
orderId={detail.order.orderId}
|
||||
orderNo={detail.order.platformOrderId || String(detail.order.orderId)}
|
||||
items={detail.items.map((item) => ({
|
||||
orderItemId: item.orderItemId,
|
||||
matchSku: item.matchSku,
|
||||
skuName: item.skuName,
|
||||
skuCode: item.skuCode,
|
||||
quantity: item.quantity,
|
||||
}))}
|
||||
onClose={closeManualCost}
|
||||
onClose={() => setFulfillOpen(false)}
|
||||
onConfirmed={() =>
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin-order-detail', orderId] })
|
||||
}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
CopyOutlined,
|
||||
DollarOutlined,
|
||||
EyeOutlined,
|
||||
LinkOutlined,
|
||||
ReloadOutlined,
|
||||
@@ -23,10 +23,11 @@ import {
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import type { TableColumnsType } from 'antd'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useNavigate, useSearchParams } from 'react-router'
|
||||
|
||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||
import { ManualFulfillmentConfirmModal } from '@/components/admin/ManualFulfillmentConfirmModal'
|
||||
import PageHeader from '@/components/admin/PageHeader'
|
||||
import StatusTag from '@/components/admin/StatusTag'
|
||||
import dayjs from '@/lib/dayjs'
|
||||
@@ -38,7 +39,7 @@ import {
|
||||
resolveVoucherStateLabel,
|
||||
} from '@/utils/admin-display'
|
||||
import {
|
||||
adminOrderExecutorOptions,
|
||||
adminOrderFulfillmentModeOptions,
|
||||
adminOrderPlatformSegmentedOptions,
|
||||
adminOrderProviderOptions,
|
||||
adminPayStatusOptions,
|
||||
@@ -54,7 +55,7 @@ import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
type OrderFilterForm = {
|
||||
keyword?: string
|
||||
provider?: string
|
||||
executorKey?: string
|
||||
fulfillmentMode?: string
|
||||
payStatus?: string
|
||||
taskStatus?: string
|
||||
dateRange?: unknown
|
||||
@@ -62,6 +63,8 @@ type OrderFilterForm = {
|
||||
|
||||
export default function AdminOrdersPage() {
|
||||
const navigate = useNavigate()
|
||||
const [fulfillOpen, setFulfillOpen] = useState(false)
|
||||
const [fulfillOrderId, setFulfillOrderId] = useState<number | null>(null)
|
||||
const { message } = App.useApp()
|
||||
const [form] = Form.useForm<OrderFilterForm>()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
@@ -71,7 +74,7 @@ export default function AdminOrdersPage() {
|
||||
const filters = {
|
||||
keyword: searchParams.get('keyword') || '',
|
||||
provider: searchParams.get('provider') || '',
|
||||
executorKey: searchParams.get('executorKey') || '',
|
||||
fulfillmentMode: searchParams.get('fulfillmentMode') || '',
|
||||
payStatus: searchParams.get('payStatus') || '',
|
||||
taskStatus: searchParams.get('taskStatus') || '',
|
||||
dateFrom: searchParams.get('dateFrom') || '',
|
||||
@@ -83,7 +86,7 @@ export default function AdminOrdersPage() {
|
||||
[
|
||||
filters.dateFrom,
|
||||
filters.dateTo,
|
||||
filters.executorKey,
|
||||
filters.fulfillmentMode,
|
||||
filters.keyword,
|
||||
filters.payStatus,
|
||||
filters.provider,
|
||||
@@ -103,7 +106,7 @@ export default function AdminOrdersPage() {
|
||||
form.setFieldsValue({
|
||||
keyword: filters.keyword || undefined,
|
||||
provider: filters.provider || undefined,
|
||||
executorKey: filters.executorKey || undefined,
|
||||
fulfillmentMode: filters.fulfillmentMode || undefined,
|
||||
payStatus: filters.payStatus || undefined,
|
||||
taskStatus: filters.taskStatus || undefined,
|
||||
dateRange:
|
||||
@@ -114,7 +117,7 @@ export default function AdminOrdersPage() {
|
||||
}, [
|
||||
filters.dateFrom,
|
||||
filters.dateTo,
|
||||
filters.executorKey,
|
||||
filters.fulfillmentMode,
|
||||
filters.keyword,
|
||||
filters.payStatus,
|
||||
filters.provider,
|
||||
@@ -328,7 +331,8 @@ export default function AdminOrdersPage() {
|
||||
render: (_, row) => {
|
||||
const orderNo = row.platformOrderId || String(row.orderId)
|
||||
const h5Url = `${window.location.origin}/h5/${encodeURIComponent(orderNo)}`
|
||||
const isManualOrder = Number(row.manualItemCount || 0) > 0
|
||||
const manualPending = Number(row.manualPendingCount || 0)
|
||||
const manualUnconfigured = Number(row.manualUnconfiguredCount || 0)
|
||||
|
||||
return (
|
||||
<Space size={6} wrap>
|
||||
@@ -341,16 +345,27 @@ export default function AdminOrdersPage() {
|
||||
>
|
||||
详情
|
||||
</Button>
|
||||
{isManualOrder ? (
|
||||
<Tooltip title="人工录单:录入这一单的实际人工成本">
|
||||
{manualPending > 0 ? (
|
||||
<Tooltip title="人工履约:确认后扣积分/备用金并写入成本">
|
||||
<Button
|
||||
size="small"
|
||||
icon={<DollarOutlined />}
|
||||
onClick={() => navigate(`/admin/orders/${row.orderId}?manualCost=1`)}
|
||||
icon={<CheckOutlined />}
|
||||
onClick={() => {
|
||||
setFulfillOrderId(row.orderId)
|
||||
setFulfillOpen(true)
|
||||
}}
|
||||
>
|
||||
人工录单
|
||||
确认履约
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : manualUnconfigured > 0 ? (
|
||||
<Tooltip
|
||||
title={`有 ${manualUnconfigured} 个人工商品未配置履约渠道,请先到「商品与成本 → 人工 SKU 配置」补全`}
|
||||
>
|
||||
<Tag color="orange" style={{ margin: 0 }}>
|
||||
待补全履约
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{row.canClaimH5 ? (
|
||||
<Tooltip title="复制自动直充 H5 领取链接">
|
||||
@@ -398,7 +413,7 @@ export default function AdminOrdersPage() {
|
||||
form.setFieldsValue({
|
||||
keyword: undefined,
|
||||
provider: undefined,
|
||||
executorKey: undefined,
|
||||
fulfillmentMode: undefined,
|
||||
payStatus: undefined,
|
||||
taskStatus: undefined,
|
||||
dateRange: undefined,
|
||||
@@ -459,11 +474,11 @@ export default function AdminOrdersPage() {
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="executorKey">
|
||||
<Form.Item name="fulfillmentMode">
|
||||
<Select
|
||||
allowClear
|
||||
placeholder="履约模式"
|
||||
options={adminOrderExecutorOptions}
|
||||
options={adminOrderFulfillmentModeOptions}
|
||||
style={{ minWidth: 130 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -525,6 +540,13 @@ export default function AdminOrdersPage() {
|
||||
})}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<ManualFulfillmentConfirmModal
|
||||
open={fulfillOpen}
|
||||
orderId={fulfillOrderId}
|
||||
onClose={() => setFulfillOpen(false)}
|
||||
onConfirmed={() => void query.refetch()}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user