添加 内勤 付款 财务收款 及统计 车辆加车系关键字采集
This commit is contained in:
@@ -0,0 +1,380 @@
|
||||
<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"></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>
|
||||
Reference in New Issue
Block a user