feat(kuaishou): 增加历史电子券补发并核销

This commit is contained in:
yml2213
2026-11-06 10:38:26 +08:00
parent 1bf1280877
commit 398eafa911
10 changed files with 607 additions and 1 deletions
@@ -6,15 +6,18 @@ import {
SearchOutlined,
SendOutlined,
SyncOutlined,
ThunderboltOutlined,
} from '@ant-design/icons'
import {
Alert,
Button,
Card,
Checkbox,
Collapse,
Descriptions,
Input,
InputNumber,
Modal,
Popconfirm,
Select,
Space,
@@ -39,6 +42,7 @@ import {
fetchAdminKuaishouIndustryShops,
fetchAdminKuaishouIndustryVouchers,
listAdminKuaishouIndustryRefunds,
reissueAndConsumeAdminKuaishouIndustryVoucher,
resendAdminKuaishouIndustryVoucherCode,
reverseAdminKuaishouIndustryVoucher,
} from '@/services/admin'
@@ -69,6 +73,7 @@ type IndustryActionKind =
| 'destroy'
| 'reverse'
| 'resend'
| 'reissue-consume'
| 'refund-list'
| 'refund-approve'
| 'refund-disagree'
@@ -120,6 +125,11 @@ export default function AdminKuaishouIndustryPage() {
const [actionLoading, setActionLoading] = useState('')
const [consumingVoucherId, setConsumingVoucherId] = useState<number | null>(null)
const [reversingVoucherId, setReversingVoucherId] = useState<number | null>(null)
const [reissueConsumeOpen, setReissueConsumeOpen] = useState(false)
const [reissueConsumeMinutes, setReissueConsumeMinutes] = useState<number>(10)
const [reissueConsumeReason, setReissueConsumeReason] =
useState('历史发码失败补偿,补发后立即核销')
const [reissueConsumeConfirmed, setReissueConsumeConfirmed] = useState(false)
const [vouchers, setVouchers] = useState<AdminKuaishouIndustryVoucher[]>([])
const [selectedVoucher, setSelectedVoucher] = useState<AdminKuaishouIndustryVoucher | null>(null)
const [voucherTotal, setVoucherTotal] = useState(0)
@@ -646,6 +656,64 @@ export default function AdminKuaishouIndustryPage() {
}
}
function openReissueConsumeModal() {
if (!selectedVoucher && !String(toolForm.voucherCode || '').trim()) {
showError('请先选择或填写本地券码')
return
}
if (selectedVoucher) {
const sendSucceeded = selectedVoucher.sendCallbackStatus === 'success'
const stillValid = Number(selectedVoucher.validEndTime || 0) > Date.now()
if (selectedVoucher.status !== 'UNUSED') {
showError('仅未使用电子凭证可以补发并核销')
return
}
if (sendSucceeded && stillValid) {
showError('该券已发码成功且仍在有效期,请直接执行手动核销')
return
}
}
setReissueConsumeConfirmed(false)
setReissueConsumeOpen(true)
}
async function runReissueConsume() {
if (!reissueConsumeConfirmed) {
showError('请先确认已核实订单仍需履约')
return
}
setActionLoading('reissue-consume')
try {
const response = await reissueAndConsumeAdminKuaishouIndustryVoucher({
...buildVoucherToolPayload(),
validMinutes: reissueConsumeMinutes,
reason: reissueConsumeReason,
})
publishActionResult(
buildIndustryActionResultView('reissue-consume', '历史券补发并核销', response.data),
)
if (response.data.success) {
showSuccess('原券码已同步到快手并完成核销')
setReissueConsumeOpen(false)
} else {
showError(response.data.error || '历史券补发并核销失败')
}
await loadVouchers()
} catch (error) {
const message = error instanceof Error ? error.message : '历史券补发并核销失败'
publishActionResult(
buildIndustryActionResultView('reissue-consume', '历史券补发并核销', {
success: false,
error: message,
}),
)
showError(message)
} finally {
setActionLoading('')
}
}
async function runDestroy() {
setActionLoading('destroy')
try {
@@ -870,6 +938,98 @@ export default function AdminKuaishouIndustryPage() {
onChange={(key) => setActiveTab(key as IndustryTab)}
items={tabItems}
/>
<Modal
title="历史券补发并核销"
open={reissueConsumeOpen}
okText="补发并核销"
cancelText="取消"
confirmLoading={actionLoading === 'reissue-consume'}
okButtonProps={{
disabled:
!reissueConsumeConfirmed ||
!String(reissueConsumeReason || '').trim() ||
reissueConsumeMinutes < 1 ||
reissueConsumeMinutes > 60,
}}
onOk={runReissueConsume}
onCancel={() => setReissueConsumeOpen(false)}
destroyOnHidden
>
<Space direction="vertical" size={16} className="full-width">
<Alert
type="warning"
showIcon
message="该操作会重发原券码并立即核销"
description="仅用于已确认订单仍需履约、但历史发码失败或凭证已过期的补偿场景。操作会先临时延长本地券有效期,发码成功后立即核销。"
/>
<Descriptions
size="small"
bordered
column={1}
items={[
{
key: 'voucherCode',
label: '本地券码',
children:
selectedVoucher?.voucherCode || String(toolForm.voucherCode || '').trim() || '-',
},
{
key: 'oid',
label: '平台订单',
children:
selectedVoucher?.oid ||
String(toolForm.oid || toolForm.orderId || '').trim() ||
'-',
},
{
key: 'validEndTime',
label: '原有效期至',
children: selectedVoucher
? formatAdminDateTime(
new Date(Number(selectedVoucher.validEndTime || 0)).toISOString(),
)
: '-',
},
{
key: 'sendError',
label: '最近发码错误',
children: selectedVoucher?.sendCallbackLastError || '-',
},
]}
/>
<label className="kuaishou-industry-tool-field">
<span>临时有效期(分钟)</span>
<InputNumber
min={1}
max={60}
precision={0}
value={reissueConsumeMinutes}
onChange={(value) => setReissueConsumeMinutes(Number(value || 10))}
style={{ width: '100%' }}
/>
</label>
<label className="kuaishou-industry-tool-field">
<span>补发原因</span>
<Input
maxLength={200}
showCount
value={reissueConsumeReason}
onChange={(event) => setReissueConsumeReason(event.target.value)}
/>
</label>
<Checkbox
checked={reissueConsumeConfirmed}
onChange={(event) => setReissueConsumeConfirmed(event.target.checked)}
>
我已核实该订单仍需履约,并确认补发后立即核销
</Checkbox>
</Space>
</Modal>
</div>
)
@@ -1210,6 +1370,15 @@ export default function AdminKuaishouIndustryPage() {
>
手动核销
</Button>
<Button
danger
icon={<ThunderboltOutlined />}
loading={actionLoading === 'reissue-consume'}
disabled={!hasVoucherTarget}
onClick={openReissueConsumeModal}
>
历史补发并核销
</Button>
<Button
danger
icon={<RollbackOutlined />}
@@ -1677,6 +1846,7 @@ function buildIndustryActionResultView(
const responseData = asRecord(response?.data)
const success = resolveActionSuccess(kind, record, openApi)
const platformMessage = pickFirstString([
...(kind === 'reissue-consume' ? [record.error] : []),
response?.error_msg,
response?.msg,
response?.sub_msg,
@@ -1788,6 +1958,24 @@ function buildIndustryActionResultView(
}
}
if (kind === 'reissue-consume') {
pushHighlight(highlights, '执行阶段', String(record.stage || '-'))
if (record.validMinutes) {
pushHighlight(highlights, '临时有效期', `${String(record.validMinutes)} 分钟`)
}
for (const [label, value] of [
['发码成功', record.sendSuccess],
['核销成功', record.consumeSuccess],
] as const) {
if (typeof value === 'boolean') {
pushHighlight(highlights, label, value ? '是' : '否')
}
}
if (record.reason) {
pushHighlight(highlights, '补发原因', String(record.reason))
}
}
if (platformMessage) {
pushHighlight(highlights, '平台消息', platformMessage)
}
@@ -1855,6 +2043,12 @@ function buildActionSummary(
: context.platformMessage || '重发发码失败。'
}
if (kind === 'reissue-consume') {
return success
? '原券码已同步到快手并完成核销。'
: context.platformMessage || '历史券补发并核销失败。'
}
if (kind === 'refund-list') {
return success
? `查询成功,共 ${context.refundCount ?? 0} 条售后单,已填充列表。`