优化券码操作类型, 增加手动销毁
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
DeleteOutlined,
|
||||
ReloadOutlined,
|
||||
RollbackOutlined,
|
||||
SearchOutlined,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
approveAdminKuaishouIndustryRefund,
|
||||
checkAdminKuaishouIndustryVoucherAvailable,
|
||||
consumeAdminKuaishouIndustryVoucher,
|
||||
destroyAdminKuaishouIndustryVoucher,
|
||||
disagreeAdminKuaishouIndustryRefund,
|
||||
fetchAdminKuaishouIndustryShops,
|
||||
fetchAdminKuaishouIndustryVouchers,
|
||||
@@ -64,6 +66,7 @@ type IndustryActionScope = 'vouchers' | 'refunds'
|
||||
type IndustryActionKind =
|
||||
| 'check'
|
||||
| 'consume'
|
||||
| 'destroy'
|
||||
| 'reverse'
|
||||
| 'resend'
|
||||
| 'refund-list'
|
||||
@@ -107,8 +110,6 @@ type RefundListState = {
|
||||
negotiateStatus: string
|
||||
}
|
||||
|
||||
const DEFAULT_ETICKET_TYPE = 'DINING_OPEN_TICKET'
|
||||
|
||||
export default function AdminKuaishouIndustryPage() {
|
||||
const isSupportOnly = getAdminRole() === 'support'
|
||||
const canManageRefund = hasAdminRole('operator')
|
||||
@@ -130,8 +131,9 @@ export default function AdminKuaishouIndustryPage() {
|
||||
pageSize: 50,
|
||||
})
|
||||
const [toolForm, setToolForm] = useState<AdminKuaishouIndustryVoucherToolPayload>({
|
||||
eticketType: DEFAULT_ETICKET_TYPE,
|
||||
eticketType: '',
|
||||
consumeType: 'consume',
|
||||
reason: 'SYS_ADMIN_DESTROY',
|
||||
})
|
||||
const [refundDateRange, setRefundDateRange] = useState<DateRangeValue>(() => [
|
||||
dayjs().subtract(1, 'day'),
|
||||
@@ -255,13 +257,20 @@ export default function AdminKuaishouIndustryPage() {
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
width: 118,
|
||||
width: 148,
|
||||
render: (_, row) => (
|
||||
<div className="cell-stack">
|
||||
<Tag color={getVoucherStatusColor(row.status)}>{getVoucherStatusLabel(row.status)}</Tag>
|
||||
<Tag color={row.sendCallbackStatus === 'success' ? 'green' : 'orange'}>
|
||||
发码:{row.sendCallbackStatus || '-'}
|
||||
</Tag>
|
||||
{row.eticketType ? (
|
||||
<Typography.Text type="secondary" ellipsis={{ tooltip: row.eticketType }} className="muted">
|
||||
{row.eticketType}
|
||||
</Typography.Text>
|
||||
) : (
|
||||
<span className="muted">类型未知</span>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
@@ -425,7 +434,9 @@ export default function AdminKuaishouIndustryPage() {
|
||||
orderId: row.oid,
|
||||
taskId: row.taskId || '',
|
||||
voucherCode: row.voucherCode,
|
||||
eticketType: row.eticketType || current.eticketType || '',
|
||||
serialNum: row.consumeSerialNum || current.serialNum,
|
||||
reason: current.reason || 'SYS_ADMIN_DESTROY',
|
||||
}))
|
||||
showSuccess('已填入券码操作区')
|
||||
}
|
||||
@@ -440,7 +451,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
await runOpenApiAction('reverse', '电子凭证冲正回调', 'reverse', () =>
|
||||
reverseAdminKuaishouIndustryVoucher({
|
||||
...buildVoucherToolPayload(),
|
||||
reason: toolForm.reason || '后台手动冲正',
|
||||
reason: '后台手动冲正',
|
||||
}),
|
||||
)
|
||||
await loadVouchers()
|
||||
@@ -484,7 +495,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
orderId: row.oid,
|
||||
taskId: row.taskId || '',
|
||||
voucherCode: row.voucherCode,
|
||||
eticketType: DEFAULT_ETICKET_TYPE,
|
||||
eticketType: row.eticketType || undefined,
|
||||
consumeType: 'consume',
|
||||
serialNum: row.consumeSerialNum || undefined,
|
||||
etickets: [{ id: row.voucherCode, code: row.voucherCode, num: 1 }],
|
||||
@@ -540,6 +551,36 @@ export default function AdminKuaishouIndustryPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function runDestroy() {
|
||||
setActionLoading('destroy')
|
||||
try {
|
||||
const response = await destroyAdminKuaishouIndustryVoucher({
|
||||
...buildVoucherToolPayload(),
|
||||
reason: toolForm.reason || 'SYS_ADMIN_DESTROY',
|
||||
})
|
||||
publishActionResult(
|
||||
buildIndustryActionResultView('destroy', '手动销毁', response.data),
|
||||
)
|
||||
showSuccess(
|
||||
response.data.alreadyDestroyed
|
||||
? `券码已是销毁状态,销毁回调已重试(${response.data.reason || 'SYS_ADMIN_DESTROY'})`
|
||||
: `券码已销毁(${response.data.reason || 'SYS_ADMIN_DESTROY'})`,
|
||||
)
|
||||
await loadVouchers()
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '手动销毁失败'
|
||||
publishActionResult(
|
||||
buildIndustryActionResultView('destroy', '手动销毁', {
|
||||
success: false,
|
||||
error: message,
|
||||
}),
|
||||
)
|
||||
showError(message)
|
||||
} finally {
|
||||
setActionLoading('')
|
||||
}
|
||||
}
|
||||
|
||||
async function runRefundList() {
|
||||
const [begin, end] = refundDateRange || []
|
||||
const sellerId = resolveRefundSellerId(refundListForm.sellerId)
|
||||
@@ -888,7 +929,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
onChange={(event) => updateToolForm({ voucherCode: event.target.value })}
|
||||
/>
|
||||
<Input
|
||||
placeholder="电子凭证类型"
|
||||
placeholder="电子凭证类型(选中券码自动填入)"
|
||||
value={toolForm.eticketType}
|
||||
onChange={(event) => updateToolForm({ eticketType: event.target.value })}
|
||||
/>
|
||||
@@ -902,10 +943,18 @@ export default function AdminKuaishouIndustryPage() {
|
||||
value={toolForm.consumeType}
|
||||
onChange={(event) => updateToolForm({ consumeType: event.target.value })}
|
||||
/>
|
||||
<Input
|
||||
placeholder="冲正原因"
|
||||
value={toolForm.reason}
|
||||
onChange={(event) => updateToolForm({ reason: event.target.value })}
|
||||
<Select
|
||||
allowClear
|
||||
placeholder="销毁/冲正原因"
|
||||
value={toolForm.reason || undefined}
|
||||
onChange={(value) => updateToolForm({ reason: value || '' })}
|
||||
options={[
|
||||
{ label: 'SYS_ADMIN_DESTROY(后台作废)', value: 'SYS_ADMIN_DESTROY' },
|
||||
{ label: 'SUPPLY_DESTROY(供应商作废)', value: 'SUPPLY_DESTROY' },
|
||||
{ label: 'USER_APPLY_REFUND(用户退款)', value: 'USER_APPLY_REFUND' },
|
||||
{ label: 'ETICKET_EXPIRED(凭证过期)', value: 'ETICKET_EXPIRED' },
|
||||
]}
|
||||
style={{ minWidth: 220 }}
|
||||
/>
|
||||
<Input
|
||||
placeholder="门店名称"
|
||||
@@ -942,6 +991,23 @@ export default function AdminKuaishouIndustryPage() {
|
||||
>
|
||||
冲正
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确认销毁该券码?"
|
||||
description="将向快手发起销毁回调,并关闭关联任务。已销毁券会重试回调。"
|
||||
okText="销毁"
|
||||
cancelText="取消"
|
||||
onConfirm={() => runDestroy()}
|
||||
>
|
||||
<Button
|
||||
danger
|
||||
type="primary"
|
||||
icon={<DeleteOutlined />}
|
||||
loading={actionLoading === 'destroy'}
|
||||
disabled={!canManageRefund}
|
||||
>
|
||||
手动销毁
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button
|
||||
icon={<SendOutlined />}
|
||||
loading={actionLoading === 'resend'}
|
||||
@@ -1416,19 +1482,44 @@ function buildIndustryActionResultView(
|
||||
}
|
||||
|
||||
if (kind === 'check') {
|
||||
const etickets = extractAvailableEtickets(responseData)
|
||||
pushHighlight(highlights, '可核销券数', String(etickets.length || 0))
|
||||
const etickets = extractAvailableEtickets(response)
|
||||
pushHighlight(highlights, '返回券数', String(etickets.length || 0))
|
||||
const resolvedType = pickFirstString([
|
||||
record.eticketType,
|
||||
voucher?.eticketType,
|
||||
asRecord(openApi.request)?.eticketType,
|
||||
asRecord(asRecord(openApi.request)?.param)?.eticketType,
|
||||
])
|
||||
if (resolvedType) {
|
||||
pushHighlight(highlights, '请求类型', resolvedType)
|
||||
}
|
||||
if (etickets[0]) {
|
||||
pushHighlight(
|
||||
highlights,
|
||||
'首张券码',
|
||||
pickFirstString([etickets[0].code, etickets[0].id]) || '-',
|
||||
)
|
||||
pushHighlight(highlights, '首张数量', String(etickets[0].num || 1))
|
||||
pushHighlight(
|
||||
highlights,
|
||||
'展示状态',
|
||||
pickFirstString([etickets[0].displayStatus, etickets[0].status]) || '-',
|
||||
)
|
||||
pushHighlight(
|
||||
highlights,
|
||||
'平台类型',
|
||||
pickFirstString([etickets[0].eticketType]) || '-',
|
||||
)
|
||||
pushHighlight(highlights, '剩余数量', String(etickets[0].leftNum ?? etickets[0].num ?? 1))
|
||||
}
|
||||
}
|
||||
|
||||
if (kind === 'consume' || kind === 'reverse' || kind === 'resend' || voucher) {
|
||||
if (
|
||||
kind === 'consume' ||
|
||||
kind === 'destroy' ||
|
||||
kind === 'reverse' ||
|
||||
kind === 'resend' ||
|
||||
voucher
|
||||
) {
|
||||
if (voucher) {
|
||||
pushHighlight(highlights, '券码', String(voucher.voucherCode || '-'))
|
||||
pushHighlight(
|
||||
@@ -1436,6 +1527,15 @@ function buildIndustryActionResultView(
|
||||
'券状态',
|
||||
getVoucherStatusLabel(String(voucher.status || '')),
|
||||
)
|
||||
if (voucher.eticketType) {
|
||||
pushHighlight(highlights, '凭证类型', String(voucher.eticketType))
|
||||
}
|
||||
if (kind === 'destroy' && record.reason) {
|
||||
pushHighlight(highlights, '销毁原因', String(record.reason))
|
||||
}
|
||||
if (kind === 'destroy' && typeof record.alreadyDestroyed === 'boolean') {
|
||||
pushHighlight(highlights, '已是销毁态', record.alreadyDestroyed ? '是(重试回调)' : '否')
|
||||
}
|
||||
if (voucher.consumeSerialNum) {
|
||||
pushHighlight(highlights, '核销序列号', String(voucher.consumeSerialNum))
|
||||
}
|
||||
@@ -1520,7 +1620,7 @@ function buildActionSummary(
|
||||
|
||||
if (kind === 'check') {
|
||||
return success
|
||||
? context.platformMessage || '平台返回券码有效,可继续核销。'
|
||||
? context.platformMessage || '检查成功,请结合展示状态(如 frozen)判断是否可核销。'
|
||||
: context.platformMessage || '检查失败,请核对卖家、券码与电子凭证类型。'
|
||||
}
|
||||
|
||||
@@ -1530,6 +1630,12 @@ function buildActionSummary(
|
||||
: context.platformMessage || '核销失败。'
|
||||
}
|
||||
|
||||
if (kind === 'destroy') {
|
||||
return success
|
||||
? `销毁成功${context.voucherStatus ? `,券状态:${context.voucherStatus}` : ''}。`
|
||||
: context.platformMessage || '销毁失败。'
|
||||
}
|
||||
|
||||
if (kind === 'reverse') {
|
||||
return success
|
||||
? `冲正成功${context.voucherStatus ? `,券状态已回写为 ${context.voucherStatus}` : ''}。`
|
||||
@@ -1575,7 +1681,7 @@ function resolveActionSuccess(
|
||||
if (typeof record.success === 'boolean') {
|
||||
return record.success
|
||||
}
|
||||
if (kind === 'consume') {
|
||||
if (kind === 'consume' || kind === 'destroy') {
|
||||
return Boolean(record.voucher)
|
||||
}
|
||||
return openApi.success
|
||||
|
||||
Reference in New Issue
Block a user