fix: 恢复退款原审批提交
All checks were successful
构建并部署前端到测试环境 / deploy (push) Successful in 55s

This commit is contained in:
luo
2026-09-20 18:13:14 +08:00
parent ffba959d45
commit c5d7a260d0
8 changed files with 400 additions and 4 deletions

View File

@@ -17,6 +17,14 @@
>
重新申请
</ElButton>
<ElButton
v-if="refund && canRecoverApproval(refund) && hasAuth('refund:detail')"
type="warning"
:loading="recoverApprovalLoading"
@click="handleRecoverApproval"
>
恢复审批
</ElButton>
<template v-if="refund && canManualApproveRefund(refund)">
<ElButton
v-if="hasAuth('refund:approve')"
@@ -173,7 +181,7 @@
<script setup lang="ts">
import { ref, onMounted, computed, h, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElButton, ElCard, ElIcon, ElMessage } from 'element-plus'
import { ElButton, ElCard, ElIcon, ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
import DetailPage from '@/components/common/DetailPage.vue'
@@ -208,6 +216,7 @@
const isRestrictedCustomerRole = computed(() => [3, 4].includes(Number(userStore.info.user_type)))
const loading = ref(false)
const recoverApprovalLoading = ref(false)
const refund = ref<Refund | null>(null)
const refundVoucherFileKeys = ref<string[]>([])
const approvalDialogVisible = ref(false)
@@ -572,6 +581,20 @@
label: '审批状态',
formatter: (_, data) => getRefundApprovalStatusText(data)
},
{
label: '审批提交状态',
formatter: (_, data) => data.submission_status_name || '-'
},
{
label: '审批失败摘要',
formatter: (_, data) => data.approval_failure_summary || '-',
fullWidth: true
},
{
label: '最近恢复时间',
formatter: (_, data) =>
data.approval_last_recovery_at ? formatDateTime(data.approval_last_recovery_at) : '-'
},
...(!isRestrictedCustomerRole.value
? [
{
@@ -707,6 +730,72 @@
return canResubmitRefund(item)
}
const canRecoverApproval = (item: Refund) => item.approval_recoverable === true
const isApprovalRecoveryConflict = (error: unknown, message = '') => {
if (!error || typeof error !== 'object') {
return message.includes('状态不允许恢复') || message.includes('不可恢复')
}
const candidate = error as {
code?: unknown
response?: { status?: unknown; data?: { code?: unknown } }
}
const code = candidate.response?.data?.code ?? candidate.code
const normalizedMessage = message || getErrorMessage(error, '')
return (
candidate.response?.status === 409 ||
code === 'APPROVAL_RECOVERY_CONFLICT' ||
code === 'REFUND_APPROVAL_NOT_RECOVERABLE' ||
normalizedMessage.includes('状态不允许恢复') ||
normalizedMessage.includes('不可恢复')
)
}
const handleRecoverApproval = async () => {
if (!refund.value || !canRecoverApproval(refund.value) || recoverApprovalLoading.value) return
try {
await ElMessageBox.confirm(
`确定要恢复退款单号 ${refund.value.refund_no} 的原审批提交吗?`,
'恢复审批',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
} catch {
return
}
recoverApprovalLoading.value = true
try {
const res = await RefundService.recoverApproval(refund.value.id)
if (res.code !== 0) {
if (isApprovalRecoveryConflict(res, res.msg || '')) {
ElMessage.error('当前退款审批状态不允许恢复')
await fetchRefundDetail(refund.value.id)
return
}
ElMessage.error(res.msg || '恢复审批失败')
return
}
ElMessage.success('恢复审批成功')
await fetchRefundDetail(refund.value.id)
} catch (error) {
const message = getErrorMessage(error, '恢复审批失败')
if (isApprovalRecoveryConflict(error, message)) {
ElMessage.error('当前退款审批状态不允许恢复')
await fetchRefundDetail(refund.value.id)
} else {
ElMessage.error(message)
}
} finally {
recoverApprovalLoading.value = false
}
}
const handleShowResubmit = () => {
if (!refund.value || !canResubmit(refund.value)) return
resubmitForm.requested_refund_amount =

View File

@@ -216,7 +216,7 @@
getCurrentApproverSummaryText,
getProcessingStatusText
} from '@/utils/business/approvalSummary'
import { toVoucherKeyList } from '@/utils/business'
import { getErrorMessage, toVoucherKeyList } from '@/utils/business'
import { RoutesAlias } from '@/router/routesAlias'
import { AUDIT_PERMISSIONS } from '@/config/constants/audit'
import {
@@ -255,6 +255,7 @@
const resubmitLoading = ref(false)
const resubmitVoucherUploading = ref(false)
const triggerApprovalLoading = ref(false)
const recoverApprovalLoading = ref(false)
const tableRef = ref()
const resubmitUploadRef = ref<InstanceType<typeof VoucherUpload>>()
const createDialogVisible = ref(false)
@@ -380,6 +381,9 @@
{ label: '审批渠道', prop: 'approval_provider' },
{ label: '提交人', prop: 'submitter_name' },
{ label: '审批状态', prop: 'approval_status' },
{ label: '审批提交状态', prop: 'submission_status_name' },
{ label: '审批失败摘要', prop: 'approval_failure_summary' },
{ label: '最近恢复时间', prop: 'approval_last_recovery_at' },
{ label: '当前审批人摘要', prop: 'current_approver_summary' },
{ label: '业务处理状态', prop: 'processing_status_name' },
{ label: '退款原因', prop: 'refund_reason' },
@@ -628,6 +632,27 @@
width: 120,
formatter: (row: Refund) => row.approval_status_name || '-'
},
{
prop: 'submission_status_name',
label: '审批提交状态',
width: 140,
showOverflowTooltip: true,
formatter: (row: Refund) => row.submission_status_name || '-'
},
{
prop: 'approval_failure_summary',
label: '审批失败摘要',
minWidth: 200,
showOverflowTooltip: true,
formatter: (row: Refund) => row.approval_failure_summary || '-'
},
{
prop: 'approval_last_recovery_at',
label: '最近恢复时间',
width: 180,
formatter: (row: Refund) =>
row.approval_last_recovery_at ? formatDateTime(row.approval_last_recovery_at) : '-'
},
{
prop: 'current_approver_summary',
label: '当前审批人摘要',
@@ -926,6 +951,28 @@
return row.status === RefundStatus.PENDING && approvalStatusEmpty
}
const canRecoverApproval = (row: Refund) => row.approval_recoverable === true
const isApprovalRecoveryConflict = (error: unknown, message = '') => {
if (!error || typeof error !== 'object') {
return message.includes('状态不允许恢复') || message.includes('不可恢复')
}
const candidate = error as {
code?: unknown
response?: { status?: unknown; data?: { code?: unknown; msg?: unknown } }
}
const code = candidate.response?.data?.code ?? candidate.code
const normalizedMessage = message || getErrorMessage(error, '')
return (
candidate.response?.status === 409 ||
code === 'APPROVAL_RECOVERY_CONFLICT' ||
code === 'REFUND_APPROVAL_NOT_RECOVERABLE' ||
normalizedMessage.includes('状态不允许恢复') ||
normalizedMessage.includes('不可恢复')
)
}
// 补发历史退款审批
const handleTriggerApproval = (row: Refund) => {
if (triggerApprovalLoading.value) return
@@ -957,6 +1004,47 @@
})
}
// 恢复退款原审批提交
const handleRecoverApproval = (row: Refund) => {
if (recoverApprovalLoading.value || !canRecoverApproval(row)) return
ElMessageBox.confirm(`确定要恢复退款单号 ${row.refund_no} 的原审批提交吗?`, '恢复审批', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
recoverApprovalLoading.value = true
try {
const res = await RefundService.recoverApproval(row.id)
if (res.code !== 0) {
if (isApprovalRecoveryConflict(res, res.msg || '')) {
ElMessage.error('当前退款审批状态不允许恢复')
await getTableData()
return
}
ElMessage.error(res.msg || '恢复审批失败')
return
}
ElMessage.success('恢复审批成功')
await getTableData()
} catch (error) {
const message = getErrorMessage(error, '恢复审批失败')
if (isApprovalRecoveryConflict(error, message)) {
ElMessage.error('当前退款审批状态不允许恢复')
await getTableData()
} else {
ElMessage.error(message)
}
} finally {
recoverApprovalLoading.value = false
}
})
.catch(() => {
// 用户取消
})
}
// 获取操作按钮
const getActions = (row: Refund) => {
const actions: any[] = []
@@ -1024,6 +1112,14 @@
})
}
if (canRecoverApproval(row) && hasAuth('refund:detail')) {
actions.push({
label: '恢复审批',
handler: () => handleRecoverApproval(row),
type: 'warning'
})
}
if (canManualApproveRefund(row) && hasAuth('refund:approve')) {
actions.push({
label: '通过',