This commit is contained in:
qiuyuan 2025-12-31 11:27:23 +08:00
parent 086b4761db
commit a23bff7a3d
4 changed files with 550 additions and 56 deletions

View File

@ -246,6 +246,12 @@ const routes: RouteRecordRaw[] = [
component: () =>
import("@/views/admin/account/cost/myMoney/index.vue"),
},
{
path: "deposit",
name: "deposit",
component: () =>
import("@/views/admin/account/cost/deposit/index.vue"),
},
{
path: "exchange",
name: "exchange",

View File

@ -0,0 +1,540 @@
<template>
<div class="withdrawal-management">
<!-- 页面标题 -->
<a-page-header title="提现管理" />
<!-- 提现账户信息卡片 -->
<a-row :gutter="24" class="mb-6">
<a-col :span="24">
<a-card title="可提现金额">
<div class="balance-info">
<div class="balance-amount">
<span class="amount">{{ formatCurrency(accountInfo.availableBalance) }}</span>
<span class="currency"></span>
</div>
<div class="balance-desc">
当前可提现金额提现将在1-3个工作日内到账
</div>
<a-button
type="primary"
size="small"
class="w-full mt-4"
@click="showWithdrawalModal"
:disabled="accountInfo.availableBalance <= 0"
>
去提现
</a-button>
</div>
</a-card>
</a-col>
</a-row>
<!-- 提现记录查询 -->
<a-card title="提现记录" class="mb-6">
<template #extra>
<a-range-picker
v-model:value="searchParams.dateRange"
:format="dateFormat"
@change="handleDateChange"
/>
</template>
<!-- 查询条件 -->
<a-form layout="inline" :model="searchParams" class="mb-4">
<a-form-item label="提现单号">
<a-input
v-model:value="searchParams.orderNo"
placeholder="请输入提现单号"
@pressEnter="handleSearch"
/>
</a-form-item>
<a-form-item label="账户">
<a-select
v-model:value="searchParams.account"
placeholder="请选择账户"
style="width: 150px"
allowClear
>
<a-select-option v-for="account in accountOptions" :key="account.value">
{{ account.label }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="状态">
<a-select
v-model:value="searchParams.status"
placeholder="请选择状态"
style="width: 150px"
allowClear
>
<a-select-option value="pending">处理中</a-select-option>
<a-select-option value="success">成功</a-select-option>
<a-select-option value="failed">失败</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleSearch">查询</a-button>
<a-button @click="handleReset" class="ml-2">重置</a-button>
</a-form-item>
</a-form>
<!-- 提现记录表格 -->
<a-table
:columns="columns"
:data-source="withdrawalRecords"
:pagination="pagination"
@change="handleTableChange"
:loading="loading"
rowKey="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'amount'">
<span class="amount-cell">{{ formatCurrency(record.amount) }}</span>
</template>
<template v-else-if="column.key === 'status'">
<a-tag :color="getStatusColor(record.status)">
{{ getStatusText(record.status) }}
</a-tag>
</template>
<template v-else-if="column.key === 'createdAt'">
{{ formatDate(record.createdAt) }}
</template>
<template v-else-if="column.key === 'completedAt'">
{{ record.completedAt ? formatDate(record.completedAt) : '-' }}
</template>
<template v-else-if="column.key === 'actions'">
<a-button type="link" @click="viewDetail(record)">查看详情</a-button>
</template>
</template>
</a-table>
</a-card>
<!-- 提现弹窗 -->
<a-modal
v-model:visible="withdrawalModal.visible"
title="提现申请"
@ok="handleWithdrawalSubmit"
@cancel="handleWithdrawalCancel"
:confirm-loading="withdrawalModal.confirming"
>
<a-form
ref="withdrawalFormRef"
:model="withdrawalForm"
:rules="withdrawalRules"
layout="vertical"
>
<a-form-item label="提现金额" name="amount">
<a-input-number
v-model:value="withdrawalForm.amount"
placeholder="请输入提现金额"
:min="1"
:max="accountInfo.availableBalance"
style="width: 100%"
:formatter="value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
:parser="value => value.replace(/¥\s?|(,*)/g, '')"
/>
<div class="amount-hint mt-2">
<div>可提现金额: {{ formatCurrency(accountInfo.availableBalance) }}</div>
<div>单笔最低提现: 1</div>
</div>
</a-form-item>
<a-form-item label="提现到账账户" name="accountId">
<a-select
v-model:value="withdrawalForm.accountId"
placeholder="请选择提现账户"
>
<a-select-option :value="accountInfo.id">
{{ accountInfo.bank }} ({{ accountInfo.number }})
</a-select-option>
</a-select>
</a-form-item>
<a-alert
v-if="withdrawalForm.amount"
:message="`预计到账金额: ${formatCurrency(calculateActualAmount(withdrawalForm.amount))}元`"
type="info"
show-icon
class="mb-4"
/>
</a-form>
</a-modal>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
//
const accountInfo = reactive({
id: '1',
type: '银行账户',
number: '6228 **** **** 5678',
name: '张三',
bank: '中国工商银行',
availableBalance: 5000.00
})
//
const searchParams = reactive({
orderNo: '',
account: undefined,
status: undefined,
dateRange: [dayjs().subtract(30, 'day'), dayjs()]
})
//
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showQuickJumper: true,
showTotal: total => `${total} 条记录`
})
//
const columns = [
{
title: '提现单号',
dataIndex: 'orderNo',
key: 'orderNo',
width: 200
},
{
title: '账户',
key: 'account',
width: 180,
render: (_, record) => `${record.bank} (${record.accountNumber})`
},
{
title: '提现金额',
key: 'amount',
width: 120,
align: 'right'
},
{
title: '手续费',
dataIndex: 'fee',
key: 'fee',
width: 100,
align: 'right',
render: fee => fee ? `${fee}` : '-'
},
{
title: '状态',
key: 'status',
width: 100
},
{
title: '申请时间',
key: 'createdAt',
width: 180
},
{
title: '完成时间',
key: 'completedAt',
width: 180
},
{
title: '操作',
key: 'actions',
width: 100,
fixed: 'right'
}
]
//
const withdrawalRecords = ref([])
const loading = ref(false)
const accountOptions = ref([
{ value: '1', label: '工商银行(尾号5678)' },
{ value: '2', label: '建设银行(尾号1234)' }
])
//
const withdrawalModal = reactive({
visible: false,
confirming: false
})
//
const withdrawalFormRef = ref()
const withdrawalForm = reactive({
amount: undefined,
accountId: accountInfo.id
})
//
const withdrawalRules = {
amount: [
{ required: true, message: '请输入提现金额' },
{ type: 'number', min: 1, max: accountInfo.availableBalance, message: `提现金额需在1-${accountInfo.availableBalance}元之间` }
],
accountId: [
{ required: true, message: '请选择提现账户' }
]
}
//
const dateFormat = 'YYYY-MM-DD'
//
onMounted(() => {
fetchWithdrawalRecords()
})
//
const fetchWithdrawalRecords = async () => {
loading.value = true
try {
// API
await new Promise(resolve => setTimeout(resolve, 500))
//
const mockData = Array.from({ length: 35 }, (_, index) => ({
id: index + 1,
orderNo: `TX${Date.now()}${index}`,
bank: ['工商银行', '建设银行', '农业银行'][index % 3],
accountNumber: `6228 **** **** ${1000 + index}`,
amount: Math.floor(Math.random() * 10000) + 100,
fee: Math.floor(Math.random() * 10),
status: ['pending', 'success', 'failed'][index % 3],
createdAt: dayjs().subtract(index, 'day').format('YYYY-MM-DD HH:mm:ss'),
completedAt: index % 3 !== 0 ? dayjs().subtract(index, 'day').add(1, 'hour').format('YYYY-MM-DD HH:mm:ss') : null
}))
//
let filteredData = mockData
if (searchParams.orderNo) {
filteredData = filteredData.filter(item => item.orderNo.includes(searchParams.orderNo))
}
if (searchParams.account) {
filteredData = filteredData.filter(item => item.accountNumber.endsWith(searchParams.account))
}
if (searchParams.status) {
filteredData = filteredData.filter(item => item.status === searchParams.status)
}
//
if (searchParams.dateRange && searchParams.dateRange[0] && searchParams.dateRange[1]) {
const start = searchParams.dateRange[0]
const end = searchParams.dateRange[1]
filteredData = filteredData.filter(item => {
const date = dayjs(item.createdAt)
return date.isAfter(start) && date.isBefore(end)
})
}
//
const start = (pagination.current - 1) * pagination.pageSize
const end = start + pagination.pageSize
withdrawalRecords.value = filteredData.slice(start, end)
pagination.total = filteredData.length
} catch (error) {
message.error('获取提现记录失败')
} finally {
loading.value = false
}
}
//
const handleTableChange = (page) => {
pagination.current = page.current
pagination.pageSize = page.pageSize
fetchWithdrawalRecords()
}
//
const handleSearch = () => {
pagination.current = 1
fetchWithdrawalRecords()
}
//
const handleReset = () => {
searchParams.orderNo = ''
searchParams.account = undefined
searchParams.status = undefined
searchParams.dateRange = [dayjs().subtract(30, 'day'), dayjs()]
handleSearch()
}
//
const handleDateChange = () => {
handleSearch()
}
//
const showWithdrawalModal = () => {
withdrawalModal.visible = true
}
//
const handleWithdrawalSubmit = async () => {
try {
await withdrawalFormRef.value.validate()
withdrawalModal.confirming = true
// API
await new Promise(resolve => setTimeout(resolve, 1000))
message.success('提现申请提交成功')
//
accountInfo.availableBalance -= withdrawalForm.amount
//
withdrawalFormRef.value.resetFields()
withdrawalModal.visible = false
//
fetchWithdrawalRecords()
} catch (error) {
console.error('提现提交失败:', error)
} finally {
withdrawalModal.confirming = false
}
}
//
const handleWithdrawalCancel = () => {
withdrawalFormRef.value.resetFields()
withdrawalModal.visible = false
}
//
const viewDetail = (record) => {
message.info(`查看提现记录详情: ${record.orderNo}`)
}
//
const calculateActualAmount = (amount) => {
const fee = amount * 0.01 // 1%
return amount - fee
}
//
const formatCurrency = (amount) => {
return amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')
}
//
const formatDate = (dateString) => {
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
}
//
const getStatusColor = (status) => {
const colors = {
pending: 'orange',
success: 'green',
failed: 'red'
}
return colors[status] || 'default'
}
//
const getStatusText = (status) => {
const texts = {
pending: '处理中',
success: '成功',
failed: '失败'
}
return texts[status] || status
}
</script>
<style scoped>
.withdrawal-management {
padding: 20px;
}
.account-info .info-item {
margin-bottom: 12px;
font-size: 14px;
}
.account-info .label {
color: #666;
margin-right: 8px;
}
.account-info .value {
color: #333;
font-weight: 500;
}
.balance-info .balance-amount {
text-align: center;
margin-bottom: 8px;
}
.balance-info .amount {
font-size: 32px;
font-weight: bold;
color: #1890ff;
}
.balance-info .currency {
font-size: 18px;
color: #666;
margin-left: 4px;
}
.balance-info .balance-desc {
color: #666;
font-size: 12px;
text-align: center;
margin-bottom: 16px;
}
.amount-hint {
color: #666;
font-size: 12px;
}
.amount-hint div {
margin-bottom: 4px;
}
.amount-cell {
color: #1890ff;
font-weight: 500;
}
.mb-4 {
margin-bottom: 16px;
}
.mb-6 {
margin-bottom: 24px;
}
.mt-2 {
margin-top: 8px;
}
.mt-4 {
margin-top: 16px;
}
.ml-2 {
margin-left: 8px;
}
.w-full {
float: inline-end;
width: 10%;
}
</style>

