优化快手电子凭证发码和手动处理
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { apiGet } from '@/lib/http'
|
||||
import { apiGet, apiPost } from '@/lib/http'
|
||||
import type { AdminOrderDetail, AdminOrderListItem, AdminPagination } from '@/types/admin'
|
||||
|
||||
export function fetchAdminOrders(params?: Record<string, unknown>) {
|
||||
@@ -11,3 +11,12 @@ export function fetchAdminOrders(params?: Record<string, unknown>) {
|
||||
export function fetchAdminOrderDetail(orderId: number | string) {
|
||||
return apiGet<AdminOrderDetail>(`/api/v1/admin/orders/${orderId}`)
|
||||
}
|
||||
|
||||
export function resendAdminOrderKuaishouIndustryVoucherCode(orderId: number | string) {
|
||||
return apiPost<{
|
||||
success: boolean
|
||||
resentCount: number
|
||||
failedCount: number
|
||||
errorMessage: string
|
||||
}>(`/api/v1/admin/orders/${orderId}/kuaishou-industry/resend-code`, {})
|
||||
}
|
||||
|
||||
@@ -91,3 +91,26 @@ export function returnNumberAdminTaskKuaishouCloudFulfillment(taskId: number | s
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
export function resendAdminTaskKuaishouIndustryVoucherCode(taskId: number | string) {
|
||||
return apiPost<AdminTaskActionResponse>(
|
||||
`/api/v1/admin/tasks/${taskId}/kuaishou-industry/resend-code`,
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
export function consumeAdminTaskKuaishouIndustryVoucher(
|
||||
taskId: number | string,
|
||||
payload: {
|
||||
consumeType?: string
|
||||
storeName?: string
|
||||
storeAddress?: string
|
||||
expressCode?: string
|
||||
expressNo?: string
|
||||
} = {},
|
||||
) {
|
||||
return apiPost<AdminTaskActionResponse>(
|
||||
`/api/v1/admin/tasks/${taskId}/kuaishou-industry/consume`,
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,4 +69,19 @@ export interface AdminOrderDetail {
|
||||
spec: Record<string, unknown>
|
||||
}>
|
||||
tasks: AdminTaskListItem[]
|
||||
kuaishouIndustryVouchers: Array<{
|
||||
oid: string
|
||||
voucherCode: string
|
||||
unitIndex: number
|
||||
status: string
|
||||
sendCallbackStatus: string
|
||||
sendCallbackAttemptCount: number
|
||||
sendCallbackLastError: string
|
||||
sendCallbackSentAt: string | null
|
||||
consumedAt: string | null
|
||||
destroyedAt: string | null
|
||||
}>
|
||||
operations: {
|
||||
canResendKuaishouIndustryVoucherCode: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ export interface AdminTaskOperations {
|
||||
canRebindKuaishouCloudRole: boolean
|
||||
canDispatchKuaishouCloudFulfillment: boolean
|
||||
canReturnKuaishouCloudFulfillment: boolean
|
||||
canResendKuaishouIndustryVoucherCode: boolean
|
||||
canConsumeKuaishouIndustryVoucher: boolean
|
||||
canViewSensitiveTaskData: boolean
|
||||
}
|
||||
|
||||
@@ -201,6 +203,18 @@ export interface AdminTaskDetail {
|
||||
}
|
||||
notes: string
|
||||
}
|
||||
kuaishouIndustryVoucher: null | {
|
||||
oid: string
|
||||
voucherCode: string
|
||||
unitIndex: number
|
||||
status: string
|
||||
sendCallbackStatus: string
|
||||
sendCallbackLastError: string
|
||||
sendCallbackAttemptCount: number
|
||||
sendCallbackSentAt: string | null
|
||||
consumedAt: string | null
|
||||
destroyedAt: string | null
|
||||
}
|
||||
manualDispatch: null | {
|
||||
outcome: string
|
||||
deliveryReference: string
|
||||
|
||||
@@ -3,27 +3,63 @@ import { onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import AdminStatusTag from '@/components/admin/AdminStatusTag.vue'
|
||||
import { fetchAdminOrderDetail } from '@/services/admin'
|
||||
import { fetchAdminOrderDetail, resendAdminOrderKuaishouIndustryVoucherCode } from '@/services/admin'
|
||||
import type { AdminOrderDetail } from '@/types/admin'
|
||||
import { showConfirm, showError, showSuccess } from '@/lib/feedback'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
|
||||
const route = useRoute()
|
||||
const loading = ref(true)
|
||||
const actionLoading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const detail = ref<AdminOrderDetail | null>(null)
|
||||
|
||||
type TagType = 'success' | 'primary' | 'warning' | 'danger' | 'info'
|
||||
|
||||
onMounted(async () => {
|
||||
async function loadDetail() {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await fetchAdminOrderDetail(String(route.params.orderId || ''))
|
||||
detail.value = response.data
|
||||
errorMessage.value = ''
|
||||
} catch (error) {
|
||||
errorMessage.value = error instanceof Error ? error.message : '读取订单详情失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(loadDetail)
|
||||
|
||||
async function handleResendKuaishouIndustryCode() {
|
||||
if (!detail.value) return
|
||||
|
||||
try {
|
||||
await showConfirm(
|
||||
`确认重发订单 ${detail.value.order.platformOrderId} 的电子凭证发码回调吗?系统会复用当前核销码。`,
|
||||
'确认操作',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '继续执行',
|
||||
cancelButtonText: '取消',
|
||||
},
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
actionLoading.value = true
|
||||
try {
|
||||
const response = await resendAdminOrderKuaishouIndustryVoucherCode(detail.value.order.orderId)
|
||||
showSuccess(`电子凭证发码回调已重发,共 ${response.data.resentCount} 张`)
|
||||
await loadDetail()
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : '重发电子凭证发码回调失败')
|
||||
await loadDetail()
|
||||
} finally {
|
||||
actionLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function formatJsonBlock(value: Record<string, unknown>) {
|
||||
return JSON.stringify(value || {}, null, 2)
|
||||
@@ -171,6 +207,33 @@ function resolveOrderProgressTone(summary: AdminOrderDetail['order']['fulfillmen
|
||||
</dl>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="detail.kuaishouIndustryVouchers.length > 0" shadow="never" class="section-card">
|
||||
<div class="section-headline">
|
||||
<h3>电子凭证</h3>
|
||||
<el-button
|
||||
v-if="detail.operations.canResendKuaishouIndustryVoucherCode"
|
||||
:loading="actionLoading"
|
||||
type="primary"
|
||||
plain
|
||||
@click="handleResendKuaishouIndustryCode"
|
||||
>
|
||||
重发发码回调
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="detail.kuaishouIndustryVouchers" size="small">
|
||||
<el-table-column prop="voucherCode" label="核销码" min-width="190" />
|
||||
<el-table-column prop="status" label="券状态" width="110" />
|
||||
<el-table-column prop="sendCallbackStatus" label="发码回调" width="120" />
|
||||
<el-table-column label="回调时间" width="180">
|
||||
<template #default="{ row }">{{ formatAdminDateTime(row.sendCallbackSentAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sendCallbackAttemptCount" label="次数" width="80" />
|
||||
<el-table-column label="异常">
|
||||
<template #default="{ row }">{{ row.sendCallbackLastError || '-' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="section-card">
|
||||
<h3>履约任务</h3>
|
||||
<el-table :data="detail.tasks" size="small">
|
||||
@@ -240,6 +303,18 @@ function resolveOrderProgressTone(summary: AdminOrderDetail['order']['fulfillmen
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.section-headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.section-headline h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.order-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -49,6 +49,8 @@ const {
|
||||
submitKuaishouCloudDispatch,
|
||||
submitKuaishouCloudRefreshRoleInfo,
|
||||
submitKuaishouCloudReturnNumber,
|
||||
submitKuaishouIndustryConsume,
|
||||
submitKuaishouIndustryResendCode,
|
||||
} = useAdminTaskKuaishouCloud(detail, runAction)
|
||||
|
||||
onMounted(loadDetail)
|
||||
@@ -93,6 +95,8 @@ onMounted(loadDetail)
|
||||
@prepare-kuaishou-cloud="submitKuaishouCloudPrepare"
|
||||
@dispatch-kuaishou-cloud="submitKuaishouCloudDispatch"
|
||||
@return-kuaishou-cloud="submitKuaishouCloudReturnNumber"
|
||||
@resend-industry-code="submitKuaishouIndustryResendCode"
|
||||
@consume-industry-voucher="submitKuaishouIndustryConsume"
|
||||
@mark-manual-review="
|
||||
runAction(
|
||||
() => markAdminTaskManualReview(detail!.task.taskId),
|
||||
|
||||
@@ -16,6 +16,8 @@ const emit = defineEmits<{
|
||||
prepareKuaishouCloud: []
|
||||
dispatchKuaishouCloud: []
|
||||
returnKuaishouCloud: []
|
||||
resendIndustryCode: []
|
||||
consumeIndustryVoucher: []
|
||||
markManualReview: []
|
||||
submitManualDispatch: [outcome: 'delivered' | 'failed']
|
||||
closeTask: []
|
||||
@@ -70,6 +72,24 @@ const emit = defineEmits<{
|
||||
>
|
||||
退还号码
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canManageTaskLifecycle && detail.operations.canResendKuaishouIndustryVoucherCode"
|
||||
:loading="actionLoading"
|
||||
round
|
||||
@click="emit('resendIndustryCode')"
|
||||
>
|
||||
重发发码回调
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canManageTaskLifecycle && detail.operations.canConsumeKuaishouIndustryVoucher"
|
||||
:loading="actionLoading"
|
||||
round
|
||||
type="warning"
|
||||
plain
|
||||
@click="emit('consumeIndustryVoucher')"
|
||||
>
|
||||
手动核销
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canManageTaskLifecycle"
|
||||
:disabled="!detail.operations.canMarkManualReview"
|
||||
|
||||
@@ -300,6 +300,25 @@ function formatRebindBinding(
|
||||
<div>
|
||||
<span>核销码</span><strong>{{ flow.ticket.code || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>电子凭证状态</span><strong>{{ detail.kuaishouIndustryVoucher?.status || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>发码回调</span
|
||||
><strong>{{ detail.kuaishouIndustryVoucher?.sendCallbackStatus || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>回调次数</span
|
||||
><strong>{{ detail.kuaishouIndustryVoucher?.sendCallbackAttemptCount || 0 }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>回调时间</span
|
||||
><strong>{{ formatAdminDateTime(detail.kuaishouIndustryVoucher?.sendCallbackSentAt) }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>回调异常</span
|
||||
><strong>{{ detail.kuaishouIndustryVoucher?.sendCallbackLastError || '-' }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>校验状态</span><strong>{{ flow.ticket.status || '-' }}</strong>
|
||||
</div>
|
||||
|
||||
@@ -102,6 +102,7 @@ export function useAdminTaskDetail() {
|
||||
await loadDetail()
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : '操作失败')
|
||||
await loadDetail()
|
||||
} finally {
|
||||
actionLoading.value = false
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { computed, type Ref } from 'vue'
|
||||
|
||||
import {
|
||||
consumeAdminTaskKuaishouIndustryVoucher,
|
||||
dispatchAdminTaskKuaishouCloudFulfillment,
|
||||
prepareAdminTaskKuaishouCloudFulfillment,
|
||||
refreshAdminTaskKuaishouCloudRoleInfo,
|
||||
resendAdminTaskKuaishouIndustryVoucherCode,
|
||||
returnNumberAdminTaskKuaishouCloudFulfillment,
|
||||
} from '@/services/admin'
|
||||
import type { AdminTaskActionResponse, AdminTaskDetail } from '@/types/admin'
|
||||
@@ -178,6 +180,30 @@ export function useAdminTaskKuaishouCloud(
|
||||
)
|
||||
}
|
||||
|
||||
async function submitKuaishouIndustryResendCode() {
|
||||
if (!detail.value) {
|
||||
return
|
||||
}
|
||||
|
||||
await runAction(
|
||||
() => resendAdminTaskKuaishouIndustryVoucherCode(detail.value!.task.taskId),
|
||||
'电子凭证发码回调已重发',
|
||||
`确认重发任务 ${detail.value.task.taskNo} 的电子凭证发码回调吗?系统会复用当前核销码,不会生成新码。`,
|
||||
)
|
||||
}
|
||||
|
||||
async function submitKuaishouIndustryConsume() {
|
||||
if (!detail.value) {
|
||||
return
|
||||
}
|
||||
|
||||
await runAction(
|
||||
() => consumeAdminTaskKuaishouIndustryVoucher(detail.value!.task.taskId),
|
||||
'电子凭证已执行核销',
|
||||
`确认手动执行任务 ${detail.value.task.taskNo} 的电子凭证核销吗?请先确认快手侧已收到发码回调。`,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
kuaishouCloudFlow,
|
||||
kuaishouCloudRole,
|
||||
@@ -189,5 +215,7 @@ export function useAdminTaskKuaishouCloud(
|
||||
submitKuaishouCloudDispatch,
|
||||
submitKuaishouCloudRefreshRoleInfo,
|
||||
submitKuaishouCloudReturnNumber,
|
||||
submitKuaishouIndustryResendCode,
|
||||
submitKuaishouIndustryConsume,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user