提现审核页增加待收款/成功失败等明细状态筛选。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-15 06:03:53 +08:00
parent a6d339c473
commit fd2e6c1c3f

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="withdraw-audit"> <div class="withdraw-audit">
<!-- 顶部统计卡片 --> <!-- 顶部统计卡片 -->
<el-row :gutter="20" class="stats-cards"> <el-row :gutter="16" class="stats-cards">
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8"> <el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4">
<el-card class="stat-card" shadow="hover"> <el-card class="stat-card" shadow="hover">
<div class="stat-item"> <div class="stat-item">
<div class="stat-label">总记录</div> <div class="stat-label">总记录</div>
@@ -10,18 +10,42 @@
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8"> <el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4">
<el-card class="stat-card" shadow="hover" @click="changeStatus(1)"> <el-card class="stat-card" shadow="hover" @click="changeDetailStatus(1)">
<div class="stat-item"> <div class="stat-item">
<div class="stat-label">待审核</div> <div class="stat-label">待审核</div>
<div class="stat-value warning">{{ stats.awaiting || 0 }}</div> <div class="stat-value warning">{{ stats.awaiting || 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8"> <el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4" v-if="isAutoMode">
<el-card class="stat-card" shadow="hover" @click="changeDetailStatus(6)">
<div class="stat-item">
<div class="stat-label">待收款</div>
<div class="stat-value warning">{{ stats.pending_collect || 0 }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4">
<el-card class="stat-card" shadow="hover" @click="changeDetailStatus(2)">
<div class="stat-item">
<div class="stat-label">提现成功</div>
<div class="stat-value success">{{ stats.success || 0 }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4">
<el-card class="stat-card" shadow="hover" @click="changeDetailStatus(3)">
<div class="stat-item">
<div class="stat-label">提现失败</div>
<div class="stat-value danger">{{ stats.fail || 0 }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="8" :md="4" :lg="4" :xl="4">
<el-card class="stat-card" shadow="hover" @click="changeStatus(2)"> <el-card class="stat-card" shadow="hover" @click="changeStatus(2)">
<div class="stat-item"> <div class="stat-item">
<div class="stat-label">已处理</div> <div class="stat-label">已处理(全部)</div>
<div class="stat-value success">{{ stats.processed || 0 }}</div> <div class="stat-value success">{{ stats.processed || 0 }}</div>
</div> </div>
</el-card> </el-card>
@@ -87,14 +111,52 @@
<el-col :span="24"> <el-col :span="24">
<div class="status-switch"> <div class="status-switch">
<el-button <el-button
:type="statusFilter === 1 ? 'primary' : 'default'" :type="isStatusActive(1) ? 'primary' : 'default'"
@click="changeStatus(1)" @click="changeDetailStatus(1)"
size="large" size="large"
> >
待审核 <el-tag size="small" type="warning" v-if="stats.awaiting">{{ stats.awaiting }}</el-tag> 待审核 <el-tag size="small" type="warning" v-if="stats.awaiting">{{ stats.awaiting }}</el-tag>
</el-button> </el-button>
<el-button <el-button
:type="statusFilter === 2 ? 'success' : 'default'" v-if="isAutoMode"
:type="isStatusActive(6) ? 'warning' : 'default'"
@click="changeDetailStatus(6)"
size="large"
>
待收款 <el-tag size="small" type="warning" v-if="stats.pending_collect">{{ stats.pending_collect }}</el-tag>
</el-button>
<el-button
:type="isStatusActive(2) ? 'success' : 'default'"
@click="changeDetailStatus(2)"
size="large"
>
提现成功 <el-tag size="small" type="success" v-if="stats.success">{{ stats.success }}</el-tag>
</el-button>
<el-button
:type="isStatusActive(3) ? 'danger' : 'default'"
@click="changeDetailStatus(3)"
size="large"
>
提现失败
</el-button>
<el-button
v-if="isAutoMode"
:type="isStatusActive(4) ? 'success' : 'default'"
@click="changeDetailStatus(4)"
size="large"
>
审核成功
</el-button>
<el-button
v-if="isAutoMode"
:type="isStatusActive(5) ? 'danger' : 'default'"
@click="changeDetailStatus(5)"
size="large"
>
审核失败
</el-button>
<el-button
:type="isProcessedActive ? 'success' : 'default'"
@click="changeStatus(2)" @click="changeStatus(2)"
size="large" size="large"
> >
@@ -148,7 +210,7 @@
</el-card> </el-card>
<!-- 自动打款批量操作栏 --> <!-- 自动打款批量操作栏 -->
<div v-if="isAutoMode && statusFilter === 1" class="batch-bar"> <div v-if="isAutoMode && canBatchOperate" class="batch-bar">
<span class="batch-tip">已选 {{ selectedRows.length }} </span> <span class="batch-tip">已选 {{ selectedRows.length }} </span>
<el-button <el-button
type="success" type="success"
@@ -182,7 +244,7 @@
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column <el-table-column
v-if="isAutoMode && statusFilter === 1" v-if="isAutoMode && canBatchOperate"
type="selection" type="selection"
width="48" width="48"
fixed="left" fixed="left"
@@ -200,13 +262,20 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="jine" label="金额" width="120"> <el-table-column prop="jine" label="申请金额" width="110">
<template #default="{ row }">¥{{ row.jine }}</template> <template #default="{ row }">¥{{ row.jine }}</template>
</el-table-column> </el-table-column>
<el-table-column v-if="isAutoMode" label="手续费" width="90">
<template #default="{ row }">{{ row.shouxufei ? `¥${row.shouxufei}` : '--' }}</template>
</el-table-column>
<el-table-column v-if="isAutoMode" label="实际到账" width="100">
<template #default="{ row }">{{ row.shijidaozhang ? `¥${row.shijidaozhang}` : '--' }}</template>
</el-table-column>
<el-table-column label="提现类型" width="110"> <el-table-column label="提现类型" width="110">
<template #default="{ row }">{{ getTypeText(row.leixing) }}</template> <template #default="{ row }">{{ getTypeText(row.leixing) }}</template>
</el-table-column> </el-table-column>
<el-table-column v-if="isAutoMode" prop="shenhe_danhao" label="审核单号" min-width="160" show-overflow-tooltip /> <el-table-column v-if="isAutoMode" prop="shenhe_danhao" label="审核单号" min-width="160" show-overflow-tooltip />
<el-table-column v-if="isAutoMode" prop="dakuan_mch_id" label="打款商户" min-width="120" show-overflow-tooltip />
<el-table-column label="打款方式" width="100"> <el-table-column label="打款方式" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="row.dakuan_mode === 2 ? 'success' : 'info'" size="small"> <el-tag :type="row.dakuan_mode === 2 ? 'success' : 'info'" size="small">
@@ -220,15 +289,18 @@
<el-table-column label="状态" width="110"> <el-table-column label="状态" width="110">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="getStatusType(row.zhuangtai)"> <el-tag :type="getStatusType(row.zhuangtai)">
{{ getStatusText(row.zhuangtai) }} {{ row.zhuangtai_text || getStatusText(row.zhuangtai) }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="失败原因" min-width="140" show-overflow-tooltip>
<template #default="{ row }">{{ row.fail_reason || row.bhliyou || '--' }}</template>
</el-table-column>
<el-table-column prop="create_time" label="申请时间" width="160" :formatter="formatTime" /> <el-table-column prop="create_time" label="申请时间" width="160" :formatter="formatTime" />
<el-table-column label="操作" :width="isAutoMode && statusFilter === 1 ? 200 : 80" fixed="right"> <el-table-column label="操作" :width="isAutoMode && canBatchOperate ? 200 : 80" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click.stop="goToDetail(row)">详情</el-button> <el-button type="primary" link @click.stop="goToDetail(row)">详情</el-button>
<template v-if="isAutoMode && statusFilter === 1 && row.zhuangtai === 1"> <template v-if="isAutoMode && canBatchOperate && row.zhuangtai === 1">
<el-button type="success" link @click.stop="handleInlineApprove(row)">同意</el-button> <el-button type="success" link @click.stop="handleInlineApprove(row)">同意</el-button>
<el-button type="danger" link @click.stop="showInlineRejectDialog(row)">驳回</el-button> <el-button type="danger" link @click.stop="showInlineRejectDialog(row)">驳回</el-button>
</template> </template>
@@ -294,6 +366,9 @@ const stats = ref({
total: 0, total: 0,
awaiting: 0, awaiting: 0,
processed: 0, processed: 0,
pending_collect: 0,
success: 0,
fail: 0,
total_amount: '0.00' total_amount: '0.00'
}) })
@@ -307,7 +382,9 @@ const filters = reactive({
dakuanMode: 1 dakuanMode: 1
}) })
// statusFilter: 1=待审核粗粒度 2=已处理粗粒度detailZhuangtai: 1~6 精确态(优先生效)
const statusFilter = ref(1) const statusFilter = ref(1)
const detailZhuangtai = ref(null)
const rejectDialogVisible = ref(false) const rejectDialogVisible = ref(false)
const rejectReason = ref('') const rejectReason = ref('')
@@ -315,6 +392,14 @@ const rejectTargetRow = ref(null)
const rejectMode = ref('single') const rejectMode = ref('single')
const isAutoMode = computed(() => filters.dakuanMode === 2) const isAutoMode = computed(() => filters.dakuanMode === 2)
const canBatchOperate = computed(() => {
if (detailZhuangtai.value != null) return Number(detailZhuangtai.value) === 1
return Number(statusFilter.value) === 1
})
const isProcessedActive = computed(() => (
detailZhuangtai.value == null && Number(statusFilter.value) === 2
))
const isStatusActive = (code) => Number(detailZhuangtai.value) === Number(code)
const getFullImageUrl = (url) => { const getFullImageUrl = (url) => {
if (!url) return '' if (!url) return ''
@@ -425,6 +510,7 @@ const saveFiltersToStorage = () => {
minAmount: filters.minAmount, minAmount: filters.minAmount,
maxAmount: filters.maxAmount, maxAmount: filters.maxAmount,
statusFilter: statusFilter.value, statusFilter: statusFilter.value,
detailZhuangtai: detailZhuangtai.value,
dakuanMode: filters.dakuanMode dakuanMode: filters.dakuanMode
} }
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore)) localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
@@ -442,6 +528,10 @@ const loadFiltersFromStorage = () => {
if (parsed.minAmount !== undefined) filters.minAmount = parsed.minAmount if (parsed.minAmount !== undefined) filters.minAmount = parsed.minAmount
if (parsed.maxAmount !== undefined) filters.maxAmount = parsed.maxAmount if (parsed.maxAmount !== undefined) filters.maxAmount = parsed.maxAmount
if (parsed.statusFilter !== undefined && [1, 2].includes(parsed.statusFilter)) statusFilter.value = parsed.statusFilter if (parsed.statusFilter !== undefined && [1, 2].includes(parsed.statusFilter)) statusFilter.value = parsed.statusFilter
if (parsed.detailZhuangtai !== undefined && parsed.detailZhuangtai !== null
&& [1, 2, 3, 4, 5, 6].includes(Number(parsed.detailZhuangtai))) {
detailZhuangtai.value = Number(parsed.detailZhuangtai)
}
if (parsed.dakuanMode !== undefined && [1, 2].includes(parsed.dakuanMode)) filters.dakuanMode = parsed.dakuanMode if (parsed.dakuanMode !== undefined && [1, 2].includes(parsed.dakuanMode)) filters.dakuanMode = parsed.dakuanMode
} catch (e) { } catch (e) {
console.error('恢复筛选条件失败', e) console.error('恢复筛选条件失败', e)
@@ -453,13 +543,18 @@ const buildListParams = () => {
phone: localStorage.getItem('username'), phone: localStorage.getItem('username'),
page: page.value, page: page.value,
page_size: pageSize.value, page_size: pageSize.value,
status: statusFilter.value,
dakuan_mode: filters.dakuanMode, dakuan_mode: filters.dakuanMode,
type: filters.type || undefined, type: filters.type || undefined,
payment: filters.payment === 0 ? undefined : filters.payment, payment: filters.payment === 0 ? undefined : filters.payment,
search_uid: filters.searchUid || undefined, search_uid: filters.searchUid || undefined,
date: filters.date || undefined date: filters.date || undefined
} }
// 明细状态优先;否则用粗粒度 status
if (detailZhuangtai.value != null && [1, 2, 3, 4, 5, 6].includes(Number(detailZhuangtai.value))) {
params.zhuangtai = Number(detailZhuangtai.value)
} else {
params.status = statusFilter.value
}
if (filters.minAmount !== null && filters.minAmount !== '') { if (filters.minAmount !== null && filters.minAmount !== '') {
params.min_amount = filters.minAmount params.min_amount = filters.minAmount
} }
@@ -501,6 +596,9 @@ const fetchData = async () => {
total: 0, total: 0,
awaiting: 0, awaiting: 0,
processed: 0, processed: 0,
pending_collect: 0,
success: 0,
fail: 0,
total_amount: '0.00', total_amount: '0.00',
...(data.stats || {}) ...(data.stats || {})
} }
@@ -524,13 +622,28 @@ const fetchData = async () => {
const handleDakuanModeChange = () => { const handleDakuanModeChange = () => {
page.value = 1 page.value = 1
selectedRows.value = [] selectedRows.value = []
// 手动打款无 4/5/6若当前卡在这些态回退待审核
if (!isAutoMode.value && [4, 5, 6].includes(Number(detailZhuangtai.value))) {
detailZhuangtai.value = 1
statusFilter.value = 1
}
fetchData() fetchData()
saveFiltersToStorage() saveFiltersToStorage()
} }
const changeStatus = (status) => { const changeStatus = (status) => {
if (statusFilter.value === status) return // 粗粒度已处理 / 待审核(清掉明细态)
statusFilter.value = status statusFilter.value = status
detailZhuangtai.value = null
page.value = 1
selectedRows.value = []
fetchData()
saveFiltersToStorage()
}
const changeDetailStatus = (code) => {
detailZhuangtai.value = Number(code)
statusFilter.value = Number(code) === 1 ? 1 : 2
page.value = 1 page.value = 1
selectedRows.value = [] selectedRows.value = []
fetchData() fetchData()
@@ -552,6 +665,7 @@ const resetFilters = () => {
filters.maxAmount = null filters.maxAmount = null
filters.dakuanMode = 1 filters.dakuanMode = 1
statusFilter.value = 1 statusFilter.value = 1
detailZhuangtai.value = null
page.value = 1 page.value = 1
localStorage.removeItem(STORAGE_KEY) localStorage.removeItem(STORAGE_KEY)
fetchData() fetchData()
@@ -766,6 +880,9 @@ onMounted(() => {
.stat-value.success { .stat-value.success {
color: #67c23a; color: #67c23a;
} }
.stat-value.danger {
color: #f56c6c;
}
.total-amount { .total-amount {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;