|
|
|
|
@@ -164,7 +164,7 @@
|
|
|
|
|
|
|
|
|
|
<div class="transfer-list" v-loading="loading">
|
|
|
|
|
<div
|
|
|
|
|
v-for="transfer in transferHistory"
|
|
|
|
|
v-for="transfer in filteredTransferHistory"
|
|
|
|
|
:key="transfer.id"
|
|
|
|
|
class="transfer-item"
|
|
|
|
|
:class="transfer.status"
|
|
|
|
|
@@ -205,7 +205,10 @@
|
|
|
|
|
</el-image>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 确认收款操作按钮 -->
|
|
|
|
|
<div v-if="transfer.status === 'pending' && transfer.to_user_id === userStore.user.id" class="transfer-actions">
|
|
|
|
|
<div
|
|
|
|
|
v-if="transfer.status === 'pending' && transfer.to_user_id === userStore.user.id"
|
|
|
|
|
class="transfer-actions"
|
|
|
|
|
>
|
|
|
|
|
<el-button
|
|
|
|
|
type="success"
|
|
|
|
|
size="small"
|
|
|
|
|
@@ -227,8 +230,8 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="transferHistory.length === 0" class="empty-state">
|
|
|
|
|
<el-empty description="暂无转账记录" />
|
|
|
|
|
<div v-if="filteredTransferHistory.length === 0" class="empty-state">
|
|
|
|
|
<el-empty :description="statusFilter === 'pending' ? '暂无待确认的转账' : '暂无转账记录'" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@@ -324,12 +327,10 @@ onMounted(() => {
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
loadUserList()
|
|
|
|
|
|
|
|
|
|
// 添加窗口大小变化监听
|
|
|
|
|
window.addEventListener('resize', handleResize)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
// 移除窗口大小变化监听
|
|
|
|
|
window.removeEventListener('resize', handleResize)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
@@ -339,6 +340,29 @@ watch(statusFilter, () => {
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
const filteredTransferHistory = computed(() => {
|
|
|
|
|
if (!statusFilter.value) return transferHistory.value
|
|
|
|
|
|
|
|
|
|
return transferHistory.value.filter(transfer => {
|
|
|
|
|
if (statusFilter.value === 'pending') {
|
|
|
|
|
return transfer.status === 'pending' && transfer.to_user_id === userStore.user.id
|
|
|
|
|
}
|
|
|
|
|
return transfer.status === statusFilter.value
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const totalCount = computed(() => pagination.total)
|
|
|
|
|
const pendingCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'pending' && t.to_user_id === userStore.user.id).length
|
|
|
|
|
})
|
|
|
|
|
const confirmedCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'confirmed').length
|
|
|
|
|
})
|
|
|
|
|
const rejectedCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'rejected').length
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 方法
|
|
|
|
|
const loadPendingTransfers = async () => {
|
|
|
|
|
try {
|
|
|
|
|
@@ -348,7 +372,6 @@ const loadPendingTransfers = async () => {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
// 过滤出需要当前用户确认的转账记录
|
|
|
|
|
pendingTransfers.value = response.data.data.filter(
|
|
|
|
|
transfer => transfer.to_user_id === userStore.user.id && transfer.status === 'pending'
|
|
|
|
|
)
|
|
|
|
|
@@ -359,9 +382,6 @@ const loadPendingTransfers = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 加载用户待处理的分配
|
|
|
|
|
*/
|
|
|
|
|
const loadPendingAllocations = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await api.get('/matching/pending-allocations')
|
|
|
|
|
@@ -379,10 +399,8 @@ const loadTransferHistory = async () => {
|
|
|
|
|
loading.value = true
|
|
|
|
|
const params = {
|
|
|
|
|
page: pagination.page,
|
|
|
|
|
limit: pagination.limit
|
|
|
|
|
}
|
|
|
|
|
if (statusFilter.value) {
|
|
|
|
|
params.status = statusFilter.value
|
|
|
|
|
limit: pagination.limit,
|
|
|
|
|
status: statusFilter.value || undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response = await api.get(`/transfers/user/${userStore.user.id}`, { params })
|
|
|
|
|
@@ -410,9 +428,6 @@ const loadUserList = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取订单状态对应的标签类型
|
|
|
|
|
*/
|
|
|
|
|
const getOrderStatusType = (status) => {
|
|
|
|
|
const statusMap = {
|
|
|
|
|
'matching': 'warning',
|
|
|
|
|
@@ -423,9 +438,6 @@ const getOrderStatusType = (status) => {
|
|
|
|
|
return statusMap[status] || 'info'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取订单状态文本
|
|
|
|
|
*/
|
|
|
|
|
const getOrderStatusText = (status) => {
|
|
|
|
|
const statusMap = {
|
|
|
|
|
'matching': '进行中',
|
|
|
|
|
@@ -436,9 +448,6 @@ const getOrderStatusText = (status) => {
|
|
|
|
|
return statusMap[status] || '未知状态'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取转账类型文本
|
|
|
|
|
*/
|
|
|
|
|
const getTransferTypeText = (type) => {
|
|
|
|
|
const typeMap = {
|
|
|
|
|
'user_to_user': '用户转账',
|
|
|
|
|
@@ -450,146 +459,6 @@ const getTransferTypeText = (type) => {
|
|
|
|
|
return typeMap[type] || '未知类型'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const confirmTransfer = async (transferId, action) => {
|
|
|
|
|
try {
|
|
|
|
|
const actionText = action === 'confirm' ? '确认' : '拒绝'
|
|
|
|
|
await ElMessageBox.confirm(
|
|
|
|
|
`确定要${actionText}这笔转账吗?`,
|
|
|
|
|
'确认操作',
|
|
|
|
|
{
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
confirmLoading.value = true
|
|
|
|
|
const response = await api.post(`/transfers/confirm/${transferId}`, { action })
|
|
|
|
|
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
ElMessage.success(response.data.message)
|
|
|
|
|
loadPendingTransfers()
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
loadAccountInfo()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
console.error('确认转账失败:', error)
|
|
|
|
|
ElMessage.error(error.response?.data?.message || '操作失败')
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
confirmLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const submitTransfer = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const valid = await transferFormRef.value.validate()
|
|
|
|
|
if (!valid) return
|
|
|
|
|
|
|
|
|
|
submitLoading.value = true
|
|
|
|
|
|
|
|
|
|
const formData = new FormData()
|
|
|
|
|
formData.append('to_user_id', transferForm.to_user_id)
|
|
|
|
|
formData.append('amount', transferForm.amount)
|
|
|
|
|
formData.append('transfer_type', transferForm.transfer_type)
|
|
|
|
|
formData.append('description', transferForm.description)
|
|
|
|
|
|
|
|
|
|
if (transferForm.voucher) {
|
|
|
|
|
// 如果有上传的凭证,需要处理文件
|
|
|
|
|
const fileInput = uploadRef.value?.$el.querySelector('input[type="file"]')
|
|
|
|
|
if (fileInput?.files[0]) {
|
|
|
|
|
formData.append('voucher', fileInput.files[0])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response = await api.post('/transfers/create', formData, {
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'multipart/form-data'
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
ElMessage.success(response.data.message)
|
|
|
|
|
showCreateTransfer.value = false
|
|
|
|
|
resetTransferForm()
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('提交转账失败:', error)
|
|
|
|
|
ElMessage.error(error.response?.data?.message || '提交失败')
|
|
|
|
|
} finally {
|
|
|
|
|
submitLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resetTransferForm = () => {
|
|
|
|
|
Object.assign(transferForm, {
|
|
|
|
|
to_user_id: '',
|
|
|
|
|
amount: '',
|
|
|
|
|
transfer_type: 'user_to_user',
|
|
|
|
|
description: '',
|
|
|
|
|
voucher: ''
|
|
|
|
|
})
|
|
|
|
|
transferFormRef.value?.resetFields()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文件上传处理
|
|
|
|
|
const beforeUpload = (file) => {
|
|
|
|
|
const isImage = file.type.startsWith('image/')
|
|
|
|
|
const isLt5M = file.size / 1024 / 1024 < 5
|
|
|
|
|
|
|
|
|
|
if (!isImage) {
|
|
|
|
|
ElMessage.error('只能上传图片文件!')
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if (!isLt5M) {
|
|
|
|
|
ElMessage.error('图片大小不能超过 5MB!')
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理文件上传成功回调
|
|
|
|
|
* @param {Object} response - 上传接口返回的响应数据
|
|
|
|
|
*/
|
|
|
|
|
const handleUploadSuccess = (response) => {
|
|
|
|
|
if (response.success) {
|
|
|
|
|
// 使用工具函数将相对路径转换为完整的服务器地址
|
|
|
|
|
transferForm.voucher = formatImageUrl(response.url)
|
|
|
|
|
ElMessage.success('上传成功')
|
|
|
|
|
} else {
|
|
|
|
|
ElMessage.error(response.message || '上传失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleUploadError = (error) => {
|
|
|
|
|
console.error('上传错误:', error)
|
|
|
|
|
ElMessage.error('上传失败,请重试')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 工具方法
|
|
|
|
|
/**
|
|
|
|
|
* 格式化时间显示
|
|
|
|
|
* @param {string} time - 时间字符串
|
|
|
|
|
* @returns {string} 格式化后的时间
|
|
|
|
|
*/
|
|
|
|
|
const formatTime = (time) => {
|
|
|
|
|
return new Date(time).toLocaleString('zh-CN')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 格式化图片URL
|
|
|
|
|
* @param {string} url - 相对路径或完整URL
|
|
|
|
|
* @returns {string} 处理后的图片URL
|
|
|
|
|
*/
|
|
|
|
|
const formatImageUrl = (url) => {
|
|
|
|
|
return getImageUrl(url)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStatusType = (status) => {
|
|
|
|
|
const types = {
|
|
|
|
|
pending: 'warning',
|
|
|
|
|
@@ -612,11 +481,14 @@ const getStatusText = (status) => {
|
|
|
|
|
return texts[status] || '未知'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取回款时间状态
|
|
|
|
|
* @param {Object} allocation - 分配对象
|
|
|
|
|
* @returns {string} 时间状态类名
|
|
|
|
|
*/
|
|
|
|
|
const formatTime = (time) => {
|
|
|
|
|
return new Date(time).toLocaleString('zh-CN')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const formatImageUrl = (url) => {
|
|
|
|
|
return getImageUrl(url)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getReturnTimeStatus = (allocation) => {
|
|
|
|
|
if (!allocation.can_return_after) return 'normal'
|
|
|
|
|
|
|
|
|
|
@@ -630,11 +502,6 @@ const getReturnTimeStatus = (allocation) => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取回款时间文本
|
|
|
|
|
* @param {Object} allocation - 分配对象
|
|
|
|
|
* @returns {string} 时间状态文本
|
|
|
|
|
*/
|
|
|
|
|
const getReturnTimeText = (allocation) => {
|
|
|
|
|
if (!allocation.can_return_after) return ''
|
|
|
|
|
|
|
|
|
|
@@ -656,11 +523,6 @@ const getReturnTimeText = (allocation) => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 判断是否可以确认回款
|
|
|
|
|
* @param {Object} allocation - 分配对象
|
|
|
|
|
* @returns {boolean} 是否可以确认回款
|
|
|
|
|
*/
|
|
|
|
|
const canConfirmReturn = (allocation) => {
|
|
|
|
|
if (!allocation.can_return_after) return false
|
|
|
|
|
|
|
|
|
|
@@ -670,10 +532,6 @@ const canConfirmReturn = (allocation) => {
|
|
|
|
|
return now >= canReturnTime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示回款确认对话框
|
|
|
|
|
* @param {Object} allocation - 分配对象
|
|
|
|
|
*/
|
|
|
|
|
const showReturnConfirmDialog = (allocation) => {
|
|
|
|
|
currentAllocation.value = allocation
|
|
|
|
|
returnForm.returnAmount = allocation.amount
|
|
|
|
|
@@ -681,9 +539,6 @@ const showReturnConfirmDialog = (allocation) => {
|
|
|
|
|
showReturnDialog.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 确认回款
|
|
|
|
|
*/
|
|
|
|
|
const confirmReturn = async () => {
|
|
|
|
|
try {
|
|
|
|
|
confirmLoading.value = true
|
|
|
|
|
@@ -696,7 +551,6 @@ const confirmReturn = async () => {
|
|
|
|
|
ElMessage.success('回款确认成功')
|
|
|
|
|
showReturnDialog.value = false
|
|
|
|
|
|
|
|
|
|
// 重新加载数据
|
|
|
|
|
await loadPendingAllocations()
|
|
|
|
|
await loadTransferHistory()
|
|
|
|
|
|
|
|
|
|
@@ -708,59 +562,36 @@ const confirmReturn = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示转账凭证并确认收款
|
|
|
|
|
*/
|
|
|
|
|
const confirmReceived = async (transferId) => {
|
|
|
|
|
try {
|
|
|
|
|
// 找到对应的转账记录
|
|
|
|
|
const transfer = transferHistory.value.find(t => t.id === transferId)
|
|
|
|
|
if (!transfer) {
|
|
|
|
|
ElMessage.error('转账记录不存在')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置当前转账信息并显示凭证对话框
|
|
|
|
|
currentTransfer.value = transfer
|
|
|
|
|
showVoucherDialog.value = true
|
|
|
|
|
|
|
|
|
|
// 直接调用确认收款方法
|
|
|
|
|
await doConfirmReceived()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('确认收款失败:', error)
|
|
|
|
|
ElMessage.error('操作失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 执行确认收款操作
|
|
|
|
|
*/
|
|
|
|
|
const doConfirmReceived = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm(
|
|
|
|
|
'确定已收到款项吗?',
|
|
|
|
|
'请确认已收到款项并核对凭证,确定要确认收款吗?',
|
|
|
|
|
'确认收款',
|
|
|
|
|
{
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
confirmButtonText: '确认收款',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
confirmLoading.value = true
|
|
|
|
|
const response = await api.post(`/transfers/confirm-received/${currentTransfer.value.id}`)
|
|
|
|
|
const response = await api.post(`/transfers/confirm-received/${transferId}`)
|
|
|
|
|
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
ElMessage.success(response.data.message)
|
|
|
|
|
showVoucherDialog.value = false
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
loadPendingTransfers() // 重新加载待确认转账
|
|
|
|
|
ElMessage.success('收款确认成功')
|
|
|
|
|
await loadTransferHistory()
|
|
|
|
|
await loadPendingTransfers()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
console.error('确认收款失败:', error)
|
|
|
|
|
ElMessage.error(error.response?.data?.message || '操作失败')
|
|
|
|
|
ElMessage.error(error.response?.data?.message || '确认收款失败')
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
confirmLoading.value = false
|
|
|
|
|
@@ -785,7 +616,6 @@ const confirmNotReceived = async (transferId) => {
|
|
|
|
|
if (response.data.success) {
|
|
|
|
|
ElMessage.success(response.data.message)
|
|
|
|
|
loadTransferHistory()
|
|
|
|
|
loadAccountInfo()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
@@ -796,19 +626,6 @@ const confirmNotReceived = async (transferId) => {
|
|
|
|
|
confirmLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算各个状态的数量
|
|
|
|
|
const totalCount = computed(() => pagination.total)
|
|
|
|
|
const pendingCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'pending').length
|
|
|
|
|
})
|
|
|
|
|
const confirmedCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'confirmed').length
|
|
|
|
|
})
|
|
|
|
|
const rejectedCount = computed(() => {
|
|
|
|
|
return transferHistory.value.filter(t => t.status === 'rejected').length
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|