View File

@ -1,60 +1,6 @@
<template>
<a-row :gutter="[18, 18]">
<a-col :span="24">
<a-row :gutter="18">
<a-col :span="12" style="display: flex;">
<a-card style="flex: 1; display: flex; flex-direction: column;">
<template #title>
<span>可开票:&nbsp;&nbsp;</span>
<span>¥&nbsp;</span><span class="bold">0.00</span>
</template>
<template #extra>
<a-button type="primary" ghost>去开票</a-button>
</template>
<div style="display: flex;justify-content: space-around;align-items: center;line-height: 30px;">
<div>
<div>可开票金额</div>
<div><span>¥&nbsp;</span><span class="bold">0.00</span></div>
</div>
<div>
<div>&nbsp;</div>
<div>=</div>
</div>
<div>
<div>累计充值</div>
<div><span>¥&nbsp;</span><span class="bold">0.00</span></div>
</div>
<div>
<div>&nbsp;</div>
<div>-</div>
</div>
<div>
<div>充值已开票</div>
<div><span>¥&nbsp;</span><span class="bold">0.00</span></div>
</div>
<div>
<div>&nbsp;</div>
<div>-</div>
</div>
<div>
<div>账单已开票</div>
<div><span>¥&nbsp;</span><span class="bold">0.00</span></div>
</div>
</div>
</a-card>
</a-col>
<a-col :span="12" style="display: flex;">
<a-card style="flex: 1; display: flex; flex-direction: column;">
<template #title>
<span>发票信息:&nbsp;&nbsp;</span>
</template>
<div>
暂无发票信息<a href="javascript:;" @click="visibleOpen = true">去添加</a>
</div>
</a-card>
</a-col>
</a-row>
</a-col>
<a-col :span="24">
<a-card title="开票记录">
<a-table :dataSource="listData" :columns="columns" bordered :pagination="paginationState"

View File

@ -62,13 +62,15 @@ const menuItems: MenuItem[] = [
children: [
{ path: '/layout/admin/myMoney', name: '费用总览', visible: true, disabled: false },
{ path: '/layout/admin/balance', name: '余额管理', visible: true, disabled: false },
{ path: '/layout/admin/invoice', name: '发票管理', disabled: false, visible: true },
{ path: '/layout/admin/deposit', name: '提现管理', disabled: false, visible: true },
//
{ path: '/layout/admin/exchange', name: '算力点兑换', visible: false, disabled: false },
{ path: '/layout/admin/myMoneyDetail', name: '消费明细', visible: false, disabled: false },
{ path: '/layout/admin/myOrder', name: '订单明细', visible: true, disabled: false },
{ path: '/layout/admin/flow', name: '账单明细', visible: true, disabled: false },
{ path: '/layout/admin/coupon', name: '优惠券(待开发)', disabled: true, visible: true },
{ path: '/layout/admin/invoice', name: '发票(待开发)', disabled: true, visible: true },
{ path: '/layout/admin/voucher', name: '代金券(待开发)', disabled: true, visible: true },
{ path: '/layout/admin/contract', name: '合同(待开发)', disabled: true, visible: true },
],