Files
art-design/src/components/custom/PaymentRecordDetailDialog.vue
T

381 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.
<template>
<el-dialog
v-model="visible"
title="付款记录详情"
width="800px"
:close-on-click-modal="false"
@close="handleClose"
>
<div class="payment-detail-dialog" v-loading="loading">
<div v-if="paymentData" class="detail-content">
<!-- 基本信息 -->
<div class="section">
<div class="section-title">
<span class="border"></span>
<span class="title">基本信息</span>
</div>
<div class="info-grid">
<div class="info-item">
<label>创建日期:</label>
<span>{{ formatDate(paymentData.created_at) }}</span>
</div>
<div class="info-item">
<label>付款来源:</label>
<span>{{ paymentData.country_name || '—' }}</span>
</div>
<div class="info-item">
<label>汇款人:</label>
<span>{{ paymentData.remitter || '—' }}</span>
</div>
<div class="info-item">
<label>账户:</label>
<span>{{ paymentData.account_name || '—' }}</span>
</div>
<div class="info-item">
<label>币种:</label>
<span>{{ paymentData.currency_name || '—' }}</span>
</div>
<div class="info-item">
<label>金额:</label>
<span class="amount">{{ paymentData.amount }}</span>
</div>
<div class="info-item">
<label>付款水单:</label>
<div>
<p v-for="(item, index) in paymentData.voucher_file" :key="index">
<el-image
v-if="
/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test(
(item.file_full || '').split('?')[0]
)
"
:src="item.file_full"
:preview-src-list="item.file_full ? [item.file_full] : []"
style="width: 100px; height: 100px"
/>
<a
v-else
:href="item.file_full"
target="_blank"
rel="noopener"
style="
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 200px;
"
>{{ item.file_name }}</a
>
</p>
</div>
</div>
</div>
</div>
<!-- 关联信息 -->
<div class="section" v-if="paymentData.payment_apply_id">
<div class="section-title">
<span class="border"></span>
<span class="title">关联信息</span>
</div>
<div class="info-grid">
<div class="info-item">
<label>付款申请ID:</label>
<span>{{ paymentData.payment_apply_id }}</span>
</div>
<div class="info-item">
<label>关联状态:</label>
<el-tag :type="getStatusType(paymentData.status)">
{{ getStatusText(paymentData.status) }}
</el-tag>
</div>
</div>
</div>
<!-- 收款记录关联 -->
<div
class="section"
v-if="paymentData.receipt_records && paymentData.receipt_records.length"
>
<div class="section-title">
<span class="border"></span>
<span class="title">关联收款记录</span>
</div>
<el-table :data="paymentData.receipt_records" style="margin-top: 12px">
<el-table-column label="收款记录ID" prop="id" min-width="120" />
<el-table-column label="创建日期" prop="created_at" min-width="140">
<template #default="scope">
{{ formatDate(scope.row.created_at) }}
</template>
</el-table-column>
<el-table-column label="金额" prop="amount" min-width="120">
<template #default="scope">
{{ formatAmount(scope.row.amount, scope.row.currency_name) }}
</template>
</el-table-column>
<el-table-column label="状态" prop="status" min-width="100">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ getStatusText(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
<!-- 备注信息 -->
<div class="section" v-if="paymentData.remark">
<div class="section-title">
<span class="border"></span>
<span class="title">备注信息</span>
</div>
<div class="remark-content">
{{ paymentData.remark }}
</div>
</div>
</div>
<!-- 无数据状态 -->
<div v-else-if="!loading" class="no-data">
<i class="iconfont-sys">&#xe60c;</i>
<span>暂无数据</span>
</div>
</div>
<!-- <div class="dialog-footer">
<el-button @click="handleClose">关闭</el-button>
</div> -->
</el-dialog>
</template>
<script setup lang="ts">
import { financeService } from '@/api/admin/finance'
interface PaymentRecord {
id: string | number
created_at: string
country_name: string
remitter: string
account_name: string
currency_name: string
amount: number
status: string
payment_apply_id?: string | number
receipt_records?: any[]
voucher_file?: any[]
submit_files?: string[]
remark?: string
}
interface Props {
modelValue: boolean
paymentId?: string | number
}
interface Emits {
(e: 'update:modelValue', value: boolean): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const visible = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
const loading = ref(false)
const paymentData = ref<PaymentRecord | null>(null)
// 获取付款记录详情
const getPaymentDetail = async () => {
if (!props.paymentId) return
loading.value = true
try {
const res = await financeService.getPaymentDetail({ id: props.paymentId })
paymentData.value = res
} catch (error) {
console.error('获取付款记录详情失败:', error)
paymentData.value = null
} finally {
loading.value = false
}
}
// 关闭对话框
const handleClose = () => {
visible.value = false
paymentData.value = null
}
// 打印功能
const handlePrint = () => {
window.print()
}
// 格式化日期
const formatDate = (dateStr: string) => {
if (!dateStr) return '—'
try {
return new Date(dateStr).toLocaleString('zh-CN')
} catch {
return dateStr
}
}
// 格式化金额
const formatAmount = (amount: number, currency: string) => {
return `${currency || ''} ${amount?.toLocaleString() || 0}`
}
// 获取状态类型
const getStatusType = (status: string): 'success' | 'info' | 'warning' | 'danger' | 'primary' => {
const statusMap: Record<string, 'success' | 'info' | 'warning' | 'danger' | 'primary'> = {
available: 'success',
used: 'info',
pending: 'warning',
cancelled: 'danger',
bound: 'success',
unbound: 'info'
}
return statusMap[status] || 'info'
}
// 获取状态文本
const getStatusText = (status: string) => {
const statusMap: Record<string, string> = {
'available': '可用',
'used': '已使用',
'pending': '待处理',
'cancelled': '已取消',
'bound': '已绑定',
'unbound': '未绑定'
}
return statusMap[status] || status
}
// 监听对话框显示状态
watch(visible, (newVal) => {
if (newVal && props.paymentId) {
getPaymentDetail()
}
})
// 监听付款ID变化
watch(() => props.paymentId, (newId) => {
if (visible.value && newId) {
getPaymentDetail()
}
})
</script>
<style scoped lang="scss">
.payment-detail-dialog {
.detail-content {
.section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
font-weight: 600;
color: #222;
.border {
width: 4px;
height: 16px;
background: #3d7bff;
margin-right: 8px;
border-radius: 2px;
}
.title {
font-size: 16px;
}
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
.info-item {
display: flex;
align-items: center;
// padding: 8px 0;
label {
font-weight: 500;
color: #666;
min-width: 100px;
margin-right: 8px;
}
span {
color: #333;
flex: 1;
&.amount {
font-weight: 600;
color: #3d7bff;
font-size: 16px;
}
}
}
}
.remark-content {
padding: 12px;
background: #f8f9fa;
border-radius: 6px;
color: #666;
line-height: 1.6;
min-height: 60px;
}
}
}
.no-data {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 0;
color: #999;
i {
font-size: 48px;
margin-bottom: 12px;
}
}
}
.dialog-footer {
display: flex;
justify-content: center;
gap: 12px;
}
// 打印样式
@media print {
.dialog-footer {
display: none;
}
.payment-detail-dialog {
.section-title {
.border {
background: #000 !important;
}
}
}
}
</style>