feat: 退款企微审批详情与业务处理状态
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 7m2s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 7m2s
This commit is contained in:
@@ -8,10 +8,7 @@ import type {
|
||||
RefundQueryParams,
|
||||
RefundListResponse,
|
||||
CreateRefundRequest,
|
||||
ApproveRefundRequest,
|
||||
RejectRefundRequest,
|
||||
ResubmitRefundRequest,
|
||||
ReturnRefundRequest,
|
||||
BaseResponse
|
||||
} from '@/types/api'
|
||||
|
||||
@@ -40,24 +37,6 @@ export class RefundService extends BaseService {
|
||||
return this.post<BaseResponse<Refund>>('/api/admin/refunds', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批通过退款申请
|
||||
* @param id 退款申请ID
|
||||
* @param data 审批通过请求参数
|
||||
*/
|
||||
static approveRefund(id: number, data: ApproveRefundRequest): Promise<BaseResponse<void>> {
|
||||
return this.post<BaseResponse<void>>(`/api/admin/refunds/${id}/approve`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批拒绝退款申请
|
||||
* @param id 退款申请ID
|
||||
* @param data 审批拒绝请求参数
|
||||
*/
|
||||
static rejectRefund(id: number, data: RejectRefundRequest): Promise<BaseResponse<void>> {
|
||||
return this.post<BaseResponse<void>>(`/api/admin/refunds/${id}/reject`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新提交退款申请
|
||||
* @param id 退款申请ID
|
||||
@@ -66,13 +45,4 @@ export class RefundService extends BaseService {
|
||||
static resubmitRefund(id: number, data: ResubmitRefundRequest): Promise<BaseResponse<void>> {
|
||||
return this.post<BaseResponse<void>>(`/api/admin/refunds/${id}/resubmit`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回申请
|
||||
* @param id 退款申请ID
|
||||
* @param data 退回请求参数
|
||||
*/
|
||||
static returnRefund(id: number, data: ReturnRefundRequest): Promise<BaseResponse<void>> {
|
||||
return this.post<BaseResponse<void>>(`/api/admin/refunds/${id}/return`, data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,16 @@
|
||||
placeholder="请输入退款原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注">
|
||||
<ElInput
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入备注"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退款凭证" prop="refund_voucher_key">
|
||||
<VoucherUpload
|
||||
ref="uploadRef"
|
||||
@@ -53,6 +63,7 @@
|
||||
voucher-name="退款凭证"
|
||||
@uploading-change="voucherUploading = $event"
|
||||
@change="formRef?.validateField('refund_voucher_key')"
|
||||
@files-change="formData.attachments = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
@@ -77,7 +88,7 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { RefundService, OrderService } from '@/api/modules'
|
||||
import type { CreateRefundRequest, Order } from '@/types/api'
|
||||
import type { CreateRefundRequest, Order, RefundAttachment } from '@/types/api'
|
||||
import { formatMoney, yuanToFen } from '@/utils/business/format'
|
||||
import { getErrorMessage } from '@/utils/business'
|
||||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||||
@@ -111,13 +122,17 @@
|
||||
requested_refund_amount?: number
|
||||
actual_received_amount: number
|
||||
refund_reason: string
|
||||
remark: string
|
||||
refund_voucher_key: string[]
|
||||
attachments: RefundAttachment[]
|
||||
}>({
|
||||
order_id: null,
|
||||
requested_refund_amount: undefined,
|
||||
actual_received_amount: 0,
|
||||
refund_reason: '',
|
||||
refund_voucher_key: []
|
||||
remark: '',
|
||||
refund_voucher_key: [],
|
||||
attachments: []
|
||||
})
|
||||
|
||||
const validateRefundAmount = (rule: any, value: number, callback: any) => {
|
||||
@@ -201,7 +216,9 @@
|
||||
formData.requested_refund_amount = undefined
|
||||
formData.actual_received_amount = 0
|
||||
formData.refund_reason = ''
|
||||
formData.remark = ''
|
||||
formData.refund_voucher_key = []
|
||||
formData.attachments = []
|
||||
orderSearchOptions.value = []
|
||||
uploadRef.value?.clearFiles(false)
|
||||
}
|
||||
@@ -221,8 +238,9 @@
|
||||
order_id: formData.order_id!,
|
||||
requested_refund_amount: yuanToFen(formData.requested_refund_amount) ?? 0,
|
||||
actual_received_amount: formData.actual_received_amount,
|
||||
refund_voucher_key: formData.refund_voucher_key,
|
||||
refund_reason: formData.refund_reason || undefined
|
||||
attachments: formData.attachments,
|
||||
refund_reason: formData.refund_reason || undefined,
|
||||
remark: formData.remark || undefined
|
||||
}
|
||||
await RefundService.createRefund(data)
|
||||
ElMessage.success('退款申请创建成功')
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
import { Close, Document, UploadFilled } from '@element-plus/icons-vue'
|
||||
import type { UploadFile, UploadInstance, UploadRawFile } from 'element-plus'
|
||||
import { StorageService } from '@/api/modules'
|
||||
import type { RefundAttachment } from '@/types/api/refund'
|
||||
|
||||
interface Props {
|
||||
modelValue?: string[] | string
|
||||
@@ -77,12 +78,14 @@
|
||||
'update:modelValue': [value: string[]]
|
||||
'uploading-change': [value: boolean]
|
||||
change: [value: string[]]
|
||||
'files-change': [value: RefundAttachment[]]
|
||||
}>()
|
||||
|
||||
const rootRef = ref<HTMLElement>()
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadingCount = ref(0)
|
||||
const voucherFileKeyMap = new Map<number, string>()
|
||||
const voucherFileMetadataMap = new Map<number, RefundAttachment>()
|
||||
const removedUploadUids = new Set<number>()
|
||||
const fileObjectUrlMap = new Map<number, string>()
|
||||
const selectedUploadUids = new Set<number>()
|
||||
@@ -100,6 +103,10 @@
|
||||
emit('change', keys)
|
||||
}
|
||||
|
||||
const emitFileMetadata = () => {
|
||||
emit('files-change', Array.from(voucherFileMetadataMap.values()))
|
||||
}
|
||||
|
||||
const setUploadingCount = (count: number) => {
|
||||
uploadingCount.value = Math.max(0, count)
|
||||
emit('uploading-change', uploadingCount.value > 0)
|
||||
@@ -109,12 +116,14 @@
|
||||
activeUploadBatch += 1
|
||||
setUploadingCount(0)
|
||||
voucherFileKeyMap.clear()
|
||||
voucherFileMetadataMap.clear()
|
||||
removedUploadUids.clear()
|
||||
selectedUploadUids.clear()
|
||||
revokeAllFileObjectUrls()
|
||||
uploadRef.value?.clearFiles()
|
||||
if (emitValue) {
|
||||
emitVoucherKeys()
|
||||
emitFileMetadata()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +237,13 @@
|
||||
}
|
||||
|
||||
voucherFileKeyMap.set(uploadFile.uid, file_key)
|
||||
voucherFileMetadataMap.set(uploadFile.uid, {
|
||||
file_key,
|
||||
file_name: file.name,
|
||||
file_size: file.size
|
||||
})
|
||||
emitVoucherKeys()
|
||||
emitFileMetadata()
|
||||
ElMessage.success('上传成功')
|
||||
} catch (error: any) {
|
||||
if (uploadBatch !== activeUploadBatch) return
|
||||
@@ -236,7 +251,9 @@
|
||||
console.error(`上传${props.voucherName}失败:`, error)
|
||||
ElMessage.error(error?.message || '上传失败,请重试')
|
||||
voucherFileKeyMap.delete(uploadFile.uid)
|
||||
voucherFileMetadataMap.delete(uploadFile.uid)
|
||||
emitVoucherKeys()
|
||||
emitFileMetadata()
|
||||
removeUploadFile(uploadFile)
|
||||
} finally {
|
||||
if (uploadBatch === activeUploadBatch) {
|
||||
@@ -250,7 +267,9 @@
|
||||
selectedUploadUids.delete(uploadFile.uid)
|
||||
revokeFileObjectUrl(uploadFile.uid)
|
||||
voucherFileKeyMap.delete(uploadFile.uid)
|
||||
voucherFileMetadataMap.delete(uploadFile.uid)
|
||||
emitVoucherKeys()
|
||||
emitFileMetadata()
|
||||
}
|
||||
|
||||
const focusUploadArea = () => {
|
||||
|
||||
@@ -10,6 +10,38 @@ export enum RefundStatus {
|
||||
RETURNED = 4 // 已退回
|
||||
}
|
||||
|
||||
export interface RefundAttachment {
|
||||
file_key: string
|
||||
file_name?: string
|
||||
file_size?: number
|
||||
}
|
||||
|
||||
export interface RefundApprovalTimelineItem {
|
||||
time?: string
|
||||
timestamp?: string
|
||||
status?: string
|
||||
status_name?: string
|
||||
operator?: string
|
||||
operator_name?: string
|
||||
comment?: string
|
||||
content?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface RefundApproval {
|
||||
source?: string | null
|
||||
sp_no?: string | null
|
||||
status?: string | null
|
||||
status_name?: string | null
|
||||
template_version?: string | null
|
||||
applicant?: unknown
|
||||
approvers?: unknown[]
|
||||
comments?: unknown[]
|
||||
attachments?: RefundAttachment[]
|
||||
timeline?: RefundApprovalTimelineItem[]
|
||||
business_process_result?: unknown
|
||||
}
|
||||
|
||||
// 退款申请
|
||||
export interface Refund {
|
||||
id: number
|
||||
@@ -25,8 +57,10 @@ export interface Refund {
|
||||
approved_refund_amount?: number | null // 实际退款金额(分)
|
||||
actual_received_amount?: number | null // 实收金额(分)
|
||||
status: RefundStatus
|
||||
status_name?: string | null
|
||||
refund_reason: string
|
||||
refund_voucher_key?: string[] | string // 退款凭证附件列表;历史数据可能为单字符串或逗号字符串
|
||||
attachments?: RefundAttachment[]
|
||||
reject_reason: string
|
||||
remark: string
|
||||
asset_reset: boolean
|
||||
@@ -38,6 +72,10 @@ export interface Refund {
|
||||
current_approver_summary?: string | null // 当前审批人摘要
|
||||
processing_status?: string | null // 业务处理状态
|
||||
processing_status_name?: string | null // 业务处理状态名称
|
||||
processing_failure_summary?: string | null
|
||||
processing_message?: string | null
|
||||
business_process_result?: unknown
|
||||
approval?: RefundApproval | null
|
||||
creator: number
|
||||
processor_id: number | null
|
||||
processed_at: string | null
|
||||
@@ -71,30 +109,15 @@ export interface CreateRefundRequest {
|
||||
order_id: number
|
||||
requested_refund_amount: number // 申请退款金额(分)
|
||||
actual_received_amount: number // 实收金额(分)
|
||||
refund_voucher_key: string[] // 退款凭证附件列表
|
||||
attachments: RefundAttachment[]
|
||||
refund_reason?: string
|
||||
}
|
||||
|
||||
// 审批通过退款申请请求
|
||||
export interface ApproveRefundRequest {
|
||||
approved_refund_amount?: number // 实际退款金额(分)
|
||||
remark?: string
|
||||
}
|
||||
|
||||
// 审批拒绝退款申请请求
|
||||
export interface RejectRefundRequest {
|
||||
reject_reason: string
|
||||
}
|
||||
|
||||
// 重新提交退款申请请求
|
||||
export interface ResubmitRefundRequest {
|
||||
requested_refund_amount?: number
|
||||
actual_received_amount?: number
|
||||
refund_voucher_key?: string[]
|
||||
attachments?: RefundAttachment[]
|
||||
refund_reason?: string
|
||||
}
|
||||
|
||||
// 退回退款申请请求
|
||||
export interface ReturnRefundRequest {
|
||||
remark?: string
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
返回
|
||||
</ElButton>
|
||||
<h2 class="detail-title">{{ pageTitle }}</h2>
|
||||
<ElButton
|
||||
v-if="refund && canResubmit(refund) && hasAuth('refund:resubmit')"
|
||||
type="primary"
|
||||
@click="handleShowResubmit"
|
||||
>
|
||||
重新申请
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
@@ -24,90 +31,10 @@
|
||||
|
||||
<PaymentVoucherDialog :file-keys="refundVoucherFileKeys" @close="refundVoucherFileKeys = []" />
|
||||
|
||||
<!-- 审批通过对话框 -->
|
||||
<ElDialog
|
||||
v-model="approveDialogVisible"
|
||||
title="审批通过"
|
||||
width="500px"
|
||||
@closed="handleApproveDialogClosed"
|
||||
>
|
||||
<ElForm ref="approveFormRef" :model="approveForm" :rules="approveRules" label-width="120px">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ refund?.refund_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="申请退款金额">
|
||||
<span>{{ formatCurrency(refund?.requested_refund_amount) }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="实际退款金额" prop="approved_refund_amount">
|
||||
<ElInputNumber
|
||||
v-model="approveForm.approved_refund_amount"
|
||||
:min="1"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
placeholder="不填则默认使用申请金额"
|
||||
/>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
||||
不填则默认使用申请金额
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="审批备注">
|
||||
<ElInput
|
||||
v-model="approveForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入审批备注"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="approveDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleApproveRefund" :loading="approveLoading">
|
||||
确认通过
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 审批拒绝对话框 -->
|
||||
<ElDialog
|
||||
v-model="rejectDialogVisible"
|
||||
title="审批拒绝"
|
||||
width="500px"
|
||||
@closed="handleRejectDialogClosed"
|
||||
>
|
||||
<ElForm ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="120px">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ refund?.refund_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="拒绝原因" prop="reject_reason">
|
||||
<ElInput
|
||||
v-model="rejectForm.reject_reason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入拒绝原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="rejectDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="danger" @click="handleRejectRefund" :loading="rejectLoading">
|
||||
确认拒绝
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 重新提交对话框 -->
|
||||
<ElDialog
|
||||
v-model="resubmitDialogVisible"
|
||||
title="重新提交退款申请"
|
||||
title="重新申请退款"
|
||||
width="500px"
|
||||
@closed="handleResubmitDialogClosed"
|
||||
>
|
||||
@@ -157,6 +84,7 @@
|
||||
voucher-name="退款凭证"
|
||||
@uploading-change="resubmitVoucherUploading = $event"
|
||||
@change="resubmitFormRef?.validateField('refund_voucher_key')"
|
||||
@files-change="resubmitForm.attachments = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
@@ -169,7 +97,7 @@
|
||||
:loading="resubmitLoading || resubmitVoucherUploading"
|
||||
:disabled="resubmitVoucherUploading"
|
||||
>
|
||||
{{ resubmitVoucherUploading ? '凭证上传中...' : '确认提交' }}
|
||||
{{ resubmitVoucherUploading ? '凭证上传中...' : '确认申请' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -180,27 +108,23 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, h, reactive } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElButton, ElCard, ElIcon, ElMessage, ElTag } from 'element-plus'
|
||||
import { ElButton, ElCard, ElIcon, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import DetailPage from '@/components/common/DetailPage.vue'
|
||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||
import { RefundService } from '@/api/modules'
|
||||
import type {
|
||||
Refund,
|
||||
RefundStatus,
|
||||
ApproveRefundRequest,
|
||||
RejectRefundRequest,
|
||||
ResubmitRefundRequest
|
||||
} from '@/types/api'
|
||||
import { formatDateTime, yuanToFen } from '@/utils/business/format'
|
||||
import { hasVoucherKeys, toVoucherKeyList } from '@/utils/business'
|
||||
import type { Refund, ResubmitRefundRequest, RefundAttachment } from '@/types/api'
|
||||
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
||||
import { toVoucherKeyList, getErrorMessage } from '@/utils/business'
|
||||
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
||||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
|
||||
defineOptions({ name: 'RefundDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
const loading = ref(false)
|
||||
const refund = ref<Refund | null>(null)
|
||||
@@ -208,44 +132,27 @@
|
||||
|
||||
const pageTitle = computed(() => `退款详情`)
|
||||
|
||||
const approveDialogVisible = ref(false)
|
||||
const rejectDialogVisible = ref(false)
|
||||
const resubmitDialogVisible = ref(false)
|
||||
|
||||
const approveLoading = ref(false)
|
||||
const rejectLoading = ref(false)
|
||||
const resubmitLoading = ref(false)
|
||||
const resubmitVoucherUploading = ref(false)
|
||||
|
||||
const approveFormRef = ref()
|
||||
const rejectFormRef = ref()
|
||||
const resubmitFormRef = ref()
|
||||
const resubmitUploadRef = ref<InstanceType<typeof VoucherUpload>>()
|
||||
|
||||
const approveRules = ref()
|
||||
const rejectRules = ref({
|
||||
reject_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
|
||||
})
|
||||
const resubmitRules = ref()
|
||||
|
||||
const approveForm = reactive<ApproveRefundRequest>({
|
||||
approved_refund_amount: undefined,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const rejectForm = reactive<RejectRefundRequest>({
|
||||
reject_reason: ''
|
||||
})
|
||||
|
||||
const resubmitForm = reactive<{
|
||||
requested_refund_amount?: number
|
||||
actual_received_amount?: number
|
||||
refund_voucher_key: string[]
|
||||
attachments: RefundAttachment[]
|
||||
refund_reason?: string
|
||||
}>({
|
||||
requested_refund_amount: undefined,
|
||||
actual_received_amount: undefined,
|
||||
refund_voucher_key: [],
|
||||
attachments: [],
|
||||
refund_reason: ''
|
||||
})
|
||||
|
||||
@@ -255,45 +162,51 @@
|
||||
return `¥${(amount / 100).toFixed(2)}`
|
||||
}
|
||||
|
||||
const getStatusType = (status: RefundStatus): 'warning' | 'success' | 'danger' | 'info' => {
|
||||
const statusMap: Record<RefundStatus, 'warning' | 'success' | 'danger' | 'info'> = {
|
||||
1: 'warning',
|
||||
2: 'success',
|
||||
3: 'danger',
|
||||
4: 'info'
|
||||
const formatStructuredValue = (value: unknown) => {
|
||||
if (value === undefined || value === null || value === '') return '-'
|
||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
||||
return String(value)
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
return JSON.stringify(value, null, 2)
|
||||
}
|
||||
|
||||
const getStatusText = (status: RefundStatus): string => {
|
||||
const statusMap: Record<RefundStatus, string> = {
|
||||
1: '待审批',
|
||||
2: '已通过',
|
||||
3: '已拒绝',
|
||||
4: '已退回'
|
||||
}
|
||||
return statusMap[status] || '-'
|
||||
const renderStructuredValue = (value: unknown) =>
|
||||
h('pre', { class: 'structured-value' }, formatStructuredValue(value))
|
||||
|
||||
const renderTimeline = (timeline: unknown) => {
|
||||
if (!Array.isArray(timeline) || timeline.length === 0) return h('span', '-')
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{ class: 'approval-timeline' },
|
||||
timeline.map((item: any) => {
|
||||
const title = item.status_name || item.status || item.content || '审批节点'
|
||||
const operator = item.operator_name || item.operator || ''
|
||||
const time = item.time || item.timestamp || ''
|
||||
const comment = item.comment || item.content || ''
|
||||
return h('div', { class: 'approval-timeline__item' }, [
|
||||
h('strong', title),
|
||||
operator || time ? h('span', `${operator}${operator && time ? ' · ' : ''}${time}`) : null,
|
||||
comment && comment !== title ? h('div', comment) : null
|
||||
])
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const getRefundAttachmentKeys = (item: Refund) => {
|
||||
const keys = item.attachments?.map((attachment) => attachment.file_key).filter(Boolean) || []
|
||||
return keys.length ? keys : toVoucherKeyList(item.refund_voucher_key)
|
||||
}
|
||||
|
||||
const detailSections = computed((): DetailSection[] => [
|
||||
{
|
||||
title: '退款信息',
|
||||
title: '退款业务信息',
|
||||
fields: [
|
||||
{ label: '退款单号', prop: 'refund_no' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '订单号', prop: 'order_no' },
|
||||
{ label: '资产标识符', prop: 'asset_identifier' },
|
||||
{
|
||||
label: '资产类型',
|
||||
formatter: (_, data) =>
|
||||
data.asset_type === 'device'
|
||||
? '设备'
|
||||
: data.asset_type === 'card'
|
||||
? '单卡'
|
||||
: data.asset_type === 'iot_card'
|
||||
? 'IoT卡'
|
||||
: data.asset_type || '-'
|
||||
},
|
||||
{ label: '资产类型', prop: 'asset_type' },
|
||||
{
|
||||
label: '申请退款金额',
|
||||
formatter: (_, data) => formatCurrency(data.requested_refund_amount)
|
||||
@@ -307,22 +220,29 @@
|
||||
formatter: (_, data) => formatCurrency(data.actual_received_amount)
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
render: (data) =>
|
||||
h(ElTag, { type: getStatusType(data.status) }, () => getStatusText(data.status))
|
||||
label: '退款原因',
|
||||
prop: 'refund_reason',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '退款凭证',
|
||||
fullWidth: true,
|
||||
render: (data) =>
|
||||
hasVoucherKeys(data.refund_voucher_key)
|
||||
getRefundAttachmentKeys(data).length
|
||||
? h(
|
||||
ElButton,
|
||||
{
|
||||
type: 'primary',
|
||||
link: true,
|
||||
onClick: () => {
|
||||
refundVoucherFileKeys.value = toVoucherKeyList(data.refund_voucher_key)
|
||||
refundVoucherFileKeys.value = getRefundAttachmentKeys(data)
|
||||
}
|
||||
},
|
||||
() => '查看退款凭证'
|
||||
@@ -331,60 +251,89 @@
|
||||
},
|
||||
{
|
||||
label: '资产重置',
|
||||
render: (data) =>
|
||||
h(ElTag, { type: data.asset_reset ? 'success' : 'info' }, () =>
|
||||
data.asset_reset ? '是' : '否'
|
||||
)
|
||||
formatter: (_, data) => (data.asset_reset ? '是' : '否')
|
||||
},
|
||||
{
|
||||
label: '佣金扣除',
|
||||
formatter: (_, data) => (data.commission_deducted ? '是' : '否')
|
||||
},
|
||||
{ label: '创建时间', prop: 'created_at', formatter: (value) => formatDateTime(value) },
|
||||
{ label: '更新时间', prop: 'updated_at', formatter: (value) => formatDateTime(value) }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '企微审批信息',
|
||||
fields: [
|
||||
{ label: '审批来源', prop: 'approval.source' },
|
||||
{ label: '审批单号', prop: 'approval.sp_no' },
|
||||
{
|
||||
label: '审批状态',
|
||||
formatter: (_, data) => data.approval?.status_name || data.approval?.status || '-'
|
||||
},
|
||||
{ label: '模板版本', prop: 'approval.template_version' },
|
||||
{
|
||||
label: '申请人',
|
||||
render: (data) => renderStructuredValue(data.approval?.applicant)
|
||||
},
|
||||
{
|
||||
label: '审批人',
|
||||
render: (data) => renderStructuredValue(data.approval?.approvers)
|
||||
},
|
||||
{
|
||||
label: '审批意见',
|
||||
render: (data) => renderStructuredValue(data.approval?.comments),
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '审批附件',
|
||||
render: (data) => {
|
||||
const keys = (data.approval?.attachments || [])
|
||||
.map((item: RefundAttachment) => item.file_key)
|
||||
.filter(Boolean)
|
||||
return keys.length
|
||||
? h(
|
||||
ElButton,
|
||||
{
|
||||
type: 'primary',
|
||||
link: true,
|
||||
onClick: () => (refundVoucherFileKeys.value = keys)
|
||||
},
|
||||
() => '查看审批附件'
|
||||
)
|
||||
: h('span', '-')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '审批时间线',
|
||||
render: (data) => renderTimeline(data.approval?.timeline),
|
||||
fullWidth: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '业务处理结果',
|
||||
fields: [
|
||||
{
|
||||
label: '处理状态',
|
||||
formatter: (_, data) => data.processing_status_name || data.processing_status || '-'
|
||||
},
|
||||
{
|
||||
label: '失败摘要',
|
||||
formatter: (_, data) => data.processing_failure_summary || data.error_summary || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '处理提示',
|
||||
formatter: (_, data) => data.processing_message || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '业务处理结果',
|
||||
render: (data) =>
|
||||
h(ElTag, { type: data.commission_deducted ? 'success' : 'info' }, () =>
|
||||
data.commission_deducted ? '是' : '否'
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '退款原因',
|
||||
fields: [
|
||||
{
|
||||
label: '退款原因',
|
||||
prop: 'refund_reason',
|
||||
formatter: (value) => value || '-',
|
||||
renderStructuredValue(
|
||||
data.business_process_result || data.approval?.business_process_result
|
||||
),
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '拒绝原因',
|
||||
prop: 'reject_reason',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '审批备注',
|
||||
prop: 'remark',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '时间信息',
|
||||
fields: [
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'created_at',
|
||||
formatter: (value) => formatDateTime(value)
|
||||
},
|
||||
{
|
||||
label: '审批时间',
|
||||
prop: 'processed_at',
|
||||
formatter: (value) => (value ? formatDateTime(value) : '-')
|
||||
},
|
||||
{
|
||||
label: '更新时间',
|
||||
prop: 'updated_at',
|
||||
formatter: (value) => formatDateTime(value)
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -416,72 +365,44 @@
|
||||
}
|
||||
})
|
||||
|
||||
const handleApproveDialogClosed = () => {
|
||||
approveFormRef.value?.resetFields()
|
||||
approveForm.approved_refund_amount = undefined
|
||||
approveForm.remark = ''
|
||||
}
|
||||
|
||||
const handleRejectDialogClosed = () => {
|
||||
rejectFormRef.value?.resetFields()
|
||||
rejectForm.reject_reason = ''
|
||||
}
|
||||
|
||||
const handleResubmitDialogClosed = () => {
|
||||
resubmitFormRef.value?.resetFields()
|
||||
resubmitForm.requested_refund_amount = undefined
|
||||
resubmitForm.actual_received_amount = undefined
|
||||
resubmitForm.refund_voucher_key = []
|
||||
resubmitForm.attachments = []
|
||||
resubmitForm.refund_reason = ''
|
||||
resubmitVoucherUploading.value = false
|
||||
resubmitUploadRef.value?.clearFiles(false)
|
||||
}
|
||||
|
||||
const handleApproveRefund = async () => {
|
||||
if (!approveFormRef.value || !refund.value) return
|
||||
const canResubmit = (item: Refund) => {
|
||||
const statusText = [item.approval_status, item.approval_status_name, item.status_name]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
|
||||
const refundId = refund.value.id
|
||||
await approveFormRef.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
approveLoading.value = true
|
||||
try {
|
||||
const data: ApproveRefundRequest = {
|
||||
approved_refund_amount: yuanToFen(approveForm.approved_refund_amount),
|
||||
remark: approveForm.remark || undefined
|
||||
}
|
||||
|
||||
await RefundService.approveRefund(refundId, data)
|
||||
ElMessage.success('审批通过成功')
|
||||
approveDialogVisible.value = false
|
||||
await fetchRefundDetail(refundId)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
approveLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
return (
|
||||
item.status === 3 ||
|
||||
statusText.includes('reject') ||
|
||||
statusText.includes('revoke') ||
|
||||
statusText.includes('delete') ||
|
||||
statusText.includes('驳回') ||
|
||||
statusText.includes('撤销') ||
|
||||
statusText.includes('删除')
|
||||
)
|
||||
}
|
||||
|
||||
const handleRejectRefund = async () => {
|
||||
if (!rejectFormRef.value || !refund.value) return
|
||||
|
||||
const refundId = refund.value.id
|
||||
await rejectFormRef.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
rejectLoading.value = true
|
||||
try {
|
||||
await RefundService.rejectRefund(refundId, rejectForm)
|
||||
ElMessage.success('审批拒绝成功')
|
||||
rejectDialogVisible.value = false
|
||||
await fetchRefundDetail(refundId)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
rejectLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
const handleShowResubmit = () => {
|
||||
if (!refund.value || !canResubmit(refund.value)) return
|
||||
resubmitForm.requested_refund_amount =
|
||||
fenToYuan(refund.value.requested_refund_amount) || undefined
|
||||
resubmitForm.actual_received_amount =
|
||||
fenToYuan(refund.value.actual_received_amount) || undefined
|
||||
resubmitForm.refund_voucher_key = []
|
||||
resubmitForm.attachments = []
|
||||
resubmitForm.refund_reason = refund.value.refund_reason
|
||||
resubmitDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleResubmitRefund = async () => {
|
||||
@@ -499,18 +420,16 @@
|
||||
const data: ResubmitRefundRequest = {
|
||||
requested_refund_amount: yuanToFen(resubmitForm.requested_refund_amount),
|
||||
actual_received_amount: yuanToFen(resubmitForm.actual_received_amount),
|
||||
refund_reason: resubmitForm.refund_reason || undefined
|
||||
}
|
||||
if (hasVoucherKeys(resubmitForm.refund_voucher_key)) {
|
||||
data.refund_voucher_key = toVoucherKeyList(resubmitForm.refund_voucher_key)
|
||||
refund_reason: resubmitForm.refund_reason || undefined,
|
||||
attachments: resubmitForm.attachments
|
||||
}
|
||||
|
||||
await RefundService.resubmitRefund(refundId, data)
|
||||
ElMessage.success('重新提交成功')
|
||||
ElMessage.success('重新申请成功')
|
||||
resubmitDialogVisible.value = false
|
||||
await fetchRefundDetail(refundId)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error(getErrorMessage(error, '重新申请失败'))
|
||||
} finally {
|
||||
resubmitLoading.value = false
|
||||
}
|
||||
@@ -530,6 +449,7 @@
|
||||
margin-bottom: 24px;
|
||||
|
||||
.detail-title {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
@@ -537,6 +457,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
.structured-value {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
font: inherit;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.approval-timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding-left: 12px;
|
||||
border-left: 2px solid var(--el-color-primary-light-5);
|
||||
|
||||
span {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -54,130 +54,10 @@
|
||||
@close="refundVoucherFileKeys = []"
|
||||
/>
|
||||
|
||||
<!-- 审批通过对话框 -->
|
||||
<ElDialog
|
||||
v-model="approveDialogVisible"
|
||||
title="审批通过"
|
||||
width="500px"
|
||||
@closed="handleApproveDialogClosed"
|
||||
>
|
||||
<ElForm
|
||||
ref="approveFormRef"
|
||||
:model="approveForm"
|
||||
:rules="approveRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ currentRefund?.refund_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="申请退款金额">
|
||||
<span>{{ formatCurrency(currentRefund?.requested_refund_amount) }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="实际退款金额" prop="approved_refund_amount">
|
||||
<ElInputNumber
|
||||
v-model="approveForm.approved_refund_amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
placeholder="不填则默认使用申请金额"
|
||||
/>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
||||
不填则默认使用申请金额
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="审批备注">
|
||||
<ElInput
|
||||
v-model="approveForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入审批备注"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="approveDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleApproveRefund" :loading="approveLoading">
|
||||
确认通过
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 审批拒绝对话框 -->
|
||||
<ElDialog
|
||||
v-model="rejectDialogVisible"
|
||||
title="审批拒绝"
|
||||
width="500px"
|
||||
@closed="handleRejectDialogClosed"
|
||||
>
|
||||
<ElForm ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="120px">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ currentRefund?.refund_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="拒绝原因" prop="reject_reason">
|
||||
<ElInput
|
||||
v-model="rejectForm.reject_reason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入拒绝原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="rejectDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="danger" @click="handleRejectRefund" :loading="rejectLoading">
|
||||
确认拒绝
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 退回对话框 -->
|
||||
<ElDialog
|
||||
v-model="returnDialogVisible"
|
||||
title="驳回申请"
|
||||
width="30%"
|
||||
@closed="handleReturnDialogClosed"
|
||||
>
|
||||
<ElForm ref="returnFormRef" :model="returnForm" :rules="returnRules" label-width="80">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ currentRefund?.refund_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退回备注">
|
||||
<ElInput
|
||||
v-model="returnForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入退回备注"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="return-dialog-tip">
|
||||
驳回后该订单不可再申请退款,若还需申请退款点击审核拒绝。
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="returnDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="warning" @click="handleReturnRefund" :loading="returnLoading">
|
||||
确认退回
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 重新提交对话框 -->
|
||||
<ElDialog
|
||||
v-model="resubmitDialogVisible"
|
||||
title="重新提交退款申请"
|
||||
title="重新申请退款"
|
||||
width="500px"
|
||||
@closed="handleResubmitDialogClosed"
|
||||
>
|
||||
@@ -227,6 +107,7 @@
|
||||
voucher-name="退款凭证"
|
||||
@uploading-change="resubmitVoucherUploading = $event"
|
||||
@change="resubmitFormRef?.validateField('refund_voucher_key')"
|
||||
@files-change="resubmitForm.attachments = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
@@ -239,7 +120,7 @@
|
||||
:loading="resubmitLoading || resubmitVoucherUploading"
|
||||
:disabled="resubmitVoucherUploading"
|
||||
>
|
||||
{{ resubmitVoucherUploading ? '凭证上传中...' : '确认提交' }}
|
||||
{{ resubmitVoucherUploading ? '凭证上传中...' : '确认申请' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -259,10 +140,8 @@
|
||||
Refund,
|
||||
RefundQueryParams,
|
||||
RefundStatus,
|
||||
ApproveRefundRequest,
|
||||
RejectRefundRequest,
|
||||
ReturnRefundRequest,
|
||||
ResubmitRefundRequest
|
||||
ResubmitRefundRequest,
|
||||
RefundAttachment
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
@@ -272,7 +151,7 @@
|
||||
getCurrentApproverSummaryText,
|
||||
getProcessingStatusText
|
||||
} from '@/utils/business/approvalSummary'
|
||||
import { hasVoucherKeys, toVoucherKeyList } from '@/utils/business'
|
||||
import { toVoucherKeyList } from '@/utils/business'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
||||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||||
@@ -286,17 +165,11 @@
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
const loading = ref(false)
|
||||
const approveLoading = ref(false)
|
||||
const rejectLoading = ref(false)
|
||||
const returnLoading = ref(false)
|
||||
const resubmitLoading = ref(false)
|
||||
const resubmitVoucherUploading = ref(false)
|
||||
const tableRef = ref()
|
||||
const resubmitUploadRef = ref<InstanceType<typeof VoucherUpload>>()
|
||||
const createDialogVisible = ref(false)
|
||||
const approveDialogVisible = ref(false)
|
||||
const rejectDialogVisible = ref(false)
|
||||
const returnDialogVisible = ref(false)
|
||||
const resubmitDialogVisible = ref(false)
|
||||
const currentRefund = ref<Refund | null>(null)
|
||||
const refundVoucherFileKeys = ref<string[]>([])
|
||||
@@ -409,43 +282,21 @@
|
||||
{ label: '审批时间', prop: 'processed_at' }
|
||||
]
|
||||
|
||||
const approveFormRef = ref<FormInstance>()
|
||||
const rejectFormRef = ref<FormInstance>()
|
||||
const returnFormRef = ref<FormInstance>()
|
||||
const resubmitFormRef = ref<FormInstance>()
|
||||
|
||||
const approveRules = reactive<FormRules>({})
|
||||
|
||||
const rejectRules = reactive<FormRules>({
|
||||
reject_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const returnRules = reactive<FormRules>({})
|
||||
|
||||
const resubmitRules = reactive<FormRules>({})
|
||||
|
||||
const approveForm = reactive<ApproveRefundRequest>({
|
||||
approved_refund_amount: undefined,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const rejectForm = reactive<RejectRefundRequest>({
|
||||
reject_reason: ''
|
||||
})
|
||||
|
||||
const returnForm = reactive<ReturnRefundRequest>({
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const resubmitForm = reactive<{
|
||||
requested_refund_amount?: number
|
||||
actual_received_amount?: number
|
||||
refund_voucher_key: string[]
|
||||
attachments: RefundAttachment[]
|
||||
refund_reason?: string
|
||||
}>({
|
||||
requested_refund_amount: undefined,
|
||||
actual_received_amount: undefined,
|
||||
refund_voucher_key: [],
|
||||
attachments: [],
|
||||
refund_reason: ''
|
||||
})
|
||||
|
||||
@@ -752,119 +603,6 @@
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 显示审批通过对话框
|
||||
const handleShowApprove = (row: Refund) => {
|
||||
currentRefund.value = row
|
||||
approveDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 审批通过对话框关闭后的清理
|
||||
const handleApproveDialogClosed = () => {
|
||||
approveFormRef.value?.resetFields()
|
||||
approveForm.approved_refund_amount = undefined
|
||||
approveForm.remark = ''
|
||||
currentRefund.value = null
|
||||
}
|
||||
|
||||
// 审批通过
|
||||
const handleApproveRefund = async () => {
|
||||
if (!approveFormRef.value || !currentRefund.value) return
|
||||
|
||||
await approveFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
approveLoading.value = true
|
||||
try {
|
||||
const data: ApproveRefundRequest = {
|
||||
approved_refund_amount: yuanToFen(approveForm.approved_refund_amount),
|
||||
remark: approveForm.remark || undefined
|
||||
}
|
||||
const refundId = currentRefund.value?.id
|
||||
if (!refundId) return
|
||||
await RefundService.approveRefund(refundId, data)
|
||||
ElMessage.success('审批通过成功')
|
||||
approveDialogVisible.value = false
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
approveLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示审批拒绝对话框
|
||||
const handleShowReject = (row: Refund) => {
|
||||
currentRefund.value = row
|
||||
rejectDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 审批拒绝对话框关闭后的清理
|
||||
const handleRejectDialogClosed = () => {
|
||||
rejectFormRef.value?.resetFields()
|
||||
rejectForm.reject_reason = ''
|
||||
currentRefund.value = null
|
||||
}
|
||||
|
||||
// 审批拒绝
|
||||
const handleRejectRefund = async () => {
|
||||
if (!rejectFormRef.value || !currentRefund.value) return
|
||||
|
||||
await rejectFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
rejectLoading.value = true
|
||||
try {
|
||||
const refundId = currentRefund.value?.id
|
||||
if (!refundId) return
|
||||
await RefundService.rejectRefund(refundId, rejectForm)
|
||||
ElMessage.success('审批拒绝成功')
|
||||
rejectDialogVisible.value = false
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
rejectLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示退回对话框
|
||||
const handleShowReturn = (row: Refund) => {
|
||||
currentRefund.value = row
|
||||
returnDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 退回对话框关闭后的清理
|
||||
const handleReturnDialogClosed = () => {
|
||||
returnFormRef.value?.resetFields()
|
||||
returnForm.remark = ''
|
||||
currentRefund.value = null
|
||||
}
|
||||
|
||||
// 退回
|
||||
const handleReturnRefund = async () => {
|
||||
if (!returnFormRef.value || !currentRefund.value) return
|
||||
|
||||
await returnFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
returnLoading.value = true
|
||||
try {
|
||||
const refundId = currentRefund.value?.id
|
||||
if (!refundId) return
|
||||
await RefundService.returnRefund(refundId, returnForm)
|
||||
ElMessage.success('退回成功')
|
||||
returnDialogVisible.value = false
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
returnLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示重新提交对话框
|
||||
const handleShowResubmit = (row: Refund) => {
|
||||
currentRefund.value = row
|
||||
@@ -872,6 +610,7 @@
|
||||
resubmitForm.requested_refund_amount = fenToYuan(row.requested_refund_amount) || undefined
|
||||
resubmitForm.actual_received_amount = fenToYuan(row.actual_received_amount) || undefined
|
||||
resubmitForm.refund_voucher_key = []
|
||||
resubmitForm.attachments = []
|
||||
resubmitForm.refund_reason = row.refund_reason
|
||||
resubmitDialogVisible.value = true
|
||||
}
|
||||
@@ -882,6 +621,7 @@
|
||||
resubmitForm.requested_refund_amount = undefined
|
||||
resubmitForm.actual_received_amount = undefined
|
||||
resubmitForm.refund_voucher_key = []
|
||||
resubmitForm.attachments = []
|
||||
resubmitForm.refund_reason = ''
|
||||
resubmitVoucherUploading.value = false
|
||||
resubmitUploadRef.value?.clearFiles(false)
|
||||
@@ -905,14 +645,12 @@
|
||||
const data: ResubmitRefundRequest = {
|
||||
requested_refund_amount: yuanToFen(resubmitForm.requested_refund_amount),
|
||||
actual_received_amount: yuanToFen(resubmitForm.actual_received_amount),
|
||||
refund_reason: resubmitForm.refund_reason || undefined
|
||||
}
|
||||
if (hasVoucherKeys(resubmitForm.refund_voucher_key)) {
|
||||
data.refund_voucher_key = toVoucherKeyList(resubmitForm.refund_voucher_key)
|
||||
refund_reason: resubmitForm.refund_reason || undefined,
|
||||
attachments: resubmitForm.attachments
|
||||
}
|
||||
|
||||
await RefundService.resubmitRefund(refundId, data)
|
||||
ElMessage.success('重新提交成功')
|
||||
ElMessage.success('重新申请成功')
|
||||
resubmitDialogVisible.value = false
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
@@ -940,43 +678,36 @@
|
||||
})
|
||||
}
|
||||
|
||||
const getRefundAttachmentKeys = (row: Refund) => {
|
||||
const keys = row.attachments?.map((attachment) => attachment.file_key).filter(Boolean) || []
|
||||
return keys.length ? keys : toVoucherKeyList(row.refund_voucher_key)
|
||||
}
|
||||
|
||||
const canResubmit = (row: Refund) => {
|
||||
const statusText = [row.approval_status, row.approval_status_name, row.status_name]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
|
||||
return (
|
||||
row.status === 3 ||
|
||||
statusText.includes('reject') ||
|
||||
statusText.includes('revoke') ||
|
||||
statusText.includes('delete') ||
|
||||
statusText.includes('驳回') ||
|
||||
statusText.includes('撤销') ||
|
||||
statusText.includes('删除')
|
||||
)
|
||||
}
|
||||
|
||||
// 获取操作按钮
|
||||
const getActions = (row: Refund) => {
|
||||
const actions: any[] = []
|
||||
const voucherKeys = toVoucherKeyList(row.refund_voucher_key)
|
||||
const voucherKeys = getRefundAttachmentKeys(row)
|
||||
|
||||
// 待审批状态可以打回重填、审批通过或审批拒绝
|
||||
if (row.status === 1) {
|
||||
// 审批通过
|
||||
if (hasAuth('refund:approve')) {
|
||||
actions.push({
|
||||
label: '审批通过',
|
||||
handler: () => handleShowApprove(row),
|
||||
type: 'primary'
|
||||
})
|
||||
}
|
||||
// 审批拒绝
|
||||
if (hasAuth('refund:reject')) {
|
||||
actions.push({
|
||||
label: '审批拒绝',
|
||||
handler: () => handleShowReject(row),
|
||||
type: 'danger'
|
||||
})
|
||||
}
|
||||
// 驳回
|
||||
if (hasAuth('refund:return')) {
|
||||
actions.push({
|
||||
label: '驳回',
|
||||
handler: () => handleShowReturn(row),
|
||||
type: 'primary'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 只有已退回状态可以重新提交
|
||||
if (row.status === 4 && hasAuth('refund:resubmit')) {
|
||||
if (canResubmit(row) && hasAuth('refund:resubmit')) {
|
||||
actions.push({
|
||||
label: '重新提交',
|
||||
label: '重新申请',
|
||||
handler: () => handleShowResubmit(row),
|
||||
type: 'primary'
|
||||
})
|
||||
@@ -994,22 +725,14 @@
|
||||
}
|
||||
|
||||
const handleViewRefundVoucher = (row: Refund) => {
|
||||
const voucherKey = row.refund_voucher_key
|
||||
if (!hasVoucherKeys(voucherKey)) return
|
||||
refundVoucherFileKeys.value = toVoucherKeyList(voucherKey)
|
||||
const voucherKeys = getRefundAttachmentKeys(row)
|
||||
if (!voucherKeys.length) return
|
||||
refundVoucherFileKeys.value = voucherKeys
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.refund-page {
|
||||
height: 100%;
|
||||
|
||||
.return-dialog-tip {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: var(--el-color-primary);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user