Files
hfb_sys/frontend/src/features/admin/components/WithdrawalDetailDialog.vue
T

330 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>