289 lines
7.0 KiB
Vue
289 lines
7.0 KiB
Vue
<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>
|