Files
hfb_sys/frontend/src/features/wallet/views/PaymentAccountsView.vue
T

289 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>