增加提现相关的与打款相关逻辑

This commit is contained in:
yml
2026-06-06 13:16:44 +08:00
parent 8a2d2f2a18
commit 5c830fe1f4
32 changed files with 3835 additions and 72 deletions
@@ -0,0 +1,307 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Delete, Star, StarFilled, Edit } from '@element-plus/icons-vue'
import {
fetchPaymentAccounts,
deletePaymentAccount,
setDefaultPaymentAccount,
type PaymentAccount,
} from '../api/withdrawal'
import PaymentAccountDialog from '../components/PaymentAccountDialog.vue'
const loading = ref(false)
const accounts = ref<PaymentAccount[]>([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(20)
const showDialog = ref(false)
const editingAccount = ref<PaymentAccount | null>(null)
onMounted(() => {
loadAccounts()
})
async function loadAccounts() {
loading.value = true
try {
const result = await fetchPaymentAccounts(currentPage.value, pageSize.value)
accounts.value = result.items
total.value = result.total
} catch (error: any) {
ElMessage.error(error.response?.data?.message || '加载失败')
} finally {
loading.value = false
}
}
function openCreateDialog() {
editingAccount.value = null
showDialog.value = true
}
function openEditDialog(account: PaymentAccount) {
editingAccount.value = account
showDialog.value = true
}
async function handleSetDefault(account: PaymentAccount) {
if (account.is_default) {
return
}
try {
await setDefaultPaymentAccount(account.id)
ElMessage.success('已设为默认账号')
await loadAccounts()
} catch (error: any) {
ElMessage.error(error.response?.data?.message || '操作失败')
}
}
async function handleDelete(account: PaymentAccount) {
try {
await ElMessageBox.confirm(`确定要删除此收款账号吗?`, '删除确认', {
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'warning',
})
await deletePaymentAccount(account.id)
ElMessage.success('删除成功')
await loadAccounts()
} catch (error: any) {
if (error !== 'cancel') {
ElMessage.error(error.response?.data?.message || '删除失败')
}
}
}
function accountTypeLabel(type: string) {
const labels: Record<string, string> = {
alipay: '支付宝',
wechat: '微信',
bank: '银行卡',
}
return labels[type] || type
}
function accountTypeColor(type: string) {
const colors: Record<string, string> = {
alipay: '#1677ff',
wechat: '#07c160',
bank: '#ff6a00',
}
return colors[type] || '#999'
}
const canAddMore = computed(() => accounts.value.length < 5)
</script>
<template>
<div class="payment-accounts-page">
<div class="page-header">
<div>
<h2>收款账号管理</h2>
<p class="page-desc">管理您的收款账号,用于提现时接收资金(最多5个)</p>
</div>
<el-button
v-if="canAddMore"
type="primary"
:icon="Plus"
@click="openCreateDialog"
>
添加收款账号
</el-button>
<el-tag v-else type="info">已达账号数量上限</el-tag>
</div>
<el-alert
v-if="accounts.length === 0 && !loading"
title="还没有收款账号"
type="info"
description="请先添加收款账号,才能进行提现操作。账户名必须与您的实名认证姓名一致。"
show-icon
:closable="false"
style="margin-bottom: 20px"
/>
<div v-loading="loading" class="accounts-grid">
<div
v-for="account in accounts"
:key="account.id"
class="account-card"
:class="{ 'is-default': account.is_default }"
>
<div class="account-header">
<div class="account-type">
<el-tag
:color="accountTypeColor(account.account_type)"
effect="dark"
size="large"
>
{{ accountTypeLabel(account.account_type) }}
</el-tag>
</div>
<div class="account-actions">
<el-tooltip
:content="account.is_default ? '默认账号' : '设为默认'"
placement="top"
>
<el-button
:icon="account.is_default ? StarFilled : Star"
:type="account.is_default ? 'warning' : 'default'"
circle
size="small"
@click="handleSetDefault(account)"
/>
</el-tooltip>
<el-button
:icon="Edit"
circle
size="small"
@click="openEditDialog(account)"
/>
<el-button
:icon="Delete"
circle
size="small"
type="danger"
@click="handleDelete(account)"
/>
</div>
</div>
<div class="account-info">
<div class="info-row">
<span class="label">账户名:</span>
<span class="value">{{ account.account_name }}</span>
</div>
<div class="info-row">
<span class="label">账号:</span>
<span class="value monospace">{{ account.account_no }}</span>
</div>
<div v-if="account.account_type === 'bank'" class="info-row">
<span class="label">银行:</span>
<span class="value">{{ account.bank_name }}</span>
</div>
<div v-if="account.account_type === 'bank' && account.bank_branch" class="info-row">
<span class="label">支行:</span>
<span class="value">{{ account.bank_branch }}</span>
</div>
</div>
<div class="account-footer">
<span class="created-time">添加于 {{ new Date(account.created_at).toLocaleDateString() }}</span>
</div>
</div>
</div>
<PaymentAccountDialog
v-model="showDialog"
:account="editingAccount"
@saved="loadAccounts"
/>
</div>
</template>
<style scoped>
.payment-accounts-page {
max-width: 1200px;
margin: 0 auto;
padding: 24px;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-header h2 {
margin: 0 0 8px;
font-size: 24px;
font-weight: 600;
}
.page-desc {
margin: 0;
color: #666;
font-size: 14px;
}
.accounts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
}
.account-card {
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 20px;
background: #fff;
transition: all 0.3s;
}
.account-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
transform: translateY(-2px);
}
.account-card.is-default {
border-color: #f59e0b;
background: linear-gradient(135deg, #fffbeb 0%, #ffffff 100%);
}
.account-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.account-actions {
display: flex;
gap: 8px;
}
.account-info {
margin-bottom: 16px;
}
.info-row {
display: flex;
margin-bottom: 8px;
font-size: 14px;
}
.info-row .label {
width: 70px;
color: #666;
flex-shrink: 0;
}
.info-row .value {
flex: 1;
color: #333;
font-weight: 500;
}
.info-row .value.monospace {
font-family: 'Courier New', Courier, monospace;
letter-spacing: 1px;
}
.account-footer {
padding-top: 12px;
border-top: 1px solid #f0f0f0;
}
.created-time {
font-size: 12px;
color: #999;
}
</style>