Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a171793e9c | |||
| 129ee07273 | |||
| 90df51097f | |||
| 7b1fdf3883 | |||
| 1c81d3108c | |||
| 2b877e9b4d | |||
| bee80af5af | |||
| 045ce9289c | |||
| c5ec4bb5e1 | |||
| 9e260ddcd8 | |||
| 6feb3ace75 | |||
| ec257a246d | |||
| fa764852ab | |||
| 65f7f4a123 | |||
| 922cfec81d | |||
| 5c8df36f12 | |||
| 5503a14408 | |||
| 3439b45d9a | |||
| 045d13eb7b | |||
| da690dfa06 | |||
| 853e9591b3 | |||
| 9052bd1027 | |||
| 079d9babb8 | |||
| 91d810b33a | |||
| ebd7479573 | |||
| 459d306504 | |||
| 64e53b6ee9 | |||
| 9bd7c89cb4 | |||
| 8a0d4fc516 | |||
| 58f7d56f40 | |||
| a91e1d7820 | |||
| a9f8c5c4dc | |||
| aefd43f79d | |||
| 1bd9d163ec | |||
| be6093e57d | |||
| d83246ba8c | |||
| 329acaf68d | |||
| b319944007 | |||
| 70d26f0829 | |||
| 0e84bedb67 | |||
| f5deb7b8f7 | |||
| e797cb24de | |||
| 619311dfbe | |||
| b402e522bf | |||
| f950f665a9 | |||
| 8deecc8197 | |||
| 3e24d1905f | |||
| 7542d80e38 | |||
| e5548f95e4 | |||
| d30ea5b7bf | |||
| 0e4160c5ca | |||
| bd23288acd | |||
| 6bfb940881 | |||
| b50f650565 | |||
| ea1dbb7af4 | |||
| 1bfbb95bd9 | |||
| a9f5f76b35 | |||
| 3ea9d3d5df | |||
| 0cef82279f | |||
| 695ebbcc71 | |||
| ffc194a1c1 | |||
| 48b95e252f | |||
| 382011d592 | |||
| 0f790269db | |||
| f18cfdb69e | |||
| 858147fbbd | |||
| c333b907e6 | |||
| 7979a31e36 | |||
| 4a39387865 | |||
| fc4de02582 | |||
| 2ffe0c9753 | |||
| c3fb2c48d3 | |||
| c5b0a8265a | |||
| ca06c9bc46 | |||
| 3b6de4c7fa | |||
| d3bb4ec6e5 | |||
| c7d890809c | |||
| 31cd18fade | |||
| 59c9c97c08 | |||
| d4b577c42e | |||
| e4967760b7 | |||
| 85102fcf32 | |||
| 0c67666793 | |||
| a41c75f703 | |||
| 22ae0e86c8 | |||
| 812e3c4b0c | |||
| 2ad479b006 | |||
| 5802e157bf | |||
| 713d43f7b4 | |||
| 719911918f | |||
| ce47b39fa5 |
+1
-2
@@ -309,7 +309,6 @@
|
|||||||
"watchWithFilter": true,
|
"watchWithFilter": true,
|
||||||
"whenever": true,
|
"whenever": true,
|
||||||
"ElMessage": true,
|
"ElMessage": true,
|
||||||
"ElTag": true,
|
"ElTag": true
|
||||||
"ElMessageBox": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -7,8 +7,8 @@ VITE_BASE_URL = /
|
|||||||
# VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
|
# VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
|
||||||
# VITE_API_URL = http://219.157.255.213:25703
|
# VITE_API_URL = http://219.157.255.213:25703
|
||||||
# VITE_API_URL = https://mzl.dev.hnxinyouhe.com
|
# VITE_API_URL = https://mzl.dev.hnxinyouhe.com
|
||||||
VITE_API_URL = https://fdesk.hnxinyouhe.com
|
# VITE_API_URL = https://fdesk.hnxinyouhe.com
|
||||||
# VITE_API_URL = https://x-server.hnxinyouhe.com
|
VITE_API_URL = https://x-server.hnxinyouhe.com
|
||||||
|
|
||||||
# VITE_API_URL_WSS = wss://mzl.dev.hnxinyouhe.com
|
# VITE_API_URL_WSS = wss://mzl.dev.hnxinyouhe.com
|
||||||
# VITE_API_URL_WSS = wss://fdesk.hnxinyouhe.com
|
# VITE_API_URL_WSS = wss://fdesk.hnxinyouhe.com
|
||||||
|
|||||||
@@ -71,4 +71,11 @@ export class financeService {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 绑定付款记录到收款记录
|
||||||
|
static bindPaymentRecord(params:any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/receipt/payment',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
<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">{{ formatAmount(paymentData.amount, paymentData.currency_name) }}</span>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</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[]
|
||||||
|
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) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'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>
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
title="选择付款记录"
|
||||||
|
width="80%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
|
<div class="payment-record-dialog">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-input
|
||||||
|
v-model="searchKeyword"
|
||||||
|
placeholder="请输入汇款人、账户或金额"
|
||||||
|
clearable
|
||||||
|
style="width: 300px"
|
||||||
|
@keyup.enter="getPaymentRecords"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="clickable" @click="getPaymentRecords"><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-button type="primary" @click="getPaymentRecords">搜索</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 付款记录表格 -->
|
||||||
|
<el-table
|
||||||
|
ref="tableRef"
|
||||||
|
:data="paymentRecords"
|
||||||
|
:loading="loading"
|
||||||
|
row-key="id"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
@row-click="handleRowClick"
|
||||||
|
highlight-current-row
|
||||||
|
style="margin-top: 16px"
|
||||||
|
>
|
||||||
|
<el-table-column type="radio" width="55">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-radio
|
||||||
|
v-model="selectedRecordId"
|
||||||
|
:value="scope.row.id"
|
||||||
|
@change="handleRadioChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建日期" prop="created_at" min-width="160" />
|
||||||
|
<el-table-column label="付款来源" prop="country_name" min-width="120" />
|
||||||
|
<el-table-column label="汇款人" prop="remitter" min-width="120" />
|
||||||
|
<el-table-column label="账户" prop="account_name" min-width="120" />
|
||||||
|
<el-table-column label="账币" prop="currency_name" min-width="120" />
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.currentPage"
|
||||||
|
v-model:page-size="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<el-button type="primary" :disabled="!selectedRecord" @click="handleConfirm">
|
||||||
|
确认绑定
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { financeService } from '@/api/admin/finance'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
interface PaymentRecord {
|
||||||
|
id: string | number
|
||||||
|
created_at: string
|
||||||
|
country_name: string
|
||||||
|
remitter: string
|
||||||
|
account_name: string
|
||||||
|
currency_name: string
|
||||||
|
amount: number
|
||||||
|
status: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modelValue: boolean
|
||||||
|
receiptId?: string | number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:modelValue', value: boolean): void
|
||||||
|
(e: 'confirm', record: PaymentRecord): 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 searchKeyword = ref('')
|
||||||
|
const paymentRecords = ref<PaymentRecord[]>([])
|
||||||
|
const selectedRecord = ref<PaymentRecord | null>(null)
|
||||||
|
const selectedRecordId = ref<string | number | null>(null)
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取付款记录列表
|
||||||
|
const getPaymentRecords = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
current: pagination.currentPage,
|
||||||
|
size: pagination.pageSize,
|
||||||
|
keyword: searchKeyword.value,
|
||||||
|
scene:'correlation',
|
||||||
|
correlation: 'unbind' // 只显示可用的付款记录
|
||||||
|
}
|
||||||
|
|
||||||
|
const { records, current, size, total } = await financeService.getPaymentList(params)
|
||||||
|
paymentRecords.value = records || []
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取付款记录失败:', error)
|
||||||
|
ElMessage.error('获取付款记录失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理选择变化(保留兼容性)
|
||||||
|
const handleSelectionChange = (selection: PaymentRecord[]) => {
|
||||||
|
// 单选模式下不使用此方法
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理单选按钮变化
|
||||||
|
const handleRadioChange = (record: PaymentRecord) => {
|
||||||
|
selectedRecord.value = record
|
||||||
|
selectedRecordId.value = record.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理行点击
|
||||||
|
const handleRowClick = (record: PaymentRecord) => {
|
||||||
|
selectedRecord.value = record
|
||||||
|
selectedRecordId.value = record.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页处理
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
pagination.currentPage = 1
|
||||||
|
getPaymentRecords()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (page: number) => {
|
||||||
|
pagination.currentPage = page
|
||||||
|
getPaymentRecords()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认绑定
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (!selectedRecord.value) {
|
||||||
|
ElMessage.warning('请选择一条付款记录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emit('confirm', selectedRecord.value)
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭对话框
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false
|
||||||
|
selectedRecord.value = null
|
||||||
|
selectedRecordId.value = null
|
||||||
|
searchKeyword.value = ''
|
||||||
|
pagination.currentPage = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化金额显示
|
||||||
|
const formatAmount = (amount: number, currency: string) => {
|
||||||
|
return `${currency} ${amount?.toLocaleString() || 0}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取状态类型
|
||||||
|
const getStatusType = (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'available': 'success',
|
||||||
|
'used': 'info',
|
||||||
|
'pending': 'warning',
|
||||||
|
'cancelled': 'danger'
|
||||||
|
}
|
||||||
|
return statusMap[status] || 'info'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
const getStatusText = (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'available': '可用',
|
||||||
|
'used': '已使用',
|
||||||
|
'pending': '待处理',
|
||||||
|
'cancelled': '已取消'
|
||||||
|
}
|
||||||
|
return statusMap[status] || status
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听对话框显示状态
|
||||||
|
watch(visible, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
getPaymentRecords()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.payment-record-dialog {
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Vendored
+1
-1
@@ -9,7 +9,7 @@ declare global {
|
|||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
const ElButton: (typeof import('element-plus/es'))['ElButton']
|
const ElButton: (typeof import('element-plus/es'))['ElButton']
|
||||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
const ElMessageBox: (typeof import('element-plus/es'))['ElMessageBox']
|
||||||
const ElNotification: (typeof import('element-plus/es'))['ElNotification']
|
const ElNotification: (typeof import('element-plus/es'))['ElNotification']
|
||||||
const ElPopconfirm: (typeof import('element-plus/es'))['ElPopconfirm']
|
const ElPopconfirm: (typeof import('element-plus/es'))['ElPopconfirm']
|
||||||
const ElPopover: (typeof import('element-plus/es'))['ElPopover']
|
const ElPopover: (typeof import('element-plus/es'))['ElPopover']
|
||||||
|
|||||||
Vendored
-13
@@ -7,7 +7,6 @@ export {}
|
|||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
ApprovalTimeline: typeof import('./../components/custom/ApprovalTimeline.vue')['default']
|
|
||||||
ArtBackToTop: typeof import('./../components/core/base/art-back-to-top/index.vue')['default']
|
ArtBackToTop: typeof import('./../components/core/base/art-back-to-top/index.vue')['default']
|
||||||
ArtBarChart: typeof import('./../components/core/charts/ArtBarChart.vue')['default']
|
ArtBarChart: typeof import('./../components/core/charts/ArtBarChart.vue')['default']
|
||||||
ArtBarChartCard: typeof import('./../components/core/cards/art-bar-chart-card/index.vue')['default']
|
ArtBarChartCard: typeof import('./../components/core/cards/art-bar-chart-card/index.vue')['default']
|
||||||
@@ -73,16 +72,12 @@ declare module 'vue' {
|
|||||||
CommentItem: typeof import('./../components/custom/comment-widget/widget/CommentItem.vue')['default']
|
CommentItem: typeof import('./../components/custom/comment-widget/widget/CommentItem.vue')['default']
|
||||||
CommentWidget: typeof import('./../components/custom/comment-widget/index.vue')['default']
|
CommentWidget: typeof import('./../components/custom/comment-widget/index.vue')['default']
|
||||||
ContainerSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ContainerSettings.vue')['default']
|
ContainerSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ContainerSettings.vue')['default']
|
||||||
copy: typeof import('./../components/custom/ProcurementDetailView copy.vue')['default']
|
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||||
ElBadge: typeof import('element-plus/es')['ElBadge']
|
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||||
ElCalendar: typeof import('element-plus/es')['ElCalendar']
|
ElCalendar: typeof import('element-plus/es')['ElCalendar']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
ElCascader: typeof import('element-plus/es')['ElCascader']
|
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
|
||||||
ElCol: typeof import('element-plus/es')['ElCol']
|
ElCol: typeof import('element-plus/es')['ElCol']
|
||||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||||
@@ -98,10 +93,8 @@ declare module 'vue' {
|
|||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||||
ElImage: typeof import('element-plus/es')['ElImage']
|
ElImage: typeof import('element-plus/es')['ElImage']
|
||||||
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
|
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||||
ElLink: typeof import('element-plus/es')['ElLink']
|
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
ElOption: typeof import('element-plus/es')['ElOption']
|
||||||
@@ -124,21 +117,16 @@ declare module 'vue' {
|
|||||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
ElTag: typeof import('element-plus/es')['ElTag']
|
||||||
ElText: typeof import('element-plus/es')['ElText']
|
|
||||||
ElTimeline: typeof import('element-plus/es')['ElTimeline']
|
ElTimeline: typeof import('element-plus/es')['ElTimeline']
|
||||||
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
ElTree: typeof import('element-plus/es')['ElTree']
|
ElTree: typeof import('element-plus/es')['ElTree']
|
||||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
|
|
||||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||||
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
||||||
HorizontalSubmenu: typeof import('./../components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue')['default']
|
HorizontalSubmenu: typeof import('./../components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue')['default']
|
||||||
LoginLeftView: typeof import('./../components/core/views/login/LoginLeftView.vue')['default']
|
LoginLeftView: typeof import('./../components/core/views/login/LoginLeftView.vue')['default']
|
||||||
MenuLayoutSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue')['default']
|
MenuLayoutSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue')['default']
|
||||||
MenuStyleSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue')['default']
|
MenuStyleSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue')['default']
|
||||||
OrderDetailContent: typeof import('./../components/custom/OrderDetailContent.vue')['default']
|
|
||||||
ProcurementDetailView: typeof import('./../components/custom/ProcurementDetailView.vue')['default']
|
|
||||||
'ProcurementDetailView copy': typeof import('./../components/custom/ProcurementDetailView copy.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
SectionTitle: typeof import('./../components/core/layouts/art-settings-panel/widget/SectionTitle.vue')['default']
|
SectionTitle: typeof import('./../components/core/layouts/art-settings-panel/widget/SectionTitle.vue')['default']
|
||||||
@@ -147,7 +135,6 @@ declare module 'vue' {
|
|||||||
SettingItem: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingItem.vue')['default']
|
SettingItem: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingItem.vue')['default']
|
||||||
SidebarSubmenu: typeof import('./../components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default']
|
SidebarSubmenu: typeof import('./../components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default']
|
||||||
ThemeSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ThemeSettings.vue')['default']
|
ThemeSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ThemeSettings.vue')['default']
|
||||||
WorkChatDrawer: typeof import('./../components/custom/chat/WorkChatDrawer.vue')['default']
|
|
||||||
}
|
}
|
||||||
export interface ComponentCustomProperties {
|
export interface ComponentCustomProperties {
|
||||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||||
|
|||||||
@@ -486,9 +486,7 @@
|
|||||||
current: currentPage,
|
current: currentPage,
|
||||||
size: pageSize,
|
size: pageSize,
|
||||||
user_id: selectValue.value.join(','),
|
user_id: selectValue.value.join(','),
|
||||||
tag_id: Object.values(tagActiveMap).filter(Boolean),
|
tag_id: Object.values(tagActiveMap).filter(Boolean)
|
||||||
keyword: keyword.value,
|
|
||||||
channel_id: selectchannel_id.value
|
|
||||||
}
|
}
|
||||||
// manageService.crmCustomerExport(params)
|
// manageService.crmCustomerExport(params)
|
||||||
try {
|
try {
|
||||||
@@ -496,7 +494,7 @@
|
|||||||
// const res = await manageService.crmCustomerExport(params)
|
// const res = await manageService.crmCustomerExport(params)
|
||||||
const urls =
|
const urls =
|
||||||
import.meta.env.VITE_API_URL +
|
import.meta.env.VITE_API_URL +
|
||||||
`/admin/crm/customer/export?current=${params.current}&size=${params.size}&user_id=${params.user_id}&tag_id=${params.tag_id}&channel_id=${params.channel_id}&keyword=${params.keyword}`
|
`/admin/crm/customer/export?current=${params.currentPage}&size=${params.pageSize}&user_id=${params.user_id}&tag_id=${params.tag_id}`
|
||||||
// 2. 创建blob对象
|
// 2. 创建blob对象
|
||||||
// const blob = new Blob([res], { type: 'application/vnd.ms-excel' }) // 或根据后端实际类型调整
|
// const blob = new Blob([res], { type: 'application/vnd.ms-excel' }) // 或根据后端实际类型调整
|
||||||
// 3. 创建下载链接
|
// 3. 创建下载链接
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stocking-page">
|
||||||
|
<div class="stocking-toolbar boxshadow">
|
||||||
|
<div class="toolbar-left"></div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-input
|
||||||
|
v-model="keyword"
|
||||||
|
placeholder="请输入客户名称"
|
||||||
|
clearable
|
||||||
|
style="width: 260px"
|
||||||
|
@keyup.enter="getList"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="boxshadow">
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane label="未认领" name="not"></el-tab-pane>
|
||||||
|
<el-tab-pane label="已认领" name="already"></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="创建日期" prop="created_at" min-width="160" />
|
||||||
|
<ElTableColumn label="付款来源" prop="country_name" min-width="120" />
|
||||||
|
<ElTableColumn label="汇款人" prop="remitter" min-width="120" />
|
||||||
|
<ElTableColumn label="账户" prop="account_name" min-width="120" />
|
||||||
|
<ElTableColumn label="账币" prop="currency_name" min-width="120" />
|
||||||
|
<ElTableColumn label="金额" prop="amount" min-width="120" />
|
||||||
|
<ElTableColumn label="操作" fixed="right" min-width="140" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow :gutter="10" justify="center">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
underline="never"
|
||||||
|
@click="handleView()"
|
||||||
|
style="margin-right: 8px"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 查看
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-if="!scope.row.payment_apply_id"
|
||||||
|
type="success"
|
||||||
|
underline="never"
|
||||||
|
@click="handleClaim(scope.row)"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 认领
|
||||||
|
</el-link>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 付款记录选择对话框 -->
|
||||||
|
<PaymentRecordDialog
|
||||||
|
v-model="paymentDialogVisible"
|
||||||
|
:receipt-id="currentReceiptId"
|
||||||
|
@confirm="handlePaymentRecordConfirm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { manageService } from '@/api/adminApi'
|
||||||
|
import { financeService } from '@/api/admin/finance'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
import PaymentRecordDialog from '@/components/custom/PaymentRecordDialog.vue'
|
||||||
|
defineOptions({ name: 'Adminclaim' })
|
||||||
|
const { hasAuth } = useAuth()
|
||||||
|
const loading = ref(false)
|
||||||
|
const keyword = ref('')
|
||||||
|
const tableRef = ref()
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||||
|
const activeTab = ref('not')
|
||||||
|
|
||||||
|
// 付款记录对话框相关
|
||||||
|
const paymentDialogVisible = ref(false)
|
||||||
|
const currentReceiptId = ref<string | number>('')
|
||||||
|
|
||||||
|
// 审批弹出框相关
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([keyword], () => {
|
||||||
|
pagination.currentPage = 1
|
||||||
|
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||||
|
})
|
||||||
|
watch([activeTab], () => {
|
||||||
|
pagination.currentPage = 1
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
const params = {
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize,
|
||||||
|
payment_apply: activeTab.value,
|
||||||
|
keyword: keyword.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { records, current, size, total } = await financeService.getReceiptList(params)
|
||||||
|
tableData.value = records || []
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
const handleCurrentChange = (page: number) => {
|
||||||
|
pagination.currentPage = page
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
const handleView = () => {}
|
||||||
|
|
||||||
|
// 处理认领操作
|
||||||
|
const handleClaim = (row: any) => {
|
||||||
|
currentReceiptId.value = row.id
|
||||||
|
paymentDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理付款记录确认绑定
|
||||||
|
const handlePaymentRecordConfirm = async (paymentRecord: any) => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
id: currentReceiptId.value,
|
||||||
|
payment_apply_id: paymentRecord.id
|
||||||
|
}
|
||||||
|
|
||||||
|
await financeService.bindPaymentRecord(params)
|
||||||
|
ElMessage.success('认领成功')
|
||||||
|
getList() // 刷新列表
|
||||||
|
} catch (error) {
|
||||||
|
console.error('认领失败:', error)
|
||||||
|
ElMessage.error('认领失败,请稍后重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = () => {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
:deep(.el-tabs__nav-wrap:after){
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.stocking-page {
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.stocking-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
}
|
||||||
|
.toolbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.toolbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
// 创建收款记录 - 弹窗样式对齐设计图
|
||||||
|
.receipt-dialog {
|
||||||
|
.receipt-form {
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-demo {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// justify-content: flex-end;
|
||||||
|
// border: 1px dashed #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.avatarimg {
|
||||||
|
width: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 200px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.receipt-dialog .el-dialog__footer) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,918 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stocking-page">
|
||||||
|
<div class="stocking-toolbar boxshadow">
|
||||||
|
<div class="toolbar-left">
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
v-ripple
|
||||||
|
@click="handleCreate"
|
||||||
|
v-if="hasAuth('payment_records@add')"
|
||||||
|
>
|
||||||
|
创建付款记录
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-input
|
||||||
|
v-model="keyword"
|
||||||
|
placeholder="请输入客户名称"
|
||||||
|
clearable
|
||||||
|
style="width: 260px"
|
||||||
|
@keyup.enter="getList"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="boxshadow">
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="创建日期" prop="created_at" min-width="140" />
|
||||||
|
<ElTableColumn label="付款来源" prop="country_name" min-width="160" />
|
||||||
|
<ElTableColumn label="汇款人" prop="remitter" min-width="120" />
|
||||||
|
<ElTableColumn label="账户" prop="account_name" min-width="120" />
|
||||||
|
<ElTableColumn label="币种" prop="currency_name" min-width="120" />
|
||||||
|
<ElTableColumn label="金额" prop="amount" min-width="120" />
|
||||||
|
<ElTableColumn label="操作" fixed="right" min-width="140" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow :gutter="10" justify="center">
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('payment_records@show')"
|
||||||
|
type="primary"
|
||||||
|
underline="never"
|
||||||
|
@click="handleView(scope.row)"
|
||||||
|
style="margin-right: 8px"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 查看
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('payment_records@update')"
|
||||||
|
type="success"
|
||||||
|
underline="never"
|
||||||
|
@click="handleEdit(scope.row)"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 修改
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('payment_records@destroy')"
|
||||||
|
type="danger"
|
||||||
|
underline="never"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 删除
|
||||||
|
</el-link>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新建/编辑付款记录 - 通用弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="isEdit ? '编辑付款记录' : '创建付款记录'"
|
||||||
|
width="900px"
|
||||||
|
class="receipt-dialog"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="createFormRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="createRules"
|
||||||
|
label-width="120px"
|
||||||
|
class="receipt-form"
|
||||||
|
>
|
||||||
|
<ElRow :gutter="12" class="item-row-wrap">
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="阿里订单号/PI号">
|
||||||
|
<el-select
|
||||||
|
v-model="form.payment_apply_id"
|
||||||
|
placeholder="请选择阿里订单号/PI号"
|
||||||
|
@change="fetchOrders"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in piOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.pi_no"
|
||||||
|
:value="item.pi_no"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="备货单">
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px">
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
:disabled="!form.payment_apply_id"
|
||||||
|
@click="openOrderPicker"
|
||||||
|
>
|
||||||
|
选择备货单
|
||||||
|
</ElButton>
|
||||||
|
<span v-if="Array.isArray(form.stock_id) && form.stock_id.length">
|
||||||
|
已选 {{ form.stock_id.length }} 条
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- <div
|
||||||
|
v-if="selectedOrders.length"
|
||||||
|
style="margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px"
|
||||||
|
>
|
||||||
|
<el-tag
|
||||||
|
v-for="it in selectedOrders"
|
||||||
|
:key="it.stock_orders_id"
|
||||||
|
closable
|
||||||
|
@close="removeSelectedOrder(it.stock_orders_id)"
|
||||||
|
>
|
||||||
|
{{ it.order_no }}
|
||||||
|
</el-tag>
|
||||||
|
</div> -->
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="业务员">
|
||||||
|
<el-input type="hidden" v-model="form.sales_user_id" placeholder="请填写业务员" />
|
||||||
|
<el-input v-model="form.sales_user_name" placeholder="请填写业务员" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="付款公司">
|
||||||
|
<el-select v-model="form.corp_id" placeholder="请选择付款公司">
|
||||||
|
<el-option
|
||||||
|
v-for="item in corpOptions"
|
||||||
|
:key="item.item_value"
|
||||||
|
:label="item.item_label"
|
||||||
|
:value="item.item_value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="付款来源">
|
||||||
|
<el-select v-model="form.country_id" placeholder="请选择付款国家">
|
||||||
|
<el-option
|
||||||
|
v-for="item in countryOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.cn_addrs"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="汇款人">
|
||||||
|
<el-input v-model="form.remitter" placeholder="请填写汇款人" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="账户">
|
||||||
|
<el-select v-model="form.account_id" placeholder="请选择账户">
|
||||||
|
<el-option
|
||||||
|
v-for="item in accountOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.short_desc"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="币种">
|
||||||
|
<el-select
|
||||||
|
v-model="form.currency_id"
|
||||||
|
placeholder="请选择币种"
|
||||||
|
@change="fetchExchangeRate"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in currencyOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.currency_name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="汇率">
|
||||||
|
<el-input v-model="form.exchange_rate" placeholder="请填写汇率" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="总金额">
|
||||||
|
<el-input v-model="form.amount" placeholder="请填写总金额" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="汇款行">
|
||||||
|
<el-input v-model="form.swift" placeholder="请填写SWIFT号" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="客户付款水单">
|
||||||
|
<el-upload
|
||||||
|
class="upload-demo"
|
||||||
|
:action="actionImageUplode"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:on-success="handleUploadSuccess"
|
||||||
|
:show-file-list="false"
|
||||||
|
:multiple="true"
|
||||||
|
>
|
||||||
|
<img :src="imageUrl1" alt="" class="avatarimg" />
|
||||||
|
<input type="hidden" v-model="form.voucher_file" />
|
||||||
|
</el-upload>
|
||||||
|
<div
|
||||||
|
v-if="Array.isArray(form.voucher_file_list) && form.voucher_file_list.length"
|
||||||
|
style="margin-top: 8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(u, i) in form.voucher_file_list"
|
||||||
|
:key="i"
|
||||||
|
style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test((u || '').split('?')[0])"
|
||||||
|
:src="u"
|
||||||
|
style="
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
:href="u"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
"
|
||||||
|
>{{ (u || '').split('?')[0].split('/').pop() }}</a
|
||||||
|
>
|
||||||
|
<el-button link type="danger" @click="removeVoucher(i)" style="width: 80px"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="入账资料提交">
|
||||||
|
<el-upload
|
||||||
|
class="upload-demo"
|
||||||
|
:action="actionImageUplode"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:on-success="handleUploadSuccess1"
|
||||||
|
:show-file-list="false"
|
||||||
|
:multiple="true"
|
||||||
|
>
|
||||||
|
<img :src="imageUrl1" alt="" class="avatarimg" />
|
||||||
|
<input type="hidden" v-model="form.submit_files" />
|
||||||
|
</el-upload>
|
||||||
|
<div
|
||||||
|
v-if="Array.isArray(form.submit_files_list) && form.submit_files_list.length"
|
||||||
|
style="margin-top: 8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(u, i) in form.submit_files_list"
|
||||||
|
:key="i"
|
||||||
|
style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test((u || '').split('?')[0])"
|
||||||
|
:src="u"
|
||||||
|
style="
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
:href="u"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
"
|
||||||
|
>{{ (u || '').split('?')[0].split('/').pop() }}</a
|
||||||
|
>
|
||||||
|
<el-button link type="danger" @click="removeSubmit(i)" style="width: 80px"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 选择备货单弹窗 -->
|
||||||
|
<el-dialog v-model="orderPicker.visible" title="选择备货单" width="800px" align-center>
|
||||||
|
<ArtTable :data="orderPicker.data" :loading="orderPicker.loading">
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn width="56" align="center">
|
||||||
|
<template #header>
|
||||||
|
<el-checkbox
|
||||||
|
:indeterminate="isOrderIndeterminate"
|
||||||
|
:model-value="isAllOrdersSelected"
|
||||||
|
@change="toggleSelectAllOrders"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-checkbox
|
||||||
|
:model-value="isOrderSelected(scope.row)"
|
||||||
|
@change="() => toggleOrder(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="备货单号" prop="order_no" min-width="160" />
|
||||||
|
<ElTableColumn label="业务员" prop="salesperson_snapshot" min-width="160" />
|
||||||
|
<ElTableColumn label="创建时间" prop="biz_date" min-width="160" />
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
<template #footer>
|
||||||
|
<ElButton type="primary" @click="orderPicker.visible = false">关闭</ElButton>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 付款记录详情查看对话框 -->
|
||||||
|
<PaymentRecordDetailDialog
|
||||||
|
v-model="detailDialogVisible"
|
||||||
|
:payment-id="currentPaymentId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts"></script>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { commonService } from '@/api/commonApi'
|
||||||
|
import { financeService } from '@/api/admin/finance'
|
||||||
|
import { UserService } from '@/api/usersApi'
|
||||||
|
import PaymentRecordDetailDialog from '@/components/custom/PaymentRecordDetailDialog.vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { purchaseService } from '@/api/admin/procurement'
|
||||||
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
import imageUrl1 from '@/assets/img/crm/upimg.png'
|
||||||
|
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||||
|
const { uploadHeaders } = useUploadHeaders()
|
||||||
|
let actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload?scene=payment_records`
|
||||||
|
defineOptions({ name: 'AdminReceiptRecords' })
|
||||||
|
const { hasAuth } = useAuth()
|
||||||
|
const loading = ref(false)
|
||||||
|
const keyword = ref('')
|
||||||
|
const tableRef = ref()
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||||
|
const piOptions = ref<any>()
|
||||||
|
const orderOptions = ref<any>()
|
||||||
|
const loadOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await purchaseService.purchaseorderpredata({ scene: 'pi_no' })
|
||||||
|
piOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
piOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fetchOrders = async (pi_no: string) => {
|
||||||
|
try {
|
||||||
|
const res = await purchaseService.purchaseorderpredata({
|
||||||
|
scene: 'order_no',
|
||||||
|
pi_no: pi_no
|
||||||
|
})
|
||||||
|
orderOptions.value = res || []
|
||||||
|
// 切换 PI 后,清空已选备货单与业务员信息
|
||||||
|
form.value.stock_id = []
|
||||||
|
form.value.sales_user_name = ''
|
||||||
|
form.value.sales_user_id = ''
|
||||||
|
} catch {
|
||||||
|
orderOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//备货单选择器(多选)
|
||||||
|
const orderPicker = reactive({ visible: false, loading: false, data: [] as any[] })
|
||||||
|
// const selectedOrders = computed<any[]>(() => {
|
||||||
|
// const ids = new Set((form.value.stock_id || []).map((v) => String(v)))
|
||||||
|
// const source = Array.isArray(orderOptions.value) ? orderOptions.value : []
|
||||||
|
// return source.filter((it: any) => ids.has(String(it.stock_orders_id)))
|
||||||
|
// })
|
||||||
|
const isAllOrdersSelected = computed<boolean>(() => {
|
||||||
|
const data = Array.isArray(orderPicker.data) ? orderPicker.data : []
|
||||||
|
if (!data.length) return false
|
||||||
|
const ids = new Set((form.value.stock_id || []).map((v) => String(v)))
|
||||||
|
return data.every((it: any) => ids.has(String(it.stock_orders_id)))
|
||||||
|
})
|
||||||
|
const isOrderIndeterminate = computed<boolean>(() => {
|
||||||
|
const data = Array.isArray(orderPicker.data) ? orderPicker.data : []
|
||||||
|
const selected = (form.value.stock_id || []).length
|
||||||
|
return selected > 0 && selected < data.length
|
||||||
|
})
|
||||||
|
function openOrderPicker() {
|
||||||
|
if (!form.value.payment_apply_id) return
|
||||||
|
orderPicker.visible = true
|
||||||
|
// 如果未加载,则用现有 orderOptions;如需远程可在此拉取
|
||||||
|
orderPicker.data = Array.isArray(orderOptions.value) ? orderOptions.value : []
|
||||||
|
}
|
||||||
|
function isOrderSelected(row: any) {
|
||||||
|
return (form.value.stock_id || []).some((id) => String(id) === String(row?.stock_orders_id))
|
||||||
|
}
|
||||||
|
function toggleSelectAllOrders() {
|
||||||
|
const data = Array.isArray(orderPicker.data) ? orderPicker.data : []
|
||||||
|
if (!data.length) return
|
||||||
|
if (isAllOrdersSelected.value) {
|
||||||
|
// 取消全选
|
||||||
|
const dataIds = new Set(data.map((d: any) => String(d.stock_orders_id)))
|
||||||
|
form.value.stock_id = (form.value.stock_id || []).filter((id) => !dataIds.has(String(id)))
|
||||||
|
} else {
|
||||||
|
// 全选
|
||||||
|
const existed = new Set((form.value.stock_id || []).map((v) => String(v)))
|
||||||
|
const merge = [...(form.value.stock_id || [])]
|
||||||
|
data.forEach((d: any) => {
|
||||||
|
const id = d?.stock_orders_id
|
||||||
|
if (id != null && !existed.has(String(id))) merge.push(id)
|
||||||
|
})
|
||||||
|
form.value.stock_id = merge
|
||||||
|
if (!form.value.sales_user_id && data.length) {
|
||||||
|
form.value.sales_user_name = data[0]?.salesperson_snapshot || ''
|
||||||
|
form.value.sales_user_id = data[0]?.salesperson_id || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(form.value.stock_id || []).length) {
|
||||||
|
form.value.sales_user_name = ''
|
||||||
|
form.value.sales_user_id = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleOrder(row: any) {
|
||||||
|
const ids = Array.isArray(form.value.stock_id) ? [...form.value.stock_id] : []
|
||||||
|
const id = row?.stock_orders_id
|
||||||
|
if (id == null) return
|
||||||
|
const idx = ids.findIndex((v) => String(v) === String(id))
|
||||||
|
if (idx >= 0) {
|
||||||
|
ids.splice(idx, 1)
|
||||||
|
} else {
|
||||||
|
ids.push(id)
|
||||||
|
}
|
||||||
|
form.value.stock_id = ids
|
||||||
|
// 同步一次业务员(使用第一个所选的业务员信息)
|
||||||
|
if (!form.value.sales_user_id && ids.length) {
|
||||||
|
form.value.sales_user_name = row?.salesperson_snapshot || ''
|
||||||
|
form.value.sales_user_id = row?.salesperson_id || ''
|
||||||
|
}
|
||||||
|
if (!ids.length) {
|
||||||
|
form.value.sales_user_name = ''
|
||||||
|
form.value.sales_user_id = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function removeSelectedOrder(stock_orders_id: string | number) {
|
||||||
|
const next = (form.value.stock_id || []).filter((v) => String(v) !== String(stock_orders_id))
|
||||||
|
form.value.stock_id = next
|
||||||
|
if (next.length === 0) {
|
||||||
|
form.value.sales_user_name = ''
|
||||||
|
form.value.sales_user_id = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//国家
|
||||||
|
const countryOptions = ref<any[]>([])
|
||||||
|
const fetchCountryOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getCountrySelect()
|
||||||
|
res.forEach((item: any) => {
|
||||||
|
item.cn_addrs = item.cn_addr + '(' + item.en_addr + ')'
|
||||||
|
})
|
||||||
|
countryOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
countryOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//付款公司
|
||||||
|
const corpOptions = ref<any[]>([])
|
||||||
|
const fetchCorpOptions = async () => {
|
||||||
|
try {
|
||||||
|
const response = await commonService.getDictSelect({ scope: '21' })
|
||||||
|
corpOptions.value = response.payment_corp
|
||||||
|
} catch {
|
||||||
|
corpOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//账户
|
||||||
|
const accountOptions = ref<any[]>([])
|
||||||
|
const fetchAccountOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getAccountSelect()
|
||||||
|
accountOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
accountOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//币种
|
||||||
|
const currencyOptions = ref<any[]>([])
|
||||||
|
const fetchCurrencyOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getCurrencySelect()
|
||||||
|
currencyOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
currencyOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fetchExchangeRate = async (currency_id: string) => {
|
||||||
|
try {
|
||||||
|
const list = Array.isArray(currencyOptions.value) ? currencyOptions.value : []
|
||||||
|
const picked = list.find((it: any) => String(it?.id ?? '') === String(currency_id))
|
||||||
|
if (!picked) {
|
||||||
|
form.value.exchange_rate = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
form.value.exchange_rate = picked?.exchange_rate || ''
|
||||||
|
} catch {
|
||||||
|
form.value.exchange_rate = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审批弹出框相关
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([keyword], () => {
|
||||||
|
pagination.currentPage = 1
|
||||||
|
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||||
|
})
|
||||||
|
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
const params = {
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize,
|
||||||
|
scene: 'todo',
|
||||||
|
keyword: keyword.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { records, current, size, total } = await financeService.getPaymentList(params)
|
||||||
|
tableData.value = records || []
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
const handleCurrentChange = (page: number) => {
|
||||||
|
pagination.currentPage = page
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建/编辑弹窗通用状态
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const createLoading = ref(false)
|
||||||
|
const isEdit = ref(false)
|
||||||
|
const currentId = ref<string | number | null>(null)
|
||||||
|
|
||||||
|
// 详情对话框相关
|
||||||
|
const detailDialogVisible = ref(false)
|
||||||
|
const currentPaymentId = ref<string | number>('')
|
||||||
|
const createFormRef = ref<FormInstance>()
|
||||||
|
const form = ref({
|
||||||
|
payment_apply_id: '',
|
||||||
|
stock_id: [] as (string | number)[],
|
||||||
|
sales_user_id: '',
|
||||||
|
sales_user_name: '',
|
||||||
|
corp_id: '',
|
||||||
|
country_id: '',
|
||||||
|
remitter: '',
|
||||||
|
account_id: '',
|
||||||
|
currency_id: '',
|
||||||
|
exchange_rate: '',
|
||||||
|
amount: '',
|
||||||
|
swift: '',
|
||||||
|
voucher_file: [] as string[],
|
||||||
|
voucher_file_list: [] as string[],
|
||||||
|
submit_files: [] as object[],
|
||||||
|
submit_files_list: [] as string[]
|
||||||
|
})
|
||||||
|
const createRules: FormRules = {
|
||||||
|
payment_apply_id: [{ required: true, message: '请选择阿里订单号/PI号', trigger: 'blur' }],
|
||||||
|
sales_user_id: [{ required: true, message: '请选择业务员', trigger: 'blur' }],
|
||||||
|
corp_id: [{ required: true, message: '请选择付款公司', trigger: 'blur' }],
|
||||||
|
country_id: [{ required: true, message: '请选择付款国家', trigger: 'blur' }],
|
||||||
|
remitter: [{ required: true, message: '请输入汇款人', trigger: 'blur' }],
|
||||||
|
account_id: [{ required: true, message: '请选择账户', trigger: 'blur' }],
|
||||||
|
currency_id: [{ required: true, message: '请选择币种', trigger: 'blur' }],
|
||||||
|
exchange_rate: [{ required: true, message: '请输入汇率', trigger: 'blur' }],
|
||||||
|
amount: [{ required: true, message: '请输入金额', trigger: 'blur' }],
|
||||||
|
swift: [{ required: true, message: '请输入汇款行', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetCreateForm = () => {
|
||||||
|
Object.assign(form.value, {
|
||||||
|
payment_apply_id: '',
|
||||||
|
stock_id: [],
|
||||||
|
sales_user_id: '',
|
||||||
|
sales_user_name: '',
|
||||||
|
corp_id: '',
|
||||||
|
country_id: '',
|
||||||
|
remitter: '',
|
||||||
|
account_id: '',
|
||||||
|
currency_id: '',
|
||||||
|
exchange_rate: '',
|
||||||
|
amount: '',
|
||||||
|
swift: '',
|
||||||
|
voucher_file: [],
|
||||||
|
voucher_file_list: [],
|
||||||
|
submit_files: [],
|
||||||
|
submit_files_list: []
|
||||||
|
})
|
||||||
|
currentId.value = null
|
||||||
|
createFormRef.value?.clearValidate?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreate = async () => {
|
||||||
|
resetCreateForm()
|
||||||
|
isEdit.value = false
|
||||||
|
loadOptions()
|
||||||
|
fetchAccountOptions()
|
||||||
|
fetchCurrencyOptions()
|
||||||
|
fetchCountryOptions()
|
||||||
|
fetchCorpOptions()
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
createFormRef.value?.validate?.(async (valid: boolean) => {
|
||||||
|
if (!valid) return
|
||||||
|
try {
|
||||||
|
createLoading.value = true
|
||||||
|
// 根据新增/编辑分支处理
|
||||||
|
const payload: any = { ...form.value }
|
||||||
|
delete payload.submit_files_list
|
||||||
|
delete payload.voucher_file_list
|
||||||
|
delete payload.sales_user_name
|
||||||
|
payload.voucher_file = payload.voucher_file.join(',')
|
||||||
|
// 将所选备货单 ID 列表传给后端字段(兼容旧字段)
|
||||||
|
if (Array.isArray(payload.stock_id)) {
|
||||||
|
// 若后端仍接收单个 stock_id,可取第一个;否则保留 stock_id
|
||||||
|
payload.stock_id = payload.stock_id ?? payload.stock_id[0]
|
||||||
|
}
|
||||||
|
payload.stock = [
|
||||||
|
// 库存数组
|
||||||
|
{
|
||||||
|
stock_id: payload.stock_id, // 备货单ID
|
||||||
|
pi_on: payload.payment_apply_id
|
||||||
|
}
|
||||||
|
]
|
||||||
|
delete payload.payment_apply_id
|
||||||
|
delete payload.stock_id
|
||||||
|
if (isEdit.value) {
|
||||||
|
const forms = { ...payload, id: currentId.value }
|
||||||
|
const { message } = await financeService.updatePayment(forms)
|
||||||
|
ElMessage.success(message)
|
||||||
|
} else {
|
||||||
|
// console.log('payload:', payload)
|
||||||
|
const { message } = await financeService.addPayment(payload)
|
||||||
|
ElMessage.success(message)
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
getList()
|
||||||
|
} finally {
|
||||||
|
createLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleView = (row: any) => {
|
||||||
|
currentPaymentId.value = row.id
|
||||||
|
detailDialogVisible.value = true
|
||||||
|
}
|
||||||
|
const handleEdit = async (row?: any) => {
|
||||||
|
resetCreateForm()
|
||||||
|
isEdit.value = true
|
||||||
|
currentId.value = row?.id ?? null
|
||||||
|
// 如有需要,这里可按接口字段回填表单
|
||||||
|
const data = await financeService.getPaymentDetail({ id: row.id })
|
||||||
|
row = data || row
|
||||||
|
if (row && typeof row === 'object') {
|
||||||
|
const stockList = Array.isArray(row.stock) ? row.stock : []
|
||||||
|
const firstStock = stockList[0] || {}
|
||||||
|
const piNo = firstStock?.pi_no || row?.payment_apply_id || row?.pi_no || ''
|
||||||
|
form.value.payment_apply_id = piNo || form.value.payment_apply_id
|
||||||
|
// 组装已选备货单ID数组
|
||||||
|
const pickedIds = stockList
|
||||||
|
.map((s: any) => s?.stock_id || s?.stock_orders_id || s?.id)
|
||||||
|
.filter((v: any) => v != null)
|
||||||
|
if (pickedIds.length) {
|
||||||
|
form.value.stock_id = pickedIds
|
||||||
|
} else if (row?.stock_id) {
|
||||||
|
form.value.stock_id = [row.stock_id]
|
||||||
|
}
|
||||||
|
form.value.sales_user_id = row.sales_user_id ?? form.value.sales_user_id
|
||||||
|
form.value.sales_user_name = row.sales_user_name ?? form.value.sales_user_name
|
||||||
|
form.value.corp_id = String(row.corp_id ?? '')
|
||||||
|
form.value.country_id = row.country_id ?? form.value.country_id
|
||||||
|
form.value.remitter = row.remitter ?? form.value.remitter
|
||||||
|
form.value.account_id = row.account_id ?? form.value.account_id
|
||||||
|
form.value.currency_id = row.currency_id ?? form.value.currency_id
|
||||||
|
form.value.exchange_rate = row.exchange_rate ?? form.value.exchange_rate
|
||||||
|
form.value.amount = row.amount ?? form.value.amount
|
||||||
|
form.value.swift = row.swift ?? form.value.swift
|
||||||
|
// 处理客户付款水单文件
|
||||||
|
if (row.voucher_file) {
|
||||||
|
const voucherFiles = Array.isArray(row.voucher_file)
|
||||||
|
? row.voucher_file
|
||||||
|
: String(row.voucher_file)
|
||||||
|
.split(',')
|
||||||
|
.map((s: string) => s.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
form.value.voucher_file = voucherFiles
|
||||||
|
// 构造预览URL列表(假设文件路径需要拼接域名)
|
||||||
|
const baseUrl = import.meta.env.VITE_API_URL || ''
|
||||||
|
form.value.voucher_file_list = voucherFiles.map((file: string) =>
|
||||||
|
file.startsWith('http') ? file : `${baseUrl}/${file}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 处理入账资料提交文件
|
||||||
|
if (row.submit_files) {
|
||||||
|
const submitFiles = row.submit_files
|
||||||
|
form.value.submit_files = submitFiles
|
||||||
|
// 构造预览URL列表
|
||||||
|
const baseUrl = import.meta.env.VITE_API_URL || ''
|
||||||
|
form.value.submit_files_list = submitFiles.map((file: any) => file.file_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadOptions()
|
||||||
|
fetchAccountOptions()
|
||||||
|
fetchCurrencyOptions()
|
||||||
|
fetchCountryOptions()
|
||||||
|
fetchCorpOptions()
|
||||||
|
// 拉取当前 PI 的备货单列表用于弹窗展示与勾选回显
|
||||||
|
try {
|
||||||
|
const res = await purchaseService.purchaseorderpredata({
|
||||||
|
scene: 'order_no',
|
||||||
|
pi_no: form.value.payment_apply_id
|
||||||
|
})
|
||||||
|
orderOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
orderOptions.value = []
|
||||||
|
}
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
const handleDelete = (row: { id: any }) => {
|
||||||
|
ElMessageBox.confirm('确定删除吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
financeService.deletePayment({ id: row.id }).then((res) => {
|
||||||
|
ElMessage.success(res.message)
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function handleUploadSuccess(response: any) {
|
||||||
|
const fileName = response?.data?.file_name || ''
|
||||||
|
const fileUrl = response?.data?.file_url || response?.data?.full_url || response?.url || ''
|
||||||
|
const names = Array.isArray(form.value.voucher_file) ? [...form.value.voucher_file] : []
|
||||||
|
if (fileName) names.push(fileName)
|
||||||
|
form.value.voucher_file = names
|
||||||
|
const list = Array.isArray(form.value.voucher_file_list) ? form.value.voucher_file_list : []
|
||||||
|
list.push(fileUrl)
|
||||||
|
form.value.voucher_file_list = [...list]
|
||||||
|
ElMessage.success(response.message)
|
||||||
|
}
|
||||||
|
function handleUploadSuccess1(response: any) {
|
||||||
|
const fileName = response?.data?.file_name || ''
|
||||||
|
const fileUrl = response?.data?.file_url || response?.data?.full_url || response?.url || ''
|
||||||
|
const names = Array.isArray(form.value.submit_files) ? [...form.value.submit_files] : []
|
||||||
|
const files = ref({
|
||||||
|
file_src: '',
|
||||||
|
file_name: ''
|
||||||
|
})
|
||||||
|
files.value.file_src = fileName
|
||||||
|
files.value.file_name = response?.data?.original_name || ''
|
||||||
|
if (fileName) names.push(files.value)
|
||||||
|
form.value.submit_files = names
|
||||||
|
const list = Array.isArray(form.value.submit_files_list) ? form.value.submit_files_list : []
|
||||||
|
list.push(fileUrl)
|
||||||
|
form.value.submit_files_list = [...list]
|
||||||
|
ElMessage.success(response.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预览项移除(同步预览数组与提交字段)
|
||||||
|
function removeVoucher(index: number) {
|
||||||
|
const list = Array.isArray(form.value.voucher_file_list)
|
||||||
|
? [...form.value.voucher_file_list]
|
||||||
|
: []
|
||||||
|
if (index < 0 || index >= list.length) return
|
||||||
|
list.splice(index, 1)
|
||||||
|
form.value.voucher_file_list = list
|
||||||
|
const names = Array.isArray(form.value.voucher_file) ? [...form.value.voucher_file] : []
|
||||||
|
if (index < names.length) names.splice(index, 1)
|
||||||
|
form.value.voucher_file = names
|
||||||
|
}
|
||||||
|
function removeSubmit(index: number) {
|
||||||
|
const list = Array.isArray(form.value.submit_files_list)
|
||||||
|
? [...form.value.submit_files_list]
|
||||||
|
: []
|
||||||
|
if (index < 0 || index >= list.length) return
|
||||||
|
list.splice(index, 1)
|
||||||
|
form.value.submit_files_list = list
|
||||||
|
const names = Array.isArray(form.value.submit_files) ? [...form.value.submit_files] : []
|
||||||
|
if (index < names.length) names.splice(index, 1)
|
||||||
|
form.value.submit_files = names
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.stocking-page {
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.stocking-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
}
|
||||||
|
.toolbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.toolbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
// 创建收款记录 - 弹窗样式对齐设计图
|
||||||
|
.receipt-dialog {
|
||||||
|
.receipt-form {
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-demo {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.avatarimg {
|
||||||
|
width: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 200px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.receipt-dialog .el-dialog__footer) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,710 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stocking-page">
|
||||||
|
<div class="stocking-toolbar boxshadow">
|
||||||
|
<div class="toolbar-left">
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
v-ripple
|
||||||
|
@click="handleCreate"
|
||||||
|
v-if="hasAuth('receipt_records@add')"
|
||||||
|
>
|
||||||
|
创建收款记录
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-input
|
||||||
|
v-model="keyword"
|
||||||
|
placeholder="请输入客户名称"
|
||||||
|
clearable
|
||||||
|
style="width: 260px"
|
||||||
|
@keyup.enter="getList"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="boxshadow">
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="创建日期" prop="created_at" min-width="140" />
|
||||||
|
<ElTableColumn label="付款来源" prop="country_name" min-width="160" />
|
||||||
|
<ElTableColumn label="汇款人" prop="remitter" min-width="120" />
|
||||||
|
<ElTableColumn label="账户" prop="account_name" min-width="120" />
|
||||||
|
<ElTableColumn label="币种" prop="currency_name" min-width="120" />
|
||||||
|
<ElTableColumn label="金额" prop="amount" min-width="120" />
|
||||||
|
<ElTableColumn label="折让金额" prop="discount_amount" min-width="120" />
|
||||||
|
<ElTableColumn label="入账" prop="id" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<span v-if="scope.row.received_at">{{ scope.row.received_at }}</span>
|
||||||
|
<el-button v-else type="primary" size="small" @click="handlebtn">确认入账</el-button>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="操作" fixed="right" min-width="140" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow :gutter="10" justify="center">
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('receipt_records@show')"
|
||||||
|
type="primary"
|
||||||
|
underline="never"
|
||||||
|
@click="handleView(scope.row)"
|
||||||
|
style="margin-right: 8px"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 查看
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('receipt_records@update')"
|
||||||
|
type="success"
|
||||||
|
underline="never"
|
||||||
|
@click="handleEdit(scope.row)"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 修改
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-if="hasAuth('receipt_records@destroy')"
|
||||||
|
type="danger"
|
||||||
|
underline="never"
|
||||||
|
@click="handleDelete()"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i> 删除
|
||||||
|
</el-link>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新建/编辑收款记录 - 通用弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="isEdit ? '编辑收款记录' : '创建收款记录'"
|
||||||
|
width="900px"
|
||||||
|
class="receipt-dialog"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="createFormRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="createRules"
|
||||||
|
label-width="180px"
|
||||||
|
class="receipt-form"
|
||||||
|
>
|
||||||
|
<ElRow :gutter="12" class="item-row-wrap">
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="付款来源">
|
||||||
|
<el-select v-model="form.country_id" placeholder="请选择付款国家">
|
||||||
|
<el-option
|
||||||
|
v-for="item in countryOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.cn_addrs"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="汇款人">
|
||||||
|
<el-input v-model="form.remitter" placeholder="请填写汇款人" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="账户">
|
||||||
|
<el-select v-model="form.account_id" placeholder="请选择账户">
|
||||||
|
<el-option
|
||||||
|
v-for="item in accountOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.short_desc"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="币种">
|
||||||
|
<el-select v-model="form.currency_id" placeholder="请选择币种">
|
||||||
|
<el-option
|
||||||
|
v-for="item in currencyOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.currency_name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="金额">
|
||||||
|
<el-input v-model="form.amount" placeholder="请填写金额" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="到账时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.arrived_at"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
type="date"
|
||||||
|
placeholder="请选择到账时间"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="折让金额">
|
||||||
|
<el-input v-model="form.discount_amount" placeholder="请填写折让金额" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="收汇凭证号">
|
||||||
|
<el-input v-model="form.voucher_no" placeholder="请填写收汇凭证号" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="实际汇率(出纳)">
|
||||||
|
<el-input v-model="form.exchange_rate" placeholder="请填写实际汇率" />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="总金额(人民币)实际汇率">
|
||||||
|
<el-input
|
||||||
|
v-model="form.total_amount_cny"
|
||||||
|
placeholder="请填写总金额(人民币)实际汇率"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="是否转回内地">
|
||||||
|
<el-radio-group v-model="form.is_domestic_return">
|
||||||
|
<el-radio :label="0">否</el-radio>
|
||||||
|
<el-radio :label="1">是</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="外汇到账回单(出纳)">
|
||||||
|
<el-upload
|
||||||
|
class="upload-demo"
|
||||||
|
:action="actionImageUplode"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:on-success="handleUploadSuccess1"
|
||||||
|
:show-file-list="false"
|
||||||
|
:multiple="true"
|
||||||
|
>
|
||||||
|
<img :src="imageUrl1" alt="" class="avatarimg" />
|
||||||
|
<input type="hidden" v-model="form.fx_receipt_file" />
|
||||||
|
</el-upload>
|
||||||
|
<div
|
||||||
|
v-if="Array.isArray(form.fx_receipt_file_list) && form.fx_receipt_file_list.length"
|
||||||
|
style="margin-top: 8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(u, i) in form.fx_receipt_file_list"
|
||||||
|
:key="i"
|
||||||
|
style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test((u || '').split('?')[0])"
|
||||||
|
:src="u"
|
||||||
|
style="
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
:href="u"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
"
|
||||||
|
>{{ (u || '').split('?')[0].split('/').pop() }}</a
|
||||||
|
>
|
||||||
|
<el-button link type="danger" @click="removeVoucher(i)" style="width: 80px"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisibleshow"
|
||||||
|
title="查看收款记录"
|
||||||
|
width="900px"
|
||||||
|
class="receipt-dialog"
|
||||||
|
>
|
||||||
|
<el-form ref="createFormRef" :model="formshow" label-width="180px" class="receipt-form">
|
||||||
|
<ElRow :gutter="12" class="item-row-wrap">
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="付款来源">
|
||||||
|
<el-input v-model="formshow.country_name" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="汇款人">
|
||||||
|
<el-input v-model="formshow.remitter" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="账户">
|
||||||
|
<el-input v-model="formshow.account_name" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="币种">
|
||||||
|
<el-input v-model="formshow.currency_name" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="金额">
|
||||||
|
<el-input v-model="formshow.amount" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="到账时间">
|
||||||
|
<el-input v-model="formshow.arrived_at" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="折让金额">
|
||||||
|
<el-input v-model="formshow.discount_amount" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="收汇凭证号">
|
||||||
|
<el-input v-model="formshow.voucher_no" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="实际汇率(出纳)">
|
||||||
|
<el-input v-model="formshow.exchange_rate" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="总金额(人民币)实际汇率">
|
||||||
|
<el-input v-model="formshow.total_amount_cny" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="是否转回内地">
|
||||||
|
<el-radio-group v-model="formshow.is_domestic_return" disabled>
|
||||||
|
<el-radio :label="0">否</el-radio>
|
||||||
|
<el-radio :label="1">是</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :sm="24" :md="12" :lg="12">
|
||||||
|
<el-form-item label="外汇到账回单(出纳)">
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
Array.isArray(formshow.fx_receipt_file_list) &&
|
||||||
|
formshow.fx_receipt_file_list.length
|
||||||
|
"
|
||||||
|
style="margin-top: 8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(u, i) in formshow.fx_receipt_file_list"
|
||||||
|
:key="i"
|
||||||
|
style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test((u || '').split('?')[0])"
|
||||||
|
:src="u"
|
||||||
|
style="
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
:href="u"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
"
|
||||||
|
>{{ (u || '').split('?')[0].split('/').pop() }}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { commonService } from '@/api/commonApi'
|
||||||
|
import { financeService } from '@/api/admin/finance'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
import imageUrl1 from '@/assets/img/crm/upimg.png'
|
||||||
|
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||||
|
const { uploadHeaders } = useUploadHeaders()
|
||||||
|
let actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload?scene=receipt_records`
|
||||||
|
defineOptions({ name: 'AdminReceiptRecords' })
|
||||||
|
const { hasAuth } = useAuth()
|
||||||
|
const loading = ref(false)
|
||||||
|
const dialogVisibleshow = ref(false)
|
||||||
|
const keyword = ref('')
|
||||||
|
const tableRef = ref()
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||||
|
//国家
|
||||||
|
const countryOptions = ref<any[]>([])
|
||||||
|
const fetchCountryOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getCountrySelect()
|
||||||
|
res.forEach((item: any) => {
|
||||||
|
item.cn_addrs = item.cn_addr + '(' + item.en_addr + ')'
|
||||||
|
})
|
||||||
|
countryOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
countryOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//账户
|
||||||
|
const accountOptions = ref<any[]>([])
|
||||||
|
const fetchAccountOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getAccountSelect()
|
||||||
|
accountOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
accountOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//币种
|
||||||
|
const currencyOptions = ref<any[]>([])
|
||||||
|
const fetchCurrencyOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await commonService.getCurrencySelect()
|
||||||
|
currencyOptions.value = res || []
|
||||||
|
} catch {
|
||||||
|
currencyOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审批弹出框相关
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([keyword], () => {
|
||||||
|
pagination.currentPage = 1
|
||||||
|
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||||
|
})
|
||||||
|
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
const params = {
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize,
|
||||||
|
keyword: keyword.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { records, current, size, total } = await financeService.getReceiptList(params)
|
||||||
|
tableData.value = records || []
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
const handleCurrentChange = (page: number) => {
|
||||||
|
pagination.currentPage = page
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建/编辑弹窗通用状态
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const createLoading = ref(false)
|
||||||
|
const isEdit = ref(false)
|
||||||
|
const currentId = ref<string | number | null>(null)
|
||||||
|
const createFormRef = ref<FormInstance>()
|
||||||
|
const form = ref({
|
||||||
|
country_id: '',
|
||||||
|
remitter: '',
|
||||||
|
account_id: '',
|
||||||
|
currency_id: '',
|
||||||
|
amount: '',
|
||||||
|
arrived_at: new Date().toISOString().split('T')[0],
|
||||||
|
discount_amount: '',
|
||||||
|
voucher_no: '',
|
||||||
|
total_amount_cny: '',
|
||||||
|
exchange_rate: '',
|
||||||
|
is_domestic_return: 0,
|
||||||
|
fx_receipt_file: '',
|
||||||
|
fx_receipt_file_list: [] as string[]
|
||||||
|
})
|
||||||
|
const createRules: FormRules = {
|
||||||
|
country_id: [{ required: true, message: '请选择付款来源', trigger: 'change' }],
|
||||||
|
remitter: [{ required: true, message: '请输入汇款人', trigger: 'blur' }],
|
||||||
|
account_id: [{ required: true, message: '请选择账户', trigger: 'change' }],
|
||||||
|
currency_id: [{ required: true, message: '请选择币种', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
const formshow = ref({
|
||||||
|
country_name: '',
|
||||||
|
remitter: '',
|
||||||
|
account_name: '',
|
||||||
|
currency_name: '',
|
||||||
|
amount: '',
|
||||||
|
arrived_at: '',
|
||||||
|
discount_amount: '',
|
||||||
|
voucher_no: '',
|
||||||
|
total_amount_cny: '',
|
||||||
|
exchange_rate: '',
|
||||||
|
is_domestic_return: 0,
|
||||||
|
fx_receipt_file: '',
|
||||||
|
fx_receipt_file_list: [] as string[]
|
||||||
|
})
|
||||||
|
const resetCreateForm = () => {
|
||||||
|
Object.assign(form.value, {
|
||||||
|
country_id: '',
|
||||||
|
remitter: '',
|
||||||
|
account_id: '',
|
||||||
|
currency_id: '',
|
||||||
|
amount: '',
|
||||||
|
arrived_at: new Date().toISOString().split('T')[0],
|
||||||
|
discount_amount: '',
|
||||||
|
voucher_no: '',
|
||||||
|
total_amount_cny: '',
|
||||||
|
exchange_rate: '',
|
||||||
|
is_domestic_return: 0,
|
||||||
|
fx_receipt_file: '',
|
||||||
|
fx_receipt_file_list: []
|
||||||
|
})
|
||||||
|
currentId.value = null
|
||||||
|
createFormRef.value?.clearValidate?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreate = async () => {
|
||||||
|
resetCreateForm()
|
||||||
|
isEdit.value = false
|
||||||
|
fetchAccountOptions()
|
||||||
|
fetchCurrencyOptions()
|
||||||
|
fetchCountryOptions()
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
createFormRef.value?.validate?.(async (valid: boolean) => {
|
||||||
|
if (!valid) return
|
||||||
|
try {
|
||||||
|
createLoading.value = true
|
||||||
|
// TODO: 根据新增/编辑调用对应接口
|
||||||
|
if (isEdit.value) {
|
||||||
|
const formData = { ...form.value }
|
||||||
|
if ('fx_receipt_file_list' in formData) {
|
||||||
|
delete formData.fx_receipt_file_list
|
||||||
|
}
|
||||||
|
const forms = { ...formData, id: currentId.value }
|
||||||
|
const { message } = await financeService.updateReceipt(forms)
|
||||||
|
ElMessage.success(message)
|
||||||
|
} else {
|
||||||
|
const { message } = await financeService.addReceipt(form.value)
|
||||||
|
ElMessage.success(message)
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
getList()
|
||||||
|
} finally {
|
||||||
|
createLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleView = (row?: any) => {
|
||||||
|
const fx_receipt_file_full = []
|
||||||
|
if (row.fx_receipt_file_full) {
|
||||||
|
fx_receipt_file_full.push(row.fx_receipt_file_full)
|
||||||
|
}
|
||||||
|
formshow.value = row
|
||||||
|
formshow.value.fx_receipt_file_list = fx_receipt_file_full
|
||||||
|
dialogVisibleshow.value = true
|
||||||
|
}
|
||||||
|
const handleEdit = (row?: any) => {
|
||||||
|
resetCreateForm()
|
||||||
|
isEdit.value = true
|
||||||
|
currentId.value = row?.id ?? null
|
||||||
|
if (row && typeof row === 'object') {
|
||||||
|
form.value.country_id = row.country_id ?? form.value.country_id
|
||||||
|
form.value.remitter = row.remitter ?? form.value.remitter
|
||||||
|
form.value.account_id = row.account_id ?? form.value.account_id
|
||||||
|
form.value.currency_id = row.currency_id ?? form.value.currency_id
|
||||||
|
form.value.amount = row.amount ?? form.value.amount
|
||||||
|
form.value.arrived_at = row.arrived_at ?? form.value.arrived_at
|
||||||
|
form.value.discount_amount = row.discount_amount ?? form.value.discount_amount
|
||||||
|
form.value.voucher_no = row.voucher_no ?? form.value.voucher_no
|
||||||
|
form.value.total_amount_cny = row.total_amount_cny ?? form.value.total_amount_cny
|
||||||
|
form.value.exchange_rate = row.exchange_rate ?? form.value.exchange_rate
|
||||||
|
form.value.is_domestic_return = row.is_domestic_return ?? form.value.is_domestic_return
|
||||||
|
form.value.fx_receipt_file = row.fx_receipt_file ?? form.value.fx_receipt_file
|
||||||
|
|
||||||
|
const fx_receipt_file_full = []
|
||||||
|
if (row.fx_receipt_file_full) {
|
||||||
|
fx_receipt_file_full.push(row.fx_receipt_file_full)
|
||||||
|
}
|
||||||
|
form.value.fx_receipt_file_list = Array.isArray(fx_receipt_file_full)
|
||||||
|
? fx_receipt_file_full
|
||||||
|
: form.value.fx_receipt_file_list
|
||||||
|
}
|
||||||
|
fetchAccountOptions()
|
||||||
|
fetchCurrencyOptions()
|
||||||
|
fetchCountryOptions()
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
const handlebtn = () => {
|
||||||
|
ElMessageBox.confirm('你是否确认入账?', '入账', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
// financeService.deleteReceipt({ id: currentId.value }).then((res) => {
|
||||||
|
// ElMessage.success(res.message)
|
||||||
|
// getList()
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleDelete = () => {
|
||||||
|
ElMessageBox.confirm('确定删除吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
financeService.deleteReceipt({ id: currentId.value }).then((res) => {
|
||||||
|
ElMessage.success(res.message)
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function handleUploadSuccess1(response: any) {
|
||||||
|
const fileName = response?.data?.file_name || ''
|
||||||
|
const fileUrl = response?.data?.file_url || response?.data?.full_url || response?.url || ''
|
||||||
|
form.value.fx_receipt_file = [form.value.fx_receipt_file, fileName].filter(Boolean).join(',')
|
||||||
|
const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||||
|
? form.value.fx_receipt_file_list
|
||||||
|
: []
|
||||||
|
list.push(fileUrl)
|
||||||
|
form.value.fx_receipt_file_list = [...list]
|
||||||
|
ElMessage.success(response.message)
|
||||||
|
}
|
||||||
|
// 预览项移除(同步预览数组与提交字段)
|
||||||
|
function removeVoucher(index: number) {
|
||||||
|
const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||||
|
? [...form.value.fx_receipt_file_list]
|
||||||
|
: []
|
||||||
|
if (index < 0 || index >= list.length) return
|
||||||
|
list.splice(index, 1)
|
||||||
|
form.value.fx_receipt_file_list = list
|
||||||
|
const names = (form.value.fx_receipt_file || '').split(',').filter(Boolean)
|
||||||
|
if (index < names.length) names.splice(index, 1)
|
||||||
|
form.value.fx_receipt_file = names.join(',')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.stocking-page {
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.stocking-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--art-main-bg-color);
|
||||||
|
}
|
||||||
|
.toolbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.toolbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
// 创建收款记录 - 弹窗样式对齐设计图
|
||||||
|
.receipt-dialog {
|
||||||
|
.receipt-form {
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-demo {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// justify-content: flex-end;
|
||||||
|
// border: 1px dashed #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.avatarimg {
|
||||||
|
width: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width: 200px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.receipt-dialog .el-dialog__footer) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -36,11 +36,11 @@
|
|||||||
<div class="form">
|
<div class="form">
|
||||||
<!-- 登录方式切换 tab -->
|
<!-- 登录方式切换 tab -->
|
||||||
<div class="login-type-tabs">
|
<div class="login-type-tabs">
|
||||||
<!-- <span
|
<span
|
||||||
:class="{ active: activeLoginType === 'password' }"
|
:class="{ active: activeLoginType === 'password' }"
|
||||||
@click="activeLoginType = 'password'"
|
@click="activeLoginType = 'password'"
|
||||||
>账号密码登录</span
|
>账号密码登录</span
|
||||||
> -->
|
>
|
||||||
<span
|
<span
|
||||||
:class="{ active: activeLoginType === 'qrcode' }"
|
:class="{ active: activeLoginType === 'qrcode' }"
|
||||||
@click="activeLoginType = 'qrcode'"
|
@click="activeLoginType = 'qrcode'"
|
||||||
|
|||||||
Reference in New Issue
Block a user