fix: some
This commit is contained in:
269
src/components/business/CommissionRecordDetailDialog.vue
Normal file
269
src/components/business/CommissionRecordDetailDialog.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<ElDialog
|
||||
:model-value="modelValue"
|
||||
title="佣金明细详情"
|
||||
width="780px"
|
||||
@update:model-value="handleVisibleChange"
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<div v-loading="loading" class="commission-record-detail">
|
||||
<template v-if="record">
|
||||
<ElDescriptions :column="2" border size="small">
|
||||
<ElDescriptionsItem label="记录类型">
|
||||
<ElTag :type="isClawback ? 'danger' : 'primary'" size="small">
|
||||
{{ recordSourceName }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="状态">
|
||||
<ElTag :type="statusTagType" size="small">
|
||||
{{ record.status_name || statusName }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="佣金金额">
|
||||
<span :class="{ 'amount-negative': isNegative(record.amount) }">
|
||||
{{ formatMoney(record.amount) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="入账后佣金余额">
|
||||
<span :class="{ 'amount-negative': isNegative(record.balance_after) }">
|
||||
{{ formatMoney(record.balance_after) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="佣金来源">
|
||||
<ElTag :type="sourceTagType" size="small">{{ sourceName }}</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="是否可提现">
|
||||
<ElTag v-if="isClawback" type="danger" size="small">不可提现</ElTag>
|
||||
<span v-else>可提现</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="订单号">{{ record.order_no || '-' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卖家店铺">
|
||||
{{ record.seller_shop_name || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="ICCID">{{ record.iccid || '-' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="设备虚拟号">
|
||||
{{ record.virtual_no || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="记录生成时间">
|
||||
{{ record.created_at ? formatDateTime(record.created_at) : '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="佣金入账时间">
|
||||
{{ record.released_at ? formatDateTime(record.released_at) : '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<template v-if="isClawback">
|
||||
<ElDescriptionsItem label="被回溯原佣金ID">
|
||||
{{ record.original_commission_id ?? '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="来源退款单号">
|
||||
{{ record.refund_no || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
</template>
|
||||
</ElDescriptions>
|
||||
|
||||
<template v-if="!isClawback">
|
||||
<div class="detail-section-title">
|
||||
回溯明细
|
||||
<span class="detail-section-summary">
|
||||
累计回溯金额:{{ formatMoney(clawbackTotalAmount) }}
|
||||
</span>
|
||||
</div>
|
||||
<ElTable :data="clawbackRecords" size="small" border :max-height="260">
|
||||
<ElTableColumn label="回溯金额" prop="amount" width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="amount-negative">{{ formatMoney(row.amount) }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="回溯后余额" prop="balance_after" width="130">
|
||||
<template #default="{ row }">
|
||||
<span :class="{ 'amount-negative': isNegative(row.balance_after) }">
|
||||
{{ formatMoney(row.balance_after) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn
|
||||
label="来源退款单号"
|
||||
prop="refund_no"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ row.refund_no || '-' }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="状态" prop="status_name" width="100">
|
||||
<template #default="{ row }">
|
||||
<ElTag type="danger" size="small">{{ row.status_name || '回溯' }}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="生成时间" prop="created_at" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ row.created_at ? formatDateTime(row.created_at) : '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
</template>
|
||||
|
||||
<template v-else-if="originalCommission">
|
||||
<div class="detail-section-title">来源原佣金</div>
|
||||
<ElDescriptions :column="2" border size="small">
|
||||
<ElDescriptionsItem label="原佣金记录ID">
|
||||
{{ originalCommission.id }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="原佣金金额">
|
||||
{{ formatMoney(originalCommission.amount) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="原佣金余额">
|
||||
{{ formatMoney(originalCommission.balance_after) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="原佣金状态">
|
||||
{{ originalCommission.status_name || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="订单号">
|
||||
{{ originalCommission.order_no || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="佣金入账时间">
|
||||
{{
|
||||
originalCommission.released_at
|
||||
? formatDateTime(originalCommission.released_at)
|
||||
: '-'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</template>
|
||||
</template>
|
||||
<ElEmpty v-else-if="!loading" description="佣金明细不存在" />
|
||||
</div>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { CommissionService } from '@/api/modules'
|
||||
import type { ShopCommissionRecordDetail, ShopCommissionRecordSource } from '@/types/api'
|
||||
import {
|
||||
COMMISSION_RECORD_SOURCE_MAP,
|
||||
CommissionSourceMap,
|
||||
CommissionStatusMap,
|
||||
isCommissionClawbackRecord
|
||||
} from '@/config/constants/commission'
|
||||
import { formatDateTime, formatMoney } from '@/utils/business/format'
|
||||
import { getErrorMessage } from '@/utils/business'
|
||||
|
||||
defineOptions({ name: 'CommissionRecordDetailDialog' })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean
|
||||
shopId?: number | null
|
||||
recordId?: number | null
|
||||
source?: ShopCommissionRecordSource
|
||||
}>(),
|
||||
{
|
||||
shopId: null,
|
||||
recordId: null,
|
||||
source: 'original'
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: boolean]
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const detail = ref<ShopCommissionRecordDetail | null>(null)
|
||||
|
||||
const record = computed(() => detail.value?.record || null)
|
||||
const isClawback = computed(() =>
|
||||
isCommissionClawbackRecord({
|
||||
source: detail.value?.source || props.source,
|
||||
status: detail.value?.record?.status
|
||||
})
|
||||
)
|
||||
const commissionStatusMeta = computed(
|
||||
() =>
|
||||
CommissionStatusMap[Number(record.value?.status) as keyof typeof CommissionStatusMap] || null
|
||||
)
|
||||
const commissionSourceMeta = computed(
|
||||
() =>
|
||||
CommissionSourceMap[
|
||||
(record.value?.commission_source || '') as keyof typeof CommissionSourceMap
|
||||
] || null
|
||||
)
|
||||
const recordSourceMeta = computed(
|
||||
() => COMMISSION_RECORD_SOURCE_MAP[isClawback.value ? 'clawback' : 'original']
|
||||
)
|
||||
const recordSourceName = computed(() => recordSourceMeta.value.label)
|
||||
const statusName = computed(() => commissionStatusMeta.value?.label || '-')
|
||||
const statusTagType = computed(() => commissionStatusMeta.value?.type || 'info')
|
||||
const sourceName = computed(
|
||||
() => commissionSourceMeta.value?.label || record.value?.commission_source || '-'
|
||||
)
|
||||
const sourceTagType = computed(() => commissionSourceMeta.value?.type || 'info')
|
||||
const clawbackRecords = computed(() => detail.value?.clawback_records ?? [])
|
||||
const clawbackTotalAmount = computed(() => record.value?.clawback_total_amount ?? 0)
|
||||
const originalCommission = computed(() => detail.value?.original_commission || null)
|
||||
|
||||
const isNegative = (value?: number | null) => typeof value === 'number' && value < 0
|
||||
|
||||
const loadDetail = async () => {
|
||||
if (!props.shopId || !props.recordId) return
|
||||
|
||||
loading.value = true
|
||||
detail.value = null
|
||||
try {
|
||||
const res = await CommissionService.getShopCommissionRecordDetail(
|
||||
props.shopId,
|
||||
props.recordId,
|
||||
props.source
|
||||
)
|
||||
if (res.code === 0) {
|
||||
detail.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.msg || '佣金明细不存在')
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(getErrorMessage(error, '佣金明细不存在'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleVisibleChange = (value: boolean) => {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
|
||||
const handleDialogClosed = () => {
|
||||
detail.value = null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.modelValue, props.shopId, props.recordId, props.source] as const,
|
||||
([visible]) => {
|
||||
if (visible) loadDetail()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.commission-record-detail {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.amount-negative {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.detail-section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-section-summary {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<ElDialog v-model="dialogVisible" title="创建退款申请" width="40%" @closed="handleDialogClosed">
|
||||
<ElForm ref="formRef" :model="formData" :rules="formRules" label-width="80px">
|
||||
<ElDialog v-model="dialogVisible" title="创建退款申请" width="45%" @closed="handleDialogClosed">
|
||||
<ElForm ref="formRef" :model="formData" :rules="formRules" label-width="120px">
|
||||
<ElFormItem label="订单号" prop="order_id">
|
||||
<ElSelect
|
||||
v-if="!hasInitialOrder"
|
||||
@@ -23,6 +23,13 @@
|
||||
</ElSelect>
|
||||
<ElInput v-else :model-value="props.initialOrderNo" disabled style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退款方式" prop="method">
|
||||
<ElRadioGroup v-model="formData.method">
|
||||
<ElRadio v-for="opt in RefundMethodOptions" :key="opt.value" :label="opt.value">
|
||||
{{ opt.label }}
|
||||
</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退款金额" prop="requested_refund_amount">
|
||||
<ElInputNumber
|
||||
v-model="formData.requested_refund_amount"
|
||||
@@ -46,7 +53,21 @@
|
||||
placeholder="请输入退款原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退款凭证" prop="refund_voucher_key">
|
||||
<template v-if="formData.method === RefundMethod.CUSTOMER_ACCOUNT">
|
||||
<ElFormItem label="收款账户名" prop="customer_account_name">
|
||||
<ElInput v-model="formData.customer_account_name" placeholder="请输入收款账户名" maxlength="50" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="收款账号" prop="customer_account_number">
|
||||
<ElInput v-model="formData.customer_account_number" placeholder="请输入收款账号" maxlength="64" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="开户银行">
|
||||
<ElInput v-model="formData.customer_bank_name" placeholder="选填" maxlength="50" />
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<ElFormItem
|
||||
:label="formData.method === RefundMethod.CUSTOMER_ACCOUNT ? '退款凭证(必填)' : '退款凭证'"
|
||||
prop="refund_voucher_key"
|
||||
>
|
||||
<VoucherUpload
|
||||
ref="uploadRef"
|
||||
v-model="formData.refund_voucher_key"
|
||||
@@ -54,6 +75,9 @@
|
||||
@uploading-change="voucherUploading = $event"
|
||||
@change="formRef?.validateField('refund_voucher_key')"
|
||||
/>
|
||||
<div v-if="formData.method === RefundMethod.CUSTOMER_ACCOUNT" class="voucher-tip">
|
||||
客户收款信息方式下须同时提供客户收款信息与至少 1 个退款凭证
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
@@ -77,7 +101,8 @@
|
||||
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 { RefundMethod, type CreateRefundRequest, type Order } from '@/types/api'
|
||||
import { RefundMethodOptions } from '@/config/constants/refund'
|
||||
import { formatMoney, yuanToFen } from '@/utils/business/format'
|
||||
import { getErrorMessage } from '@/utils/business'
|
||||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||||
@@ -110,16 +135,24 @@
|
||||
const formData = reactive<{
|
||||
order_id: number | null
|
||||
package_usage_id?: number
|
||||
method?: RefundMethod
|
||||
requested_refund_amount?: number
|
||||
actual_received_amount: number
|
||||
refund_reason: string
|
||||
customer_account_name: string
|
||||
customer_account_number: string
|
||||
customer_bank_name: string
|
||||
refund_voucher_key: string[]
|
||||
}>({
|
||||
order_id: null,
|
||||
package_usage_id: undefined,
|
||||
method: RefundMethod.ORIGINAL_ROUTE,
|
||||
requested_refund_amount: undefined,
|
||||
actual_received_amount: 0,
|
||||
refund_reason: '',
|
||||
customer_account_name: '',
|
||||
customer_account_number: '',
|
||||
customer_bank_name: '',
|
||||
refund_voucher_key: []
|
||||
})
|
||||
|
||||
@@ -134,14 +167,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
const requireCustomerAccount = (field: string, message: string) => ({
|
||||
validator: (_rule: unknown, value: string, callback: (error?: Error) => void) => {
|
||||
if (formData.method === RefundMethod.CUSTOMER_ACCOUNT && !value?.trim()) {
|
||||
callback(new Error(message))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
})
|
||||
|
||||
const validateVoucherKey = (
|
||||
_rule: unknown,
|
||||
value: string[],
|
||||
callback: (error?: Error) => void
|
||||
) => {
|
||||
if (
|
||||
formData.method === RefundMethod.CUSTOMER_ACCOUNT &&
|
||||
(!Array.isArray(value) || value.length === 0)
|
||||
) {
|
||||
callback(new Error('请上传至少 1 个退款凭证'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const formRules = reactive<FormRules>({
|
||||
order_id: [{ required: true, message: '请选择订单', trigger: 'change' }],
|
||||
method: [{ required: true, message: '请选择退款方式', trigger: 'change' }],
|
||||
requested_refund_amount: [
|
||||
{ required: true, message: '请输入申请退款金额', trigger: 'blur' },
|
||||
{ validator: validateRefundAmount, trigger: 'blur' }
|
||||
],
|
||||
refund_reason: [{ required: true, message: '请输入退款原因', trigger: 'blur' }],
|
||||
refund_voucher_key: [{ required: true, message: '请上传退款凭证', trigger: 'change' }]
|
||||
customer_account_name: requireCustomerAccount('customer_account_name', '请填写收款账户名'),
|
||||
customer_account_number: requireCustomerAccount('customer_account_number', '请填写收款账号'),
|
||||
refund_voucher_key: [{ validator: validateVoucherKey, trigger: 'change' }]
|
||||
})
|
||||
|
||||
const hasInitialOrder = computed(() => !!props.initialOrderId || !!props.initialOrderNo)
|
||||
@@ -202,9 +264,13 @@
|
||||
voucherUploading.value = false
|
||||
formData.order_id = null
|
||||
formData.package_usage_id = undefined
|
||||
formData.method = RefundMethod.ORIGINAL_ROUTE
|
||||
formData.requested_refund_amount = undefined
|
||||
formData.actual_received_amount = 0
|
||||
formData.refund_reason = ''
|
||||
formData.customer_account_name = ''
|
||||
formData.customer_account_number = ''
|
||||
formData.customer_bank_name = ''
|
||||
formData.refund_voucher_key = []
|
||||
orderSearchOptions.value = []
|
||||
uploadRef.value?.clearFiles(false)
|
||||
@@ -222,20 +288,30 @@
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const data: CreateRefundRequest = {
|
||||
actual_received_amount: formData.actual_received_amount,
|
||||
order_id: formData.order_id!,
|
||||
method: formData.method!,
|
||||
package_usage_id: formData.package_usage_id ?? 0,
|
||||
refund_reason: formData.refund_reason,
|
||||
refund_voucher_key: formData.refund_voucher_key,
|
||||
requested_refund_amount: yuanToFen(formData.requested_refund_amount) ?? 0
|
||||
}
|
||||
if (formData.method === RefundMethod.CUSTOMER_ACCOUNT) {
|
||||
data.customer_account_info = {
|
||||
account_name: formData.customer_account_name.trim(),
|
||||
account_number: formData.customer_account_number.trim(),
|
||||
...(formData.customer_bank_name.trim()
|
||||
? { bank_name: formData.customer_bank_name.trim() }
|
||||
: {})
|
||||
}
|
||||
data.refund_voucher_key = formData.refund_voucher_key
|
||||
} else if (formData.refund_voucher_key.length) {
|
||||
data.refund_voucher_key = formData.refund_voucher_key
|
||||
}
|
||||
await RefundService.createRefund(data)
|
||||
ElMessage.success('退款申请创建成功')
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error(getErrorMessage(error, '退款申请创建失败'))
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
@@ -257,3 +333,12 @@
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.voucher-tip {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
</style>
|
||||
|
||||
201
src/components/business/RefundApprovalDialog.vue
Normal file
201
src/components/business/RefundApprovalDialog.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<ElDialog
|
||||
:model-value="modelValue"
|
||||
:title="dialogTitle"
|
||||
width="480px"
|
||||
@update:model-value="handleVisibleChange"
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<template v-if="action === 'approve'">
|
||||
<ElForm ref="approveFormRef" :model="approveForm" :rules="approveRules" label-width="120px">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ refund?.refund_no || '-' }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="审批退款金额">
|
||||
<ElInputNumber
|
||||
v-model="approveForm.approved_refund_amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
placeholder="不填则按申请金额审批"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="审批备注">
|
||||
<ElInput
|
||||
v-model="approveForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入审批备注(选填)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</template>
|
||||
<template v-else-if="action === 'reject'">
|
||||
<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="1000"
|
||||
show-word-limit
|
||||
placeholder="请输入拒绝原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ElForm ref="returnFormRef" :model="returnForm" :rules="returnRules" label-width="120px">
|
||||
<ElFormItem label="退款单号">
|
||||
<span>{{ refund?.refund_no || '-' }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退回备注">
|
||||
<ElInput
|
||||
v-model="returnForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入退回备注(选填)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="handleVisibleChange(false)">取消</ElButton>
|
||||
<ElButton type="primary" :loading="submitLoading" @click="handleConfirm">
|
||||
{{ confirmText }}
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { RefundService } from '@/api/modules'
|
||||
import type { Refund } from '@/types/api'
|
||||
import { yuanToFen } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'RefundApprovalDialog' })
|
||||
|
||||
type ApprovalAction = 'approve' | 'reject' | 'return'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
refund: Refund | null
|
||||
action: ApprovalAction
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: boolean]
|
||||
success: []
|
||||
}>()
|
||||
|
||||
const submitLoading = ref(false)
|
||||
const approveFormRef = ref<FormInstance>()
|
||||
const rejectFormRef = ref<FormInstance>()
|
||||
const returnFormRef = ref<FormInstance>()
|
||||
|
||||
const approveForm = reactive<{
|
||||
approved_refund_amount?: number
|
||||
remark: string
|
||||
}>({
|
||||
approved_refund_amount: undefined,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const rejectForm = reactive<{
|
||||
reject_reason: string
|
||||
}>({
|
||||
reject_reason: ''
|
||||
})
|
||||
|
||||
const returnForm = reactive<{
|
||||
remark: string
|
||||
}>({
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const approveRules = reactive<FormRules>({})
|
||||
const rejectRules = reactive<FormRules>({
|
||||
reject_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
|
||||
})
|
||||
const returnRules = reactive<FormRules>({})
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
if (props.action === 'approve') return '审批通过退款申请'
|
||||
if (props.action === 'reject') return '审批拒绝退款申请'
|
||||
return '退回退款申请'
|
||||
})
|
||||
|
||||
const confirmText = computed(() => {
|
||||
if (props.action === 'approve') return '确认通过'
|
||||
if (props.action === 'reject') return '确认拒绝'
|
||||
return '确认退回'
|
||||
})
|
||||
|
||||
const handleVisibleChange = (visible: boolean) => {
|
||||
emit('update:modelValue', visible)
|
||||
}
|
||||
|
||||
const handleDialogClosed = () => {
|
||||
approveForm.approved_refund_amount = undefined
|
||||
approveForm.remark = ''
|
||||
rejectForm.reject_reason = ''
|
||||
returnForm.remark = ''
|
||||
submitLoading.value = false
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!props.refund || submitLoading.value) return
|
||||
|
||||
let valid = true
|
||||
if (props.action === 'approve') {
|
||||
valid = await approveFormRef.value?.validate().catch(() => false) !== false
|
||||
} else if (props.action === 'reject') {
|
||||
valid = await rejectFormRef.value?.validate().catch(() => false) !== false
|
||||
} else {
|
||||
valid = await returnFormRef.value?.validate().catch(() => false) !== false
|
||||
}
|
||||
if (!valid) return
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const refundId = props.refund.id
|
||||
if (props.action === 'approve') {
|
||||
await RefundService.approveRefund(refundId, {
|
||||
approved_refund_amount: yuanToFen(approveForm.approved_refund_amount),
|
||||
remark: approveForm.remark.trim() || undefined
|
||||
})
|
||||
ElMessage.success('审批通过成功')
|
||||
} else if (props.action === 'reject') {
|
||||
await RefundService.rejectRefund(refundId, {
|
||||
reject_reason: rejectForm.reject_reason.trim()
|
||||
})
|
||||
ElMessage.success('审批拒绝成功')
|
||||
} else {
|
||||
await RefundService.returnRefund(refundId, {
|
||||
remark: returnForm.remark.trim() || undefined
|
||||
})
|
||||
ElMessage.success('退回成功')
|
||||
}
|
||||
emit('update:modelValue', false)
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('操作失败,请稍后重试')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<!-- 分页 -->
|
||||
<div
|
||||
v-if="pagination && tableData.length > 0"
|
||||
v-if="pagination && (alwaysShowPagination || tableData.length > 0)"
|
||||
class="table-pagination"
|
||||
:class="paginationAlign"
|
||||
>
|
||||
@@ -113,7 +113,7 @@
|
||||
/** 是否显示加载状态 */
|
||||
loading?: boolean
|
||||
/** 行数据的 Key,用于标识每一行数据 */
|
||||
rowKey?: string
|
||||
rowKey?: string | ((row: any) => string)
|
||||
/** 行的 className 的回调方法 */
|
||||
rowClassName?: ((data: { row: any; rowIndex: number }) => string) | string
|
||||
/** 是否显示边框 */
|
||||
@@ -144,6 +144,8 @@
|
||||
pageSizes?: number[]
|
||||
/** 只有一页时是否隐藏分页器 */
|
||||
hideOnSinglePage?: boolean
|
||||
/** 数据为空时也始终显示分页器 */
|
||||
alwaysShowPagination?: boolean
|
||||
/** 分页器的对齐方式 */
|
||||
paginationAlign?: 'left' | 'center' | 'right'
|
||||
/** 分页器的大小 */
|
||||
@@ -185,6 +187,7 @@
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
hideOnSinglePage: false,
|
||||
alwaysShowPagination: false,
|
||||
pageSizes: () => [10, 20, 30, 50],
|
||||
paginationAlign: 'center',
|
||||
paginationSize: 'default',
|
||||
|
||||
Reference in New Issue
Block a user