作废链接和取消订单
This commit is contained in:
@@ -85,6 +85,8 @@ export const merchantApi = {
|
||||
game_account?: string
|
||||
note?: string
|
||||
}) => request.post('/merchant/orders/manual', data).then((r) => r.data.data as CreateManualOrderResult),
|
||||
cancelOrder: (orderNo: string, reason: string) =>
|
||||
request.post(`/merchant/orders/${encodeURIComponent(orderNo)}/cancel`, { reason }).then((r) => r.data.data as { order: FulfillmentOrder; refund_amount: number }),
|
||||
getDeliveryLink: (orderNo: string) =>
|
||||
request.get(`/merchant/orders/${encodeURIComponent(orderNo)}/delivery-link`).then((r) => r.data.data as DeliveryLinkResult),
|
||||
revokeDeliveryLink: (orderNo: string) =>
|
||||
|
||||
@@ -131,7 +131,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
||||
message.success('发货链接已作废')
|
||||
patchDeliveryLinkState(orderNo, { delivery_link_revoked_at: revokedAt })
|
||||
})
|
||||
.catch((e) => message.error(e instanceof Error ? e.message : '作废失败'))
|
||||
.catch((e) => message.error(e instanceof Error ? e.message : '链接作废失败'))
|
||||
}, [patchDeliveryLinkState])
|
||||
|
||||
const restoreDeliveryLink = useCallback((orderNo: string) => {
|
||||
@@ -355,6 +355,12 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
||||
loadOrders(1, orders.size, orderSource, filters).catch((e) => message.error(e instanceof Error ? e.message : '订单加载失败'))
|
||||
}
|
||||
|
||||
const cancelOrder = useCallback(async (orderNo: string, reason: string) => {
|
||||
const result = await merchantApi.cancelOrder(orderNo, reason)
|
||||
message.success(`订单已取消,已退还 ${Number(result.refund_amount || 0)} 积分`)
|
||||
await loadOrders()
|
||||
}, [loadOrders])
|
||||
|
||||
const submitAPIClient = async () => {
|
||||
const values = await apiClientForm.validateFields()
|
||||
try {
|
||||
@@ -510,7 +516,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer
|
||||
<ProductsTab loading={loading} products={products} canManage={canManage} onToggleProduct={openProductToggle} onLoadProducts={loadProducts} />
|
||||
) },
|
||||
{ key: 'orders', label: '发货订单', disabled: !hasFeature('orders'), children: (
|
||||
<OrdersTab loading={loading} orders={orders} orderSource={orderSource} filters={orderFilters} canManage={canOrderManage} onCreateManualOrder={openManualOrderCreate} onOrderSourceChange={changeOrderSource} onFilterChange={changeOrderFilters} onLoadOrders={loadOrders} onCopyLink={copyDeliveryLink} onOpenLink={openDeliveryLink} onRevokeLink={revokeDeliveryLink} onRestoreLink={restoreDeliveryLink} />
|
||||
<OrdersTab loading={loading} orders={orders} orderSource={orderSource} filters={orderFilters} canManage={canOrderManage} onCreateManualOrder={openManualOrderCreate} onOrderSourceChange={changeOrderSource} onFilterChange={changeOrderFilters} onLoadOrders={loadOrders} onCopyLink={copyDeliveryLink} onOpenLink={openDeliveryLink} onRevokeLink={revokeDeliveryLink} onRestoreLink={restoreDeliveryLink} onCancelOrder={cancelOrder} />
|
||||
) },
|
||||
{ key: 'wallet', label: '钱包', disabled: !hasFeature('wallet'), children: (
|
||||
<WalletTab loading={loading} wallet={wallet} canFinance={canFinance} ledger={ledger} form={walletFilterForm} onFilter={handleWalletFilter} onResetFilter={handleWalletFilterReset} onLoadLedger={handleLoadLedger} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, Card, Col, Form, Input, Popconfirm, Row, Select, Space, Table, Tabs, Tag, Typography, message } from 'antd'
|
||||
import { Alert, Button, Card, Col, Form, Input, Modal, Popconfirm, Row, Select, Space, Table, Tabs, Tag, Typography, message } from 'antd'
|
||||
import type { FormInstance } from 'antd'
|
||||
import {
|
||||
ClockCircleOutlined,
|
||||
@@ -183,6 +183,7 @@ export function OrdersTab({
|
||||
onOpenLink,
|
||||
onRevokeLink,
|
||||
onRestoreLink,
|
||||
onCancelOrder,
|
||||
}: {
|
||||
loading: boolean
|
||||
orders: PageResult<FulfillmentOrder>
|
||||
@@ -197,8 +198,12 @@ export function OrdersTab({
|
||||
onOpenLink: (orderNo: string) => void
|
||||
onRevokeLink: (orderNo: string) => void
|
||||
onRestoreLink: (orderNo: string) => void
|
||||
onCancelOrder: (orderNo: string, reason: string) => Promise<void> | void
|
||||
}) {
|
||||
const [keyword, setKeyword] = useState(filters.keyword)
|
||||
const [cancelling, setCancelling] = useState<FulfillmentOrder | null>(null)
|
||||
const [cancelReason, setCancelReason] = useState('')
|
||||
const [cancelSubmitting, setCancelSubmitting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setKeyword(filters.keyword)
|
||||
@@ -206,6 +211,22 @@ export function OrdersTab({
|
||||
|
||||
const submitKeyword = () => onFilterChange({ ...filters, keyword: keyword.trim() })
|
||||
|
||||
const submitCancel = async () => {
|
||||
if (!cancelling) return
|
||||
if (!cancelReason.trim()) {
|
||||
message.warning('请填写取消原因')
|
||||
return
|
||||
}
|
||||
setCancelSubmitting(true)
|
||||
try {
|
||||
await onCancelOrder(cancelling.order_no, cancelReason.trim())
|
||||
setCancelling(null)
|
||||
setCancelReason('')
|
||||
} finally {
|
||||
setCancelSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const orderColumns: ColumnsType<FulfillmentOrder> = [
|
||||
{
|
||||
title: '平台订单号',
|
||||
@@ -237,16 +258,55 @@ export function OrdersTab({
|
||||
{
|
||||
title: '发货链接',
|
||||
key: 'delivery_link',
|
||||
width: 150,
|
||||
render: (_, record) => record.delivery_link_revoked_at ? (
|
||||
<Button type="link" size="small" onClick={() => onRestoreLink(record.order_no)}>取消作废</Button>
|
||||
) : (
|
||||
<Space size={4} wrap>
|
||||
<Button type="link" size="small" onClick={() => onCopyLink(record.order_no)}>复制</Button>
|
||||
<Button type="link" size="small" onClick={() => onOpenLink(record.order_no)}>打开</Button>
|
||||
<Button type="link" danger size="small" onClick={() => onRevokeLink(record.order_no)}>作废</Button>
|
||||
</Space>
|
||||
),
|
||||
width: 160,
|
||||
render: (_, record) => {
|
||||
if (record.order_status === 'cancelled') {
|
||||
return <Typography.Text type="secondary">订单已取消</Typography.Text>
|
||||
}
|
||||
if (record.delivery_link_revoked_at) {
|
||||
return <Button type="link" size="small" onClick={() => onRestoreLink(record.order_no)}>恢复链接</Button>
|
||||
}
|
||||
return (
|
||||
<Space size={4} wrap>
|
||||
<Button type="link" size="small" onClick={() => onCopyLink(record.order_no)}>复制</Button>
|
||||
<Button type="link" size="small" onClick={() => onOpenLink(record.order_no)}>打开</Button>
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
size="small"
|
||||
title="仅作废发货链接,不影响订单状态与积分"
|
||||
onClick={() => onRevokeLink(record.order_no)}
|
||||
>
|
||||
链接作废
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 110,
|
||||
fixed: 'right',
|
||||
render: (_, record) => {
|
||||
if (!canManage) return '-'
|
||||
if (record.order_status === 'paid' || record.order_status === 'ship_failed') {
|
||||
return (
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setCancelling(record)
|
||||
setCancelReason('')
|
||||
}}
|
||||
>
|
||||
取消订单
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
return '-'
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -300,9 +360,38 @@ export function OrdersTab({
|
||||
columns={orderColumns}
|
||||
dataSource={orders.list}
|
||||
tableLayout="fixed"
|
||||
scroll={{ x: 1660 }}
|
||||
scroll={{ x: 1780 }}
|
||||
pagination={pageConfig(orders, onLoadOrders)}
|
||||
/>
|
||||
<Modal
|
||||
title={`取消订单:${cancelling?.order_no || ''}`}
|
||||
open={!!cancelling}
|
||||
confirmLoading={cancelSubmitting}
|
||||
onOk={submitCancel}
|
||||
onCancel={() => {
|
||||
setCancelling(null)
|
||||
setCancelReason('')
|
||||
}}
|
||||
okText="确认取消并退款"
|
||||
okButtonProps={{ danger: true }}
|
||||
destroyOnClose
|
||||
>
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
message="取消后订单将不可再发货"
|
||||
description="已扣积分将全额退还商户钱包,商品库存自动回补;已提交上游发货的失败订单不可取消。"
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
<Input.TextArea
|
||||
rows={3}
|
||||
maxLength={512}
|
||||
showCount
|
||||
value={cancelReason}
|
||||
onChange={(e) => setCancelReason(e.target.value)}
|
||||
placeholder="请填写取消原因(必填)"
|
||||
/>
|
||||
</Modal>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user