330 lines
10 KiB
Vue
330 lines
10 KiB
Vue
<script setup lang="ts">
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import { ref } from 'vue'
|
||
|
||
import type { WithdrawalDetail } from '@/features/admin/api/adminWithdrawal'
|
||
import { reviewWithdrawal, confirmPayment } from '@/features/admin/api/adminWithdrawal'
|
||
import { formatCent } from '@/shared/utils/money'
|
||
|
||
const props = defineProps<{
|
||
modelValue: boolean
|
||
withdrawal: WithdrawalDetail | null
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'update:modelValue', val: boolean): void
|
||
(e: 'saved'): void
|
||
}>()
|
||
|
||
const submitting = ref(false)
|
||
|
||
async function handleReview(approved: boolean) {
|
||
if (!props.withdrawal) return
|
||
|
||
const action = approved ? '通过' : '拒绝'
|
||
try {
|
||
const { value: remark } = await ElMessageBox.prompt(
|
||
`请输入${action}原因(可选)`,
|
||
`${action}审核`,
|
||
{
|
||
confirmButtonText: `确认${action}`,
|
||
cancelButtonText: '取消',
|
||
inputType: 'textarea',
|
||
inputPlaceholder: '输入备注信息...',
|
||
}
|
||
)
|
||
|
||
submitting.value = true
|
||
await reviewWithdrawal(props.withdrawal.id, {
|
||
approved,
|
||
remark: remark || '',
|
||
})
|
||
|
||
ElMessage.success(`审核${action}`)
|
||
emit('saved')
|
||
} catch (error: any) {
|
||
if (error !== 'cancel') {
|
||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||
}
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
|
||
async function handleConfirmPayment() {
|
||
if (!props.withdrawal) return
|
||
|
||
try {
|
||
const { value: remark } = await ElMessageBox.prompt(
|
||
'请输入打款备注(如:已通过支付宝转账)',
|
||
'确认打款',
|
||
{
|
||
confirmButtonText: '确认完成',
|
||
cancelButtonText: '取消',
|
||
inputType: 'textarea',
|
||
inputPlaceholder: '输入打款备注...',
|
||
inputValidator: value => {
|
||
return value && value.trim().length > 0
|
||
},
|
||
inputErrorMessage: '请输入打款备注',
|
||
}
|
||
)
|
||
|
||
submitting.value = true
|
||
await confirmPayment(props.withdrawal.id, {
|
||
remark: remark || '',
|
||
})
|
||
|
||
ElMessage.success('打款完成')
|
||
emit('saved')
|
||
} catch (error: any) {
|
||
if (error !== 'cancel') {
|
||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||
}
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
|
||
function statusLabel(status: string) {
|
||
const labels: Record<string, string> = {
|
||
pending: '待审核',
|
||
processing: '处理中',
|
||
completed: '已完成',
|
||
rejected: '已拒绝',
|
||
cancelled: '已取消',
|
||
}
|
||
return labels[status] || status
|
||
}
|
||
|
||
function statusType(status: string) {
|
||
return status === 'completed'
|
||
? 'success'
|
||
: status === 'pending'
|
||
? 'warning'
|
||
: status === 'processing'
|
||
? 'primary'
|
||
: status === 'rejected'
|
||
? 'danger'
|
||
: 'info'
|
||
}
|
||
|
||
function accountTypeLabel(type: string) {
|
||
const labels: Record<string, string> = {
|
||
alipay: '支付宝',
|
||
wechat: '微信',
|
||
bank: '银行卡',
|
||
}
|
||
return labels[type] || type
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<el-dialog
|
||
:model-value="modelValue"
|
||
title="提现详情"
|
||
width="700px"
|
||
@update:model-value="emit('update:modelValue', $event)"
|
||
>
|
||
<div v-if="withdrawal" class="withdrawal-detail">
|
||
<!-- 基本信息 -->
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="提现单号" :span="2">
|
||
{{ withdrawal.withdraw_no }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="状态">
|
||
<el-tag :type="statusType(withdrawal.status)">
|
||
{{ statusLabel(withdrawal.status) }}
|
||
</el-tag>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="申请时间">
|
||
{{ new Date(withdrawal.created_at).toLocaleString('zh-CN') }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 用户信息 -->
|
||
<h3 style="margin-top: 20px">用户信息</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="用户ID">
|
||
{{ withdrawal.user_id }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="昵称">
|
||
{{ withdrawal.user_nickname }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="手机号" :span="2">
|
||
{{ withdrawal.user_phone }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 金额信息 -->
|
||
<h3 style="margin-top: 20px">金额信息</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="提现金额">
|
||
<span style="color: #f56c6c; font-weight: 600; font-size: 16px">
|
||
¥{{ formatCent(withdrawal.amount_cent) }}
|
||
</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="手续费">
|
||
¥{{ formatCent(withdrawal.fee_cent) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="实际到账" :span="2">
|
||
<span style="color: #67c23a; font-weight: 600; font-size: 16px">
|
||
¥{{ formatCent(withdrawal.actual_amount_cent) }}
|
||
</span>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 收款账号信息 -->
|
||
<h3 style="margin-top: 20px">收款账号信息</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="账号类型">
|
||
<el-tag>{{ accountTypeLabel(withdrawal.account_type) }}</el-tag>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="账户名">
|
||
{{ withdrawal.account_name }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="账号" :span="2">
|
||
<span style="font-family: monospace; font-weight: 600">
|
||
{{ withdrawal.account_no }}
|
||
</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="withdrawal.bank_name" label="银行名称">
|
||
{{ withdrawal.bank_name }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="withdrawal.bank_branch" label="开户支行">
|
||
{{ withdrawal.bank_branch }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item
|
||
v-if="withdrawal.certificate_urls && withdrawal.certificate_urls.length > 0"
|
||
label="收款二维码"
|
||
:span="2"
|
||
>
|
||
<div style="display: flex; gap: 8px; flex-wrap: wrap">
|
||
<el-image
|
||
v-for="(url, idx) in withdrawal.certificate_urls"
|
||
:key="idx"
|
||
:src="url"
|
||
:preview-src-list="withdrawal.certificate_urls"
|
||
:initial-index="idx"
|
||
fit="cover"
|
||
style="width: 100px; height: 100px; border-radius: 4px; cursor: pointer"
|
||
/>
|
||
</div>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 审核信息 -->
|
||
<div v-if="withdrawal.reviewed_at">
|
||
<h3 style="margin-top: 20px">审核信息</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="审核人">
|
||
{{ withdrawal.reviewed_by_name }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="审核时间">
|
||
{{ new Date(withdrawal.reviewed_at).toLocaleString('zh-CN') }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="withdrawal.review_remark" label="审核备注" :span="2">
|
||
{{ withdrawal.review_remark }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
|
||
<!-- 打款信息 -->
|
||
<div v-if="withdrawal.paid_at">
|
||
<h3 style="margin-top: 20px">打款信息</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="打款人">
|
||
{{ withdrawal.paid_by_name }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="打款时间">
|
||
{{ new Date(withdrawal.paid_at).toLocaleString('zh-CN') }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="withdrawal.payment_remark" label="打款备注" :span="2">
|
||
{{ withdrawal.payment_remark }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="withdrawal.payment_proof_url" label="打款凭证" :span="2">
|
||
<el-link :href="withdrawal.payment_proof_url" target="_blank" type="primary">
|
||
查看凭证
|
||
</el-link>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
|
||
<!-- 操作提示 -->
|
||
<el-alert
|
||
v-if="withdrawal.status === 'pending'"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
style="margin-top: 20px"
|
||
>
|
||
<template #title>
|
||
<div style="font-size: 13px">
|
||
请仔细核对账号信息后进行审核。审核通过后,需要手动转账到用户账号,并确认打款完成。
|
||
</div>
|
||
</template>
|
||
</el-alert>
|
||
|
||
<el-alert
|
||
v-if="withdrawal.status === 'processing'"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
style="margin-top: 20px"
|
||
>
|
||
<template #title>
|
||
<div style="font-size: 13px">
|
||
请手动转账 <strong>¥{{ formatCent(withdrawal.actual_amount_cent) }}</strong> 到用户收款账号,
|
||
完成后点击"确认打款"按钮。
|
||
</div>
|
||
</template>
|
||
</el-alert>
|
||
</div>
|
||
|
||
<template #footer>
|
||
<div style="display: flex; justify-content: space-between; width: 100%">
|
||
<div>
|
||
<el-button
|
||
v-if="withdrawal?.status === 'pending'"
|
||
type="success"
|
||
:loading="submitting"
|
||
@click="handleReview(true)"
|
||
>
|
||
通过审核
|
||
</el-button>
|
||
<el-button
|
||
v-if="withdrawal?.status === 'pending'"
|
||
type="danger"
|
||
:loading="submitting"
|
||
@click="handleReview(false)"
|
||
>
|
||
拒绝
|
||
</el-button>
|
||
<el-button
|
||
v-if="withdrawal?.status === 'processing'"
|
||
type="primary"
|
||
:loading="submitting"
|
||
@click="handleConfirmPayment"
|
||
>
|
||
确认打款
|
||
</el-button>
|
||
</div>
|
||
<el-button @click="emit('update:modelValue', false)"> 关闭 </el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.withdrawal-detail h3 {
|
||
margin: 20px 0 12px;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
|
||
:deep(.el-descriptions__label) {
|
||
width: 120px;
|
||
}
|
||
</style>
|