增加兑换重试链路

This commit is contained in:
yml2213
2026-04-13 22:54:14 +08:00
parent bc0d6fc8aa
commit 0c2f2e0a12
12 changed files with 661 additions and 31 deletions
@@ -8,7 +8,7 @@ const props = defineProps<{
function resolveTone(status: string) {
const normalized = String(status || '').trim().toLowerCase()
if (['paid', 'link_generated', 'redeemed', 'available', 'delivered', 'consumed', 'success', 'active', 'system_bound', 'binding_completed'].includes(normalized)) {
if (['paid', 'link_generated', 'redeemed', 'available', 'delivered', 'success', 'active', 'system_bound', 'binding_completed'].includes(normalized)) {
return 'success'
}
@@ -16,7 +16,7 @@ function resolveTone(status: string) {
return 'primary'
}
if (['waiting_inventory', 'retry_pending', 'manual_review', 'invalid', 'expired', 'operator', 'pending_binding', 'binding_exception', 'not_started'].includes(normalized)) {
if (['waiting_inventory', 'retry_pending', 'manual_review', 'invalid', 'expired', 'operator', 'pending_binding', 'binding_exception', 'not_started', 'consumed'].includes(normalized)) {
return 'warning'
}
@@ -56,7 +56,7 @@ function resolveLabel(status: string) {
available: '可用',
reserved: '已预占',
delivered: '已发放',
consumed: '已发放',
consumed: '已消耗',
invalid: '已作废',
active: '生效中',
admin: '管理员',
+15
View File
@@ -373,6 +373,21 @@ export interface AdminTaskDetail {
roleId: string
roleName: string
}
redeemResolution: null | {
status: string
taskStatus: string
replacementCount: number
finishedAt: string | null
attempts: Array<{
attempt: number
inventoryItemId: number | null
codeMasked: string
credentialType: string
outcome: string
resultCode: string
resultMessage: string
}>
}
manualDispatch: null | {
outcome: string
deliveryReference: string
+4
View File
@@ -54,6 +54,10 @@ export function formatTaskEventType(eventType: string) {
const labelMap: Record<string, string> = {
manual_dispatch_completed: '人工履约已回写',
inventory_binding_released: '库存绑定已释放',
claim_redeem_code_used: '兑换码已使用',
claim_redeem_code_invalid: '兑换码错误',
claim_redeem_inventory_replaced: '已切换新兑换码',
claim_redeem_completed: '兑换链路完成',
agiso_auto_delivery_success: '咸鱼自动发货成功',
agiso_auto_delivery_failed: '咸鱼自动发货失败',
agiso_auto_delivery_skipped: '咸鱼自动发货已跳过',
+1
View File
@@ -28,6 +28,7 @@ export const adminInventoryStatusOptions = [
{ label: '可用', value: 'available' },
{ label: '已预占', value: 'reserved' },
{ label: '已发放', value: 'delivered' },
{ label: '已消耗', value: 'consumed' },
{ label: '已作废', value: 'invalid' },
]
@@ -146,6 +146,13 @@ function formatTaskEventPayload(payload: Record<string, unknown>) {
payload.outcome ? `结果 ${payload.outcome}` : '',
payload.resultCode ? `代码 ${payload.resultCode}` : '',
payload.resultMessage ? `说明 ${payload.resultMessage}` : '',
payload.codeMasked ? `凭据 ${payload.codeMasked}` : '',
payload.previousCodeMasked ? `旧码 ${payload.previousCodeMasked}` : '',
payload.nextCodeMasked ? `新码 ${payload.nextCodeMasked}` : '',
payload.inventoryItemId ? `库存项 #${payload.inventoryItemId}` : '',
payload.previousInventoryItemId ? `旧库存 #${payload.previousInventoryItemId}` : '',
payload.nextInventoryItemId ? `新库存 #${payload.nextInventoryItemId}` : '',
payload.previousOutcome ? `切换原因 ${formatRedeemOutcomeLabel(String(payload.previousOutcome || ''))}` : '',
payload.deliveryReference ? `单号 ${payload.deliveryReference}` : '',
payload.platformOrderId ? `平台单 ${payload.platformOrderId}` : '',
payload.reason ? `原因 ${payload.reason}` : '',
@@ -161,6 +168,29 @@ function formatTaskEventPayload(payload: Record<string, unknown>) {
return JSON.stringify(payload || {})
}
function formatRedeemOutcomeLabel(value: string) {
const normalized = String(value || '').trim()
switch (normalized) {
case 'success':
return '兑换成功'
case 'code_used':
return '兑换码已使用'
case 'code_invalid':
return '兑换码错误'
case 'captcha_rejected':
return '验证码错误'
case 'failed':
return '兑换失败'
default:
return normalized || '-'
}
}
function formatRedeemResolutionStatus(value: string) {
return value === 'success' ? '已完成' : value === 'failed' ? '失败收口' : (value || '-')
}
onMounted(loadDetail)
onBeforeUnmount(clearScreenshotPreview)
</script>
@@ -309,6 +339,62 @@ onBeforeUnmount(clearScreenshotPreview)
</table>
</section>
<section v-if="detail.redeemResolution" class="table-card">
<h3>兑换重试链路</h3>
<p class="section-copy">这里记录自动兑换时每次使用过的 CDK判定结果以及是否切换到了新的同类型凭据</p>
<div class="redeem-summary-grid">
<article class="redeem-summary-card">
<span>处理结果</span>
<strong>{{ formatRedeemResolutionStatus(detail.redeemResolution.status) }}</strong>
</article>
<article class="redeem-summary-card">
<span>任务收口状态</span>
<strong>{{ detail.redeemResolution.taskStatus || detail.task.status || '-' }}</strong>
</article>
<article class="redeem-summary-card">
<span>更换新码次数</span>
<strong>{{ detail.redeemResolution.replacementCount }}</strong>
</article>
<article class="redeem-summary-card">
<span>完成时间</span>
<strong>{{ formatAdminDateTime(detail.redeemResolution.finishedAt) }}</strong>
</article>
</div>
<div v-if="detail.redeemResolution.attempts.length > 0" class="redeem-attempts">
<article
v-for="attempt in detail.redeemResolution.attempts"
:key="`${attempt.attempt}-${attempt.inventoryItemId || 'na'}`"
class="redeem-attempt-card"
>
<div class="redeem-attempt-head">
<strong> {{ attempt.attempt }} 次尝试</strong>
<span class="redeem-outcome">{{ formatRedeemOutcomeLabel(attempt.outcome) }}</span>
</div>
<div class="redeem-attempt-grid">
<div>
<span>库存项</span>
<strong>{{ attempt.inventoryItemId ? `#${attempt.inventoryItemId}` : '-' }}</strong>
</div>
<div>
<span>凭据</span>
<strong>{{ attempt.codeMasked || '-' }}</strong>
</div>
<div>
<span>类型</span>
<strong>{{ attempt.credentialType || '-' }}</strong>
</div>
<div>
<span>结果码</span>
<strong>{{ attempt.resultCode || '-' }}</strong>
</div>
</div>
<p class="redeem-attempt-copy">{{ attempt.resultMessage || '-' }}</p>
</article>
</div>
</section>
<section class="table-card">
<h3>库存绑定</h3>
<p class="section-copy">这里展示任务当前和历史绑定过的库存项便于核对多库存任务的真实履约轨迹</p>
@@ -347,7 +433,9 @@ onBeforeUnmount(clearScreenshotPreview)
<AdminStatusTag :status="binding.bindingStatus" />
<AdminStatusTag :status="binding.inventoryStatus" />
</div>
<div v-if="binding.invalidReason" class="binding-meta">作废原因{{ binding.invalidReason }}</div>
<div v-if="binding.invalidReason" class="binding-meta">
{{ binding.inventoryStatus === 'invalid' ? '作废原因' : binding.inventoryStatus === 'consumed' ? '消耗原因' : '处理原因' }}{{ binding.invalidReason }}
</div>
</td>
<td>{{ canViewSensitiveTaskData ? (binding.displayValue || '-') : '客服不可见' }}</td>
<td>
@@ -461,6 +549,56 @@ onBeforeUnmount(clearScreenshotPreview)
.data-table th,.data-table td { padding: 12px 10px; text-align: left; border-bottom: 1px solid rgba(86,108,138,.08); }
.data-table th { width: 160px; color: #64748b; }
.status-stack { display: flex; flex-wrap: wrap; gap: 8px; }
.redeem-summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
margin-bottom: 14px;
}
.redeem-summary-card,
.redeem-attempt-card {
padding: 14px 16px;
border-radius: 16px;
border: 1px solid rgba(86,108,138,.1);
background: rgba(248,250,252,.92);
}
.redeem-summary-card span,
.redeem-attempt-grid span {
display: block;
color: #64748b;
font-size: 12px;
margin-bottom: 6px;
}
.redeem-summary-card strong,
.redeem-attempt-grid strong {
color: #1d3555;
}
.redeem-attempts {
display: grid;
gap: 12px;
}
.redeem-attempt-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.redeem-outcome {
color: #175cd3;
font-size: 13px;
font-weight: 600;
}
.redeem-attempt-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
margin-top: 12px;
}
.redeem-attempt-copy {
margin: 12px 0 0;
color: #334155;
line-height: 1.6;
}
.table-empty { text-align: center; color: #64748b; }
.binding-primary { margin-top: 4px; color: #0f766e; font-size: 12px; font-weight: 600; }
.binding-meta { margin-top: 4px; color: #64748b; font-size: 12px; }