301 lines
9.1 KiB
Vue
301 lines
9.1 KiB
Vue
|
|
<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-tab-pane label="超时未认领" name="timeout"></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"
|
||
|
|
:row-class-name="tableRowClassName"
|
||
|
|
>
|
||
|
|
<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="计时" prop="amount" min-width="120">
|
||
|
|
<template #default="scope">
|
||
|
|
<span
|
||
|
|
v-if="!scope.row.payment_apply_id"
|
||
|
|
:class="getCountdownClass(scope.row.claim_timeout_time)"
|
||
|
|
>
|
||
|
|
<span class="custom-clock-icon" style="vertical-align: middle; margin-right: 4px">
|
||
|
|
<i class="iconfont-sys"></i>
|
||
|
|
</span>
|
||
|
|
{{ getCountdown(scope.row.claim_timeout_time) }}
|
||
|
|
</span>
|
||
|
|
<span v-else class="countdown-success">已认领</span>
|
||
|
|
</template>
|
||
|
|
</ElTableColumn>
|
||
|
|
<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(scope.row)"
|
||
|
|
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"
|
||
|
|
/>
|
||
|
|
<!-- 付款记录详情查看对话框 -->
|
||
|
|
<ClaimRecordDetailDialog v-model="detailDialogVisible" :payment-id="currentPaymentId" />
|
||
|
|
</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'
|
||
|
|
import ClaimRecordDetailDialog from '@/components/custom/ClaimRecordDetailDialog.vue'
|
||
|
|
import dayjs from 'dayjs'
|
||
|
|
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 detailDialogVisible = ref(false)
|
||
|
|
// 付款记录对话框相关
|
||
|
|
const paymentDialogVisible = ref(false)
|
||
|
|
const currentReceiptId = ref<string | number>('')
|
||
|
|
watch([keyword], () => {
|
||
|
|
pagination.currentPage = 1
|
||
|
|
getList()
|
||
|
|
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||
|
|
})
|
||
|
|
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 currentPaymentId = ref<string | number>('')
|
||
|
|
const handleView = async (params: any) => {
|
||
|
|
detailDialogVisible.value = true
|
||
|
|
currentPaymentId.value = params.id
|
||
|
|
await financeService.getReceiptDetail(params)
|
||
|
|
}
|
||
|
|
// 处理认领操作
|
||
|
|
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 = () => {}
|
||
|
|
const timer = ref(0)
|
||
|
|
const refreshKey = ref(0)
|
||
|
|
onMounted(() => {
|
||
|
|
getList()
|
||
|
|
timer.value = window.setInterval(() => {
|
||
|
|
refreshKey.value++
|
||
|
|
}, 1000)
|
||
|
|
})
|
||
|
|
function getCountdown(targetDate: string) {
|
||
|
|
// 让 refreshKey 成为依赖,确保每秒刷新
|
||
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||
|
|
refreshKey.value
|
||
|
|
const now = dayjs()
|
||
|
|
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||
|
|
if (!target.isValid()) return '时间格式错误'
|
||
|
|
const diff = target.diff(now)
|
||
|
|
if (diff <= 0) return '已超时'
|
||
|
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||
|
|
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24)
|
||
|
|
const minutes = Math.floor((diff / (1000 * 60)) % 60)
|
||
|
|
const seconds = Math.floor((diff / 1000) % 60)
|
||
|
|
return `${days > 0 ? days + '天' : ''}${hours}小时${minutes}分${seconds}秒`
|
||
|
|
}
|
||
|
|
|
||
|
|
function getCountdownClass(targetDate: string) {
|
||
|
|
const now = dayjs()
|
||
|
|
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||
|
|
if (!target.isValid() || target.diff(now) <= 0) {
|
||
|
|
return 'countdown-danger'
|
||
|
|
}
|
||
|
|
return 'countdown-success'
|
||
|
|
}
|
||
|
|
const tableRowClassName = ({ row }: { row: any }) => {
|
||
|
|
const flag = Number(row?.claim_timeout)
|
||
|
|
return flag === 1 ? 'row-claim-timeout' : ''
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped lang="scss">
|
||
|
|
:deep(.row-claim-timeout) {
|
||
|
|
background-color: #ffc9c9 !important;
|
||
|
|
}
|
||
|
|
:deep(.el-tabs__nav-wrap:after){
|
||
|
|
background: #fff;
|
||
|
|
}
|
||
|
|
.countdown-danger {
|
||
|
|
color: #ff0000 !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
.countdown-success {
|
||
|
|
color: #00a43f !important;
|
||
|
|
}
|
||
|
|
.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>
|