946 lines
27 KiB
Vue
946 lines
27 KiB
Vue
<template>
|
||
<ArtTableFullScreen>
|
||
<div class="refund-page" id="table-full-screen">
|
||
<!-- 搜索栏 -->
|
||
<ArtSearchBar
|
||
v-model:filter="searchForm"
|
||
:items="searchFormItems"
|
||
show-expand
|
||
@reset="handleReset"
|
||
@search="handleSearch"
|
||
></ArtSearchBar>
|
||
|
||
<ElCard shadow="never" class="art-table-card">
|
||
<!-- 表格头部 -->
|
||
<ArtTableHeader
|
||
:columnList="columnOptions"
|
||
v-model:columns="columnChecks"
|
||
@refresh="handleRefresh"
|
||
>
|
||
<template #left>
|
||
<ElButton type="primary" @click="showCreateDialog" v-if="hasAuth('refund:create')"
|
||
>创建退款申请</ElButton
|
||
>
|
||
</template>
|
||
</ArtTableHeader>
|
||
|
||
<!-- 表格 -->
|
||
<ArtTable
|
||
ref="tableRef"
|
||
row-key="id"
|
||
:loading="loading"
|
||
:data="refundList"
|
||
:currentPage="pagination.page"
|
||
:pageSize="pagination.page_size"
|
||
:total="pagination.total"
|
||
:marginTop="10"
|
||
:actions="getActions"
|
||
:actionsWidth="220"
|
||
:inlineActionsCount="2"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
>
|
||
<template #default>
|
||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||
</template>
|
||
</ArtTable>
|
||
|
||
<!-- 创建退款申请对话框 -->
|
||
<CreateRefundDialog v-model="createDialogVisible" @success="handleCreateSuccess" />
|
||
|
||
<!-- 退款凭证预览 -->
|
||
<PaymentVoucherDialog :file-key="refundVoucherFileKey" @close="refundVoucherFileKey = ''" />
|
||
|
||
<!-- 审批通过对话框 -->
|
||
<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="重新提交退款申请"
|
||
width="500px"
|
||
@closed="handleResubmitDialogClosed"
|
||
>
|
||
<ElForm
|
||
ref="resubmitFormRef"
|
||
:model="resubmitForm"
|
||
:rules="resubmitRules"
|
||
label-width="120px"
|
||
>
|
||
<ElFormItem label="退款单号">
|
||
<span>{{ currentRefund?.refund_no }}</span>
|
||
</ElFormItem>
|
||
<ElFormItem label="申请退款金额">
|
||
<ElInputNumber
|
||
v-model="resubmitForm.requested_refund_amount"
|
||
:min="1"
|
||
:precision="2"
|
||
:step="1"
|
||
style="width: 100%"
|
||
placeholder="不填则使用原金额"
|
||
/>
|
||
</ElFormItem>
|
||
<ElFormItem label="实收金额">
|
||
<ElInputNumber
|
||
v-model="resubmitForm.actual_received_amount"
|
||
:min="1"
|
||
:precision="2"
|
||
:step="1"
|
||
style="width: 100%"
|
||
placeholder="不填则使用原金额"
|
||
/>
|
||
</ElFormItem>
|
||
<ElFormItem label="退款原因">
|
||
<ElInput
|
||
v-model="resubmitForm.refund_reason"
|
||
type="textarea"
|
||
:rows="3"
|
||
maxlength="1000"
|
||
show-word-limit
|
||
placeholder="请输入退款原因"
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="resubmitDialogVisible = false">取消</ElButton>
|
||
<ElButton type="primary" @click="handleResubmitRefund" :loading="resubmitLoading">
|
||
确认提交
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
</ElCard>
|
||
</div>
|
||
</ArtTableFullScreen>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { h } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { RefundService, ShopService, OrderService } from '@/api/modules'
|
||
import { ElMessage, ElTag, ElButton } from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
import type {
|
||
Refund,
|
||
RefundQueryParams,
|
||
RefundStatus,
|
||
ApproveRefundRequest,
|
||
RejectRefundRequest,
|
||
ReturnRefundRequest,
|
||
ResubmitRefundRequest
|
||
} from '@/types/api'
|
||
import type { SearchFormItem } from '@/types'
|
||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
||
import { RoutesAlias } from '@/router/routesAlias'
|
||
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
||
|
||
import { useAuth } from '@/composables/useAuth'
|
||
|
||
import CreateRefundDialog from '@/components/business/CreateRefundDialog.vue'
|
||
defineOptions({ name: 'RefundList' })
|
||
|
||
const router = useRouter()
|
||
const { hasAuth } = useAuth()
|
||
|
||
const loading = ref(false)
|
||
const approveLoading = ref(false)
|
||
const rejectLoading = ref(false)
|
||
const returnLoading = ref(false)
|
||
const resubmitLoading = ref(false)
|
||
const tableRef = ref()
|
||
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 refundVoucherFileKey = ref('')
|
||
|
||
// 搜索表单初始值
|
||
const initialSearchState: RefundQueryParams = {
|
||
status: undefined,
|
||
order_id: undefined,
|
||
shop_id: undefined,
|
||
asset_identifier: ''
|
||
}
|
||
|
||
// 搜索表单
|
||
const searchForm = reactive<RefundQueryParams>({ ...initialSearchState })
|
||
|
||
// 店铺选项
|
||
const shopOptions = ref<any[]>([])
|
||
// 订单选项
|
||
const orderOptions = ref<any[]>([])
|
||
// 搜索表单配置
|
||
const searchFormItems: SearchFormItem[] = [
|
||
{
|
||
label: '店铺',
|
||
prop: 'shop_id',
|
||
type: 'select',
|
||
placeholder: '请选择店铺',
|
||
options: () =>
|
||
shopOptions.value.map((shop) => ({
|
||
label: shop.shop_name,
|
||
value: shop.id
|
||
})),
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: (query: string) => searchShops(query)
|
||
}
|
||
},
|
||
{
|
||
label: '订单号',
|
||
prop: 'order_id',
|
||
type: 'select',
|
||
placeholder: '请选择订单号',
|
||
options: () =>
|
||
orderOptions.value.map((order) => ({
|
||
label: `${order.order_no}`,
|
||
value: order.id
|
||
})),
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: (query: string) => searchOrdersForFilter(query)
|
||
}
|
||
},
|
||
{
|
||
label: '资产标识',
|
||
prop: 'asset_identifier',
|
||
type: 'input',
|
||
placeholder: '请输入ICCID或设备虚拟号',
|
||
config: {
|
||
clearable: true
|
||
}
|
||
},
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
type: 'select',
|
||
placeholder: '请选择状态',
|
||
options: [
|
||
{ label: '待审批', value: 1 },
|
||
{ label: '已通过', value: 2 },
|
||
{ label: '已拒绝', value: 3 },
|
||
{ label: '已退回', value: 4 }
|
||
],
|
||
config: {
|
||
clearable: true
|
||
}
|
||
}
|
||
]
|
||
|
||
// 分页
|
||
const pagination = reactive({
|
||
page: 1,
|
||
page_size: 20,
|
||
total: 0
|
||
})
|
||
|
||
// 列配置
|
||
const columnOptions = [
|
||
{ label: '退款单号', prop: 'refund_no' },
|
||
{ label: '店铺名称', prop: 'shop_name' },
|
||
{ label: '订单号', prop: 'order_no' },
|
||
{ label: '资产标识符', prop: 'asset_identifier' },
|
||
{ label: '资产类型', prop: 'asset_type' },
|
||
{ label: '申请退款金额', prop: 'requested_refund_amount' },
|
||
{ label: '实际退款金额', prop: 'approved_refund_amount' },
|
||
{ label: '实收金额', prop: 'actual_received_amount' },
|
||
{ label: '状态', prop: 'status' },
|
||
{ label: '退款原因', prop: 'refund_reason' },
|
||
{ label: '拒绝原因', prop: 'reject_reason' },
|
||
{ label: '审批备注', prop: 'remark' },
|
||
{ label: '资产重置', prop: 'asset_reset' },
|
||
{ label: '佣金扣除', prop: 'commission_deducted' },
|
||
{ label: '创建时间', prop: 'created_at' },
|
||
{ 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_reason?: string
|
||
}>({
|
||
requested_refund_amount: undefined,
|
||
actual_received_amount: undefined,
|
||
refund_reason: ''
|
||
})
|
||
|
||
const refundList = ref<Refund[]>([])
|
||
|
||
// 格式化货币 - 将分转换为元
|
||
const formatCurrency = (amount: number | null | undefined): string => {
|
||
if (amount === undefined || amount === null || Number.isNaN(amount)) return '-'
|
||
|
||
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' // 已退回
|
||
}
|
||
return statusMap[status] || 'info'
|
||
}
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (status: RefundStatus): string => {
|
||
const statusMap: Record<RefundStatus, string> = {
|
||
1: '待审批',
|
||
2: '已通过',
|
||
3: '已拒绝',
|
||
4: '已退回'
|
||
}
|
||
return statusMap[status] || '-'
|
||
}
|
||
|
||
// 动态列配置
|
||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||
{
|
||
prop: 'refund_no',
|
||
label: '退款单号',
|
||
minWidth: 210,
|
||
formatter: (row: Refund) => {
|
||
return h(
|
||
'span',
|
||
{
|
||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||
onClick: (e: MouseEvent) => {
|
||
e.stopPropagation()
|
||
handleNameClick(row)
|
||
}
|
||
},
|
||
row.refund_no
|
||
)
|
||
}
|
||
},
|
||
{
|
||
prop: 'shop_name',
|
||
label: '店铺名称',
|
||
width: 160
|
||
},
|
||
{
|
||
prop: 'order_no',
|
||
label: '订单号',
|
||
width: 180,
|
||
showOverflowTooltip: true
|
||
},
|
||
{
|
||
prop: 'asset_identifier',
|
||
label: '资产标识符',
|
||
width: 200,
|
||
showOverflowTooltip: true
|
||
},
|
||
{
|
||
prop: 'asset_type',
|
||
label: '资产类型',
|
||
width: 100,
|
||
formatter: (row: Refund) =>
|
||
row.asset_type === 'device'
|
||
? '设备'
|
||
: row.asset_type === 'card'
|
||
? '单卡'
|
||
: row.asset_type === 'iot_card'
|
||
? 'IoT卡'
|
||
: row.asset_type || '-'
|
||
},
|
||
{
|
||
prop: 'requested_refund_amount',
|
||
label: '申请退款金额',
|
||
width: 150,
|
||
formatter: (row: Refund) => formatCurrency(row.requested_refund_amount)
|
||
},
|
||
{
|
||
prop: 'approved_refund_amount',
|
||
label: '实际退款金额',
|
||
width: 150,
|
||
formatter: (row: Refund) => formatCurrency(row.approved_refund_amount)
|
||
},
|
||
{
|
||
prop: 'actual_received_amount',
|
||
label: '实收金额',
|
||
width: 120,
|
||
formatter: (row: Refund) => formatCurrency(row.actual_received_amount)
|
||
},
|
||
{
|
||
prop: 'status',
|
||
label: '状态',
|
||
width: 100,
|
||
formatter: (row: Refund) => {
|
||
return h(ElTag, { type: getStatusType(row.status) }, () => getStatusText(row.status))
|
||
}
|
||
},
|
||
{
|
||
prop: 'refund_reason',
|
||
label: '退款原因',
|
||
minWidth: 200,
|
||
formatter: (row: Refund) => row.refund_reason || '-'
|
||
},
|
||
{
|
||
prop: 'reject_reason',
|
||
label: '拒绝原因',
|
||
minWidth: 200,
|
||
formatter: (row: Refund) => row.reject_reason || '-'
|
||
},
|
||
{
|
||
prop: 'remark',
|
||
label: '审批备注',
|
||
minWidth: 200,
|
||
formatter: (row: Refund) => row.remark || '-'
|
||
},
|
||
{
|
||
prop: 'asset_reset',
|
||
label: '资产重置',
|
||
width: 100,
|
||
formatter: (row: Refund) => {
|
||
return h(ElTag, { type: row.asset_reset ? 'success' : 'info' }, () =>
|
||
row.asset_reset ? '是' : '否'
|
||
)
|
||
}
|
||
},
|
||
{
|
||
prop: 'commission_deducted',
|
||
label: '佣金扣除',
|
||
width: 100,
|
||
formatter: (row: Refund) => {
|
||
return h(ElTag, { type: row.commission_deducted ? 'success' : 'info' }, () =>
|
||
row.commission_deducted ? '是' : '否'
|
||
)
|
||
}
|
||
},
|
||
{
|
||
prop: 'created_at',
|
||
label: '创建时间',
|
||
width: 180,
|
||
formatter: (row: Refund) => formatDateTime(row.created_at)
|
||
},
|
||
{
|
||
prop: 'processed_at',
|
||
label: '审批时间',
|
||
width: 180,
|
||
formatter: (row: Refund) => (row.processed_at ? formatDateTime(row.processed_at) : '-')
|
||
}
|
||
])
|
||
|
||
onMounted(() => {
|
||
getTableData()
|
||
searchShops('')
|
||
searchOrdersForFilter('')
|
||
})
|
||
|
||
let isFirstActivation = true
|
||
onActivated(() => {
|
||
if (!isFirstActivation) {
|
||
getTableData()
|
||
}
|
||
isFirstActivation = false
|
||
})
|
||
|
||
// 搜索店铺(用于搜索表单)
|
||
const searchShops = async (query: string) => {
|
||
try {
|
||
const params: any = {
|
||
page: 1,
|
||
page_size: 20
|
||
}
|
||
if (query) {
|
||
params.shop_name = query
|
||
}
|
||
const res = await ShopService.getShops(params)
|
||
if (res.code === 0) {
|
||
shopOptions.value = res.data.items || []
|
||
}
|
||
} catch (error) {
|
||
console.error('Search shops failed:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索订单(用于搜索表单)
|
||
const searchOrdersForFilter = async (query: string) => {
|
||
try {
|
||
const params: any = {
|
||
page: 1,
|
||
page_size: 20
|
||
}
|
||
if (query) {
|
||
params.order_no = query
|
||
}
|
||
const res = await OrderService.getOrders(params)
|
||
if (res.code === 0) {
|
||
orderOptions.value = res.data.items || []
|
||
}
|
||
} catch (error) {
|
||
console.error('Search orders failed:', error)
|
||
}
|
||
}
|
||
|
||
// 获取退款申请列表
|
||
const getTableData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const assetIdentifier = searchForm.asset_identifier?.trim()
|
||
const params: RefundQueryParams = {
|
||
page: pagination.page,
|
||
page_size: pagination.page_size,
|
||
status: searchForm.status,
|
||
order_id: searchForm.order_id,
|
||
shop_id: searchForm.shop_id,
|
||
asset_identifier: assetIdentifier || undefined
|
||
}
|
||
const res = await RefundService.getRefunds(params)
|
||
if (res.code === 0) {
|
||
refundList.value = res.data.items || []
|
||
pagination.total = res.data.total || 0
|
||
}
|
||
} catch (error: any) {
|
||
console.error(error)
|
||
ElMessage.error(error?.message || '重新提交失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 重置搜索
|
||
const handleReset = () => {
|
||
Object.assign(searchForm, { ...initialSearchState })
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = () => {
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
// 刷新表格
|
||
const handleRefresh = () => {
|
||
getTableData()
|
||
}
|
||
|
||
// 处理表格分页变化
|
||
const handleSizeChange = (newPageSize: number) => {
|
||
pagination.page_size = newPageSize
|
||
getTableData()
|
||
}
|
||
|
||
const handleCurrentChange = (newCurrentPage: number) => {
|
||
pagination.page = newCurrentPage
|
||
getTableData()
|
||
}
|
||
|
||
// 显示创建对话框
|
||
const showCreateDialog = () => {
|
||
createDialogVisible.value = true
|
||
}
|
||
|
||
// 创建退款申请成功
|
||
const handleCreateSuccess = () => {
|
||
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
|
||
// 预填充原有数据
|
||
resubmitForm.requested_refund_amount = fenToYuan(row.requested_refund_amount) || undefined
|
||
resubmitForm.actual_received_amount = fenToYuan(row.actual_received_amount) || undefined
|
||
resubmitForm.refund_reason = row.refund_reason
|
||
resubmitDialogVisible.value = true
|
||
}
|
||
|
||
// 重新提交对话框关闭后的清理
|
||
const handleResubmitDialogClosed = () => {
|
||
resubmitFormRef.value?.resetFields()
|
||
resubmitForm.requested_refund_amount = undefined
|
||
resubmitForm.actual_received_amount = undefined
|
||
resubmitForm.refund_reason = ''
|
||
currentRefund.value = null
|
||
}
|
||
|
||
// 重新提交
|
||
const handleResubmitRefund = async () => {
|
||
if (!resubmitFormRef.value || !currentRefund.value) return
|
||
|
||
await resubmitFormRef.value.validate(async (valid) => {
|
||
if (valid) {
|
||
resubmitLoading.value = true
|
||
try {
|
||
const refundId = currentRefund.value?.id
|
||
if (!refundId) return
|
||
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
|
||
}
|
||
|
||
await RefundService.resubmitRefund(refundId, data)
|
||
ElMessage.success('重新提交成功')
|
||
resubmitDialogVisible.value = false
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
resubmitLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 处理名称点击
|
||
const handleNameClick = (row: Refund) => {
|
||
if (hasAuth('refund:detail')) {
|
||
handleViewDetail(row)
|
||
} else {
|
||
ElMessage.warning('您没有查看详情的权限')
|
||
}
|
||
}
|
||
|
||
// 查看详情
|
||
const handleViewDetail = (row: Refund) => {
|
||
router.push({
|
||
path: `${RoutesAlias.RefundManagement}/detail/${row.id}`
|
||
})
|
||
}
|
||
|
||
// 获取操作按钮
|
||
const getActions = (row: Refund) => {
|
||
const actions: any[] = []
|
||
const voucherKey = row.refund_voucher_key
|
||
|
||
// 待审批状态可以打回重填、审批通过或审批拒绝
|
||
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')) {
|
||
actions.push({
|
||
label: '重新提交',
|
||
handler: () => handleShowResubmit(row),
|
||
type: 'primary'
|
||
})
|
||
}
|
||
|
||
if (voucherKey && hasAuth('refund:view_voucher')) {
|
||
actions.push({
|
||
label: '查看退款凭证',
|
||
handler: () => handleViewRefundVoucher(row),
|
||
type: 'primary'
|
||
})
|
||
}
|
||
|
||
return actions
|
||
}
|
||
|
||
const handleViewRefundVoucher = (row: Refund) => {
|
||
const voucherKey = row.refund_voucher_key
|
||
if (!voucherKey) return
|
||
refundVoucherFileKey.value = voucherKey
|
||
}
|
||
</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>
|