update
This commit is contained in:
parent
0f7e55b139
commit
b66cd95bda
@ -16,6 +16,14 @@
|
|||||||
<template #icon><dashboard-outlined /></template>
|
<template #icon><dashboard-outlined /></template>
|
||||||
<span>仪表盘</span>
|
<span>仪表盘</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="finance" @click="() => $router.push('/finance')">
|
||||||
|
<template #icon><dollar-outlined /></template>
|
||||||
|
<span>财务管理</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="bank-card" @click="() => $router.push('/bank-card')">
|
||||||
|
<template #icon><credit-card-outlined /></template>
|
||||||
|
<span>银行卡管理</span>
|
||||||
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-layout-sider>
|
</a-layout-sider>
|
||||||
|
|
||||||
@ -71,14 +79,18 @@ import { useStore } from 'vuex';
|
|||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import {
|
import {
|
||||||
DashboardOutlined,
|
DashboardOutlined,
|
||||||
HomeOutlined
|
HomeOutlined,
|
||||||
|
DollarOutlined,
|
||||||
|
CreditCardOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AdminLayout',
|
name: 'AdminLayout',
|
||||||
components: {
|
components: {
|
||||||
DashboardOutlined,
|
DashboardOutlined,
|
||||||
HomeOutlined
|
HomeOutlined,
|
||||||
|
DollarOutlined,
|
||||||
|
CreditCardOutlined
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|||||||
@ -12,6 +12,18 @@ const routes = [
|
|||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: () => import('../views/Dashboard.vue'),
|
component: () => import('../views/Dashboard.vue'),
|
||||||
meta: { title: '仪表盘', icon: 'dashboard' }
|
meta: { title: '仪表盘', icon: 'dashboard' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'finance',
|
||||||
|
name: 'Finance',
|
||||||
|
component: () => import('../views/Finance.vue'),
|
||||||
|
meta: { title: '财务管理', icon: 'money' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'bank-card',
|
||||||
|
name: 'BankCard',
|
||||||
|
component: () => import('../views/BankCard.vue'),
|
||||||
|
meta: { title: '银行卡管理', icon: 'credit-card' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -28,7 +28,11 @@ export default {
|
|||||||
BASE_URL,
|
BASE_URL,
|
||||||
BUILD_TIMESTAMP,
|
BUILD_TIMESTAMP,
|
||||||
API: {
|
API: {
|
||||||
LOGIN: '/api/user/password-login'
|
LOGIN: '/api/user/password-login',
|
||||||
|
ACCOUNT_SUMMARY: '/api/account/summary',
|
||||||
|
ACCOUNT_WITHDRAWALS: '/api/withdraw/user',
|
||||||
|
BANK_CARDS: '/api/bank-cards',
|
||||||
|
WITHDRAW: '/api/withdraw'
|
||||||
},
|
},
|
||||||
// 添加时间戳参数到 URL,用于破除缓存
|
// 添加时间戳参数到 URL,用于破除缓存
|
||||||
addTimestamp: (url) => {
|
addTimestamp: (url) => {
|
||||||
|
|||||||
288
src/views/BankCard.vue
Normal file
288
src/views/BankCard.vue
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bank-card-container">
|
||||||
|
<a-card title="银行卡管理" :bordered="false">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>我的银行卡</h3>
|
||||||
|
<div class="section-actions">
|
||||||
|
<a-button type="primary" @click="showAddBankCardModal">
|
||||||
|
<plus-outlined style="color: #fff;" />
|
||||||
|
添加银行卡
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<div v-if="bankCards.length === 0" class="empty-data">
|
||||||
|
<a-empty description="暂无银行卡" />
|
||||||
|
<div class="empty-action">
|
||||||
|
<a-button type="primary" @click="showAddBankCardModal">
|
||||||
|
<plus-outlined style="color: #fff;" />
|
||||||
|
添加银行卡
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-row :gutter="16" v-else>
|
||||||
|
<a-col :span="8" v-for="card in bankCards" :key="card.id">
|
||||||
|
<a-card class="bank-card">
|
||||||
|
<div class="bank-card-header">
|
||||||
|
<div class="bank-name">{{ card.bank_name }}</div>
|
||||||
|
<div class="card-type">储蓄卡</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-number">{{ card.card_number }}</div>
|
||||||
|
<div class="card-holder">{{ card.name }}</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-spin>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 添加银行卡弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="addBankCardModalVisible"
|
||||||
|
title="添加银行卡"
|
||||||
|
@ok="handleAddBankCard"
|
||||||
|
@cancel="addBankCardModalVisible = false"
|
||||||
|
>
|
||||||
|
<a-form :model="bankCardForm" layout="vertical">
|
||||||
|
<a-form-item name="name" label="持卡人姓名" required>
|
||||||
|
<a-input
|
||||||
|
v-model:value="bankCardForm.name"
|
||||||
|
placeholder="请输入持卡人姓名"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item name="card_number" label="银行卡号" required>
|
||||||
|
<a-input
|
||||||
|
v-model:value="bankCardForm.card_number"
|
||||||
|
placeholder="请输入银行卡号"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item name="bank_name" label="银行名称" required>
|
||||||
|
<a-select
|
||||||
|
v-model:value="bankCardForm.bank_name"
|
||||||
|
placeholder="请选择银行"
|
||||||
|
>
|
||||||
|
<a-select-option value="工商银行">工商银行</a-select-option>
|
||||||
|
<a-select-option value="建设银行">建设银行</a-select-option>
|
||||||
|
<a-select-option value="农业银行">农业银行</a-select-option>
|
||||||
|
<a-select-option value="招商银行">招商银行</a-select-option>
|
||||||
|
<a-select-option value="中国银行">中国银行</a-select-option>
|
||||||
|
<a-select-option value="交通银行">交通银行</a-select-option>
|
||||||
|
<a-select-option value="邮储银行">邮储银行</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive, onMounted } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { getBankCards, addBankCard } from '../api/finance';
|
||||||
|
import {
|
||||||
|
PlusOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BankCard',
|
||||||
|
components: {
|
||||||
|
PlusOutlined
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
// 银行卡数据
|
||||||
|
const bankCards = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const addBankCardModalVisible = ref(false);
|
||||||
|
const bankCardForm = reactive({
|
||||||
|
name: '',
|
||||||
|
card_number: '',
|
||||||
|
bank_name: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取银行卡列表
|
||||||
|
const fetchBankCards = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const data = await getBankCards();
|
||||||
|
bankCards.value = data || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取银行卡列表失败:', error);
|
||||||
|
message.error('获取银行卡列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示添加银行卡弹窗
|
||||||
|
const showAddBankCardModal = () => {
|
||||||
|
bankCardForm.name = '';
|
||||||
|
bankCardForm.card_number = '';
|
||||||
|
bankCardForm.bank_name = '';
|
||||||
|
addBankCardModalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理添加银行卡
|
||||||
|
const handleAddBankCard = async () => {
|
||||||
|
// 表单验证
|
||||||
|
if (!bankCardForm.name) {
|
||||||
|
message.error('请输入持卡人姓名');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!bankCardForm.card_number) {
|
||||||
|
message.error('请输入银行卡号');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!bankCardForm.bank_name) {
|
||||||
|
message.error('请选择银行');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await addBankCard(bankCardForm);
|
||||||
|
message.success('银行卡添加成功');
|
||||||
|
addBankCardModalVisible.value = false;
|
||||||
|
|
||||||
|
// 刷新银行卡列表
|
||||||
|
fetchBankCards();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('添加银行卡失败:', error);
|
||||||
|
message.error('添加银行卡失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchBankCards();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
bankCards,
|
||||||
|
loading,
|
||||||
|
addBankCardModalVisible,
|
||||||
|
bankCardForm,
|
||||||
|
showAddBankCardModal,
|
||||||
|
handleAddBankCard
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bank-card-container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-data {
|
||||||
|
padding: 32px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-action {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bank-card {
|
||||||
|
height: 200px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: linear-gradient(135deg, #1a1a1a 0%, #333333 100%);
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bank-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -50px;
|
||||||
|
right: -50px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bank-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bank-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-type {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-number {
|
||||||
|
font-size: 20px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-holder {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.8;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button :deep(.ant-btn-icon) {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
margin-right: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保所有按钮中的图标和文字都能正确对齐 */
|
||||||
|
.ant-btn {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-btn :deep(.anticon) {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
line-height: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保主要按钮中的图标颜色为白色 */
|
||||||
|
.ant-btn-primary :deep(.anticon) {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保默认按钮中的图标颜色可见 */
|
||||||
|
.ant-btn-default :deep(.anticon) {
|
||||||
|
color: rgba(0, 0, 0, 0.85) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
544
src/views/Finance.vue
Normal file
544
src/views/Finance.vue
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
<template>
|
||||||
|
<div class="finance-container">
|
||||||
|
<a-card title="账户管理" :bordered="false">
|
||||||
|
<!-- 账户信息卡片 -->
|
||||||
|
<a-row :gutter="16" class="account-summary">
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-card class="summary-card">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-title">
|
||||||
|
<wallet-outlined />
|
||||||
|
<span>账户余额</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="amount">
|
||||||
|
<span class="currency">¥</span>
|
||||||
|
<span class="value">{{ accountInfo.total_balance || '0.00' }}</span>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-card class="summary-card">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-title">
|
||||||
|
<dollar-outlined />
|
||||||
|
<span>可提现金额</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="amount">
|
||||||
|
<span class="currency">¥</span>
|
||||||
|
<span class="value">{{ accountInfo.balance || '0.00' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a-button type="primary" @click="showWithdrawalModal">申请提现</a-button>
|
||||||
|
<a-button @click="goToBankCardPage" style="margin-left: 8px">管理银行卡</a-button>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-card class="summary-card">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-title">
|
||||||
|
<lock-outlined />
|
||||||
|
<span>锁定金额</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="amount">
|
||||||
|
<span class="currency">¥</span>
|
||||||
|
<span class="value">{{ accountInfo.lock_balance || '0.00' }}</span>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 提现记录表格 -->
|
||||||
|
<div class="withdrawal-list">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>提现记录</h3>
|
||||||
|
<div class="section-actions">
|
||||||
|
<a-input-search
|
||||||
|
v-model:value="searchText"
|
||||||
|
placeholder="搜索提现记录"
|
||||||
|
style="width: 250px"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<a-button type="primary" @click="refreshData">
|
||||||
|
<reload-outlined style="color: #fff;" />
|
||||||
|
刷新
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
:dataSource="withdrawalList"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="{
|
||||||
|
total: total,
|
||||||
|
current: currentPage,
|
||||||
|
pageSize: pageSize,
|
||||||
|
showTotal: total => `共 ${total} 条记录`,
|
||||||
|
showSizeChanger: true,
|
||||||
|
}"
|
||||||
|
@change="handleTableChange"
|
||||||
|
>
|
||||||
|
<a-table-column title="提现单号" dataIndex="id" key="id" />
|
||||||
|
<a-table-column title="申请时间" dataIndex="create_time" key="create_time">
|
||||||
|
<template #default="{ text }">
|
||||||
|
{{ formatDate(text) }}
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="提现金额" dataIndex="amount" key="amount">
|
||||||
|
<template #default="{ text }">
|
||||||
|
¥ {{ text }}
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="状态" dataIndex="status" key="status">
|
||||||
|
<template #default="{ text }">
|
||||||
|
<a-tag :color="getStatusColor(text)">
|
||||||
|
{{ getStatusText(text) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="银行卡" key="bank_card">
|
||||||
|
<template #default="{ record }">
|
||||||
|
{{ record.bank_name }} ({{ record.bank_card_number }})
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="持卡人" dataIndex="name" key="name" />
|
||||||
|
<a-table-column title="更新时间" dataIndex="update_time" key="update_time">
|
||||||
|
<template #default="{ text }">
|
||||||
|
{{ text ? formatDate(text) : '-' }}
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="操作" key="action" width="120px">
|
||||||
|
<template #default="{ record }">
|
||||||
|
<a-popconfirm
|
||||||
|
v-if="record.status === 'PENDING'"
|
||||||
|
title="确定要取消此提现申请吗?"
|
||||||
|
ok-text="确定"
|
||||||
|
cancel-text="取消"
|
||||||
|
@confirm="handleCancelWithdraw(record.id)"
|
||||||
|
>
|
||||||
|
<a-button type="link" danger>
|
||||||
|
取消申请
|
||||||
|
</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<span v-else-if="record.status === 'CANCELLED'" class="status-text">已取消</span>
|
||||||
|
<span v-else-if="record.status === 'REJECTED'" class="status-text">已驳回</span>
|
||||||
|
<span v-else-if="record.status === 'APPROVED'" class="status-text">处理中</span>
|
||||||
|
<span v-else-if="record.status === 'COMPLETED'" class="status-text">已完成</span>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 提现申请弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="withdrawalModalVisible"
|
||||||
|
title="申请提现"
|
||||||
|
@ok="handleWithdrawalSubmit"
|
||||||
|
@cancel="withdrawalModalVisible = false"
|
||||||
|
>
|
||||||
|
<a-form :model="withdrawalForm" layout="vertical">
|
||||||
|
<a-form-item name="amount" label="提现金额" required>
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="withdrawalForm.amount"
|
||||||
|
placeholder="请输入提现金额"
|
||||||
|
style="width: 100%"
|
||||||
|
:min="1"
|
||||||
|
:max="accountInfo.balance"
|
||||||
|
:precision="2"
|
||||||
|
/>
|
||||||
|
<div class="form-tip">
|
||||||
|
可提现金额: ¥{{ accountInfo.balance || '0.00' }},最低提现金额: ¥1.00
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item name="bank_card_id" label="收款银行账户" required>
|
||||||
|
<a-select
|
||||||
|
v-model:value="withdrawalForm.bank_card_id"
|
||||||
|
placeholder="请选择收款银行账户"
|
||||||
|
>
|
||||||
|
<a-select-option v-for="card in bankCards" :key="card.id" :value="card.id">
|
||||||
|
{{ card.bank_name }} ({{ card.card_number }})
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<div v-if="bankCards.length === 0" class="form-tip">
|
||||||
|
<a-alert type="warning" message="您还没有添加银行卡,请先添加银行卡" banner />
|
||||||
|
<div style="margin-top: 8px;">
|
||||||
|
<a @click="goToBankCardPage">添加银行卡</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive, onMounted } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import {
|
||||||
|
getAccountSummary,
|
||||||
|
getWithdrawalList,
|
||||||
|
getBankCards,
|
||||||
|
applyWithdraw,
|
||||||
|
cancelWithdraw
|
||||||
|
} from '../api/finance';
|
||||||
|
import {
|
||||||
|
WalletOutlined,
|
||||||
|
LockOutlined,
|
||||||
|
DollarOutlined,
|
||||||
|
ReloadOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Finance',
|
||||||
|
components: {
|
||||||
|
WalletOutlined,
|
||||||
|
LockOutlined,
|
||||||
|
DollarOutlined,
|
||||||
|
ReloadOutlined
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// 账户信息
|
||||||
|
const accountInfo = ref({
|
||||||
|
total_balance: '0.00',
|
||||||
|
lock_balance: '0.00',
|
||||||
|
balance: '0.00'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 提现列表数据
|
||||||
|
const withdrawalList = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const total = ref(0);
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const searchText = ref('');
|
||||||
|
|
||||||
|
// 银行卡数据
|
||||||
|
const bankCards = ref([]);
|
||||||
|
const bankCardsLoading = ref(false);
|
||||||
|
|
||||||
|
// 提现申请表单
|
||||||
|
const withdrawalModalVisible = ref(false);
|
||||||
|
const withdrawalForm = reactive({
|
||||||
|
amount: null,
|
||||||
|
bank_card_id: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取账户信息
|
||||||
|
const fetchAccountInfo = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getAccountSummary();
|
||||||
|
accountInfo.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取账户信息失败:', error);
|
||||||
|
message.error('获取账户信息失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取提现列表
|
||||||
|
const fetchWithdrawalList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
page: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
keyword: searchText.value
|
||||||
|
};
|
||||||
|
const response = await getWithdrawalList(params);
|
||||||
|
withdrawalList.value = response.items || [];
|
||||||
|
total.value = response.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取提现列表失败:', error);
|
||||||
|
message.error('获取提现列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取银行卡列表
|
||||||
|
const fetchBankCards = async () => {
|
||||||
|
bankCardsLoading.value = true;
|
||||||
|
try {
|
||||||
|
const data = await getBankCards();
|
||||||
|
bankCards.value = data || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取银行卡列表失败:', error);
|
||||||
|
message.error('获取银行卡列表失败');
|
||||||
|
} finally {
|
||||||
|
bankCardsLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
const refreshData = () => {
|
||||||
|
fetchAccountInfo();
|
||||||
|
fetchWithdrawalList();
|
||||||
|
fetchBankCards();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理表格变化(分页、排序、筛选)
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
currentPage.value = pagination.current;
|
||||||
|
pageSize.value = pagination.pageSize;
|
||||||
|
fetchWithdrawalList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理搜索
|
||||||
|
const handleSearch = () => {
|
||||||
|
currentPage.value = 1;
|
||||||
|
fetchWithdrawalList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 跳转到银行卡管理页面
|
||||||
|
const goToBankCardPage = () => {
|
||||||
|
router.push('/bank-card');
|
||||||
|
if (withdrawalModalVisible.value) {
|
||||||
|
withdrawalModalVisible.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示提现弹窗
|
||||||
|
const showWithdrawalModal = () => {
|
||||||
|
withdrawalForm.amount = null;
|
||||||
|
withdrawalForm.bank_card_id = null;
|
||||||
|
withdrawalModalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理提现提交
|
||||||
|
const handleWithdrawalSubmit = async () => {
|
||||||
|
if (!withdrawalForm.amount) {
|
||||||
|
message.error('请输入提现金额');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!withdrawalForm.bank_card_id) {
|
||||||
|
message.error('请选择收款银行账户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await applyWithdraw({
|
||||||
|
bank_card_id: withdrawalForm.bank_card_id,
|
||||||
|
amount: withdrawalForm.amount
|
||||||
|
});
|
||||||
|
message.success('提现申请已提交,请等待审核');
|
||||||
|
withdrawalModalVisible.value = false;
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
setTimeout(() => {
|
||||||
|
refreshData();
|
||||||
|
}, 1000);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提现申请失败:', error);
|
||||||
|
message.error('提现申请失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理取消提现申请
|
||||||
|
const handleCancelWithdraw = async (id) => {
|
||||||
|
try {
|
||||||
|
await cancelWithdraw(id);
|
||||||
|
message.success('提现申请已取消');
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
refreshData();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消提现申请失败:', error);
|
||||||
|
message.error('取消提现申请失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化日期
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
if (!dateString) return '-';
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取状态颜色
|
||||||
|
const getStatusColor = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
PENDING: 'orange',
|
||||||
|
APPROVED: 'blue',
|
||||||
|
COMPLETED: 'green',
|
||||||
|
REJECTED: 'red',
|
||||||
|
CANCELLED: 'gray'
|
||||||
|
};
|
||||||
|
return statusMap[status] || 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
const getStatusText = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
PENDING: '已申请',
|
||||||
|
APPROVED: '已通过',
|
||||||
|
COMPLETED: '已完成',
|
||||||
|
REJECTED: '已驳回',
|
||||||
|
CANCELLED: '已取消'
|
||||||
|
};
|
||||||
|
return statusMap[status] || '未知状态';
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
refreshData();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountInfo,
|
||||||
|
withdrawalList,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
searchText,
|
||||||
|
bankCards,
|
||||||
|
withdrawalModalVisible,
|
||||||
|
withdrawalForm,
|
||||||
|
refreshData,
|
||||||
|
handleTableChange,
|
||||||
|
handleSearch,
|
||||||
|
goToBankCardPage,
|
||||||
|
showWithdrawalModal,
|
||||||
|
handleWithdrawalSubmit,
|
||||||
|
handleCancelWithdraw,
|
||||||
|
formatDate,
|
||||||
|
getStatusColor,
|
||||||
|
getStatusText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.finance-container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-summary {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-card {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-card:hover {
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title :deep(.anticon) {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-right: 4px;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.withdrawal-list {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button :deep(.ant-btn-icon) {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
margin-right: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保所有按钮中的图标和文字都能正确对齐 */
|
||||||
|
.ant-btn {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-btn :deep(.anticon) {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
line-height: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保主要按钮中的图标颜色为白色 */
|
||||||
|
.ant-btn-primary :deep(.anticon) {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保默认按钮中的图标颜色可见 */
|
||||||
|
.ant-btn-default :deep(.anticon) {
|
||||||
|
color: rgba(0, 0, 0, 0.85) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user