余额管理
This commit is contained in:
parent
b0df62b28d
commit
18c638d03b
@ -233,6 +233,13 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import("@/views/admin/account/cost/myOrder/index.vue"),
|
import("@/views/admin/account/cost/myOrder/index.vue"),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "balance",
|
||||||
|
name: "balance",
|
||||||
|
component: () =>
|
||||||
|
import("@/views/admin/account/cost/balance/index.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "myMoney",
|
path: "myMoney",
|
||||||
name: "myMoney",
|
name: "myMoney",
|
||||||
|
|||||||
830
src/views/admin/account/cost/balance/index.vue
Normal file
830
src/views/admin/account/cost/balance/index.vue
Normal file
@ -0,0 +1,830 @@
|
|||||||
|
<template>
|
||||||
|
<div class="recharge-page">
|
||||||
|
<!-- 面包屑导航 -->
|
||||||
|
<a-breadcrumb class="breadcrumb">
|
||||||
|
<a-breadcrumb-item>
|
||||||
|
<router-link to="/">首页</router-link>
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
<a-breadcrumb-item>我的余额</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
|
||||||
|
<!-- 页面标题 -->
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 class="page-title">我的余额</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<!-- 余额和充值部分 -->
|
||||||
|
<div class="balance-section">
|
||||||
|
<!-- 余额卡片(带充值方式) -->
|
||||||
|
<a-card class="balance-card" :bordered="false">
|
||||||
|
<div class="balance-header">
|
||||||
|
<div class="balance-info">
|
||||||
|
<div class="balance-amount">
|
||||||
|
<div class="amount-label">账户余额</div>
|
||||||
|
<div class="amount-value">¥{{ formatCurrency(balance) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="recharge-content">
|
||||||
|
<!-- 充值金额选择 -->
|
||||||
|
<div class="recharge-section">
|
||||||
|
<h3 class="section-title">充值金额(¥)</h3>
|
||||||
|
<div class="amount-options">
|
||||||
|
<div
|
||||||
|
v-for="option in amountOptions"
|
||||||
|
:key="option.value"
|
||||||
|
:class="['amount-option', { 'selected': selectedAmount === option.value }]"
|
||||||
|
@click="selectAmount(option.value)"
|
||||||
|
>
|
||||||
|
<div class="amount-number">¥{{ option.value }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 自定义金额输入 -->
|
||||||
|
<div class="recharge-section">
|
||||||
|
<h3 class="section-title">自定义充值金额</h3>
|
||||||
|
<div class="custom-amount">
|
||||||
|
<a-input
|
||||||
|
v-model:value="customAmount"
|
||||||
|
placeholder="请输入金额"
|
||||||
|
size="large"
|
||||||
|
:disabled="loading"
|
||||||
|
@change="handleCustomAmountChange"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<span class="input-prefix">¥</span>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
<div v-if="customAmountError" class="error-text">
|
||||||
|
{{ customAmountError }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 充值方式 -->
|
||||||
|
<div class="payment-methods-container">
|
||||||
|
<div class="payment-methods-title">充值方式</div>
|
||||||
|
<div class="payment-methods-row">
|
||||||
|
<div
|
||||||
|
v-for="method in paymentMethods"
|
||||||
|
:key="method.value"
|
||||||
|
:class="['payment-method-item', { 'selected': selectedPaymentMethod === method.value }]"
|
||||||
|
@click="selectPaymentMethod(method.value)"
|
||||||
|
>
|
||||||
|
<div class="method-icon">
|
||||||
|
<component :is="method.icon" />
|
||||||
|
</div>
|
||||||
|
<div class="method-info">
|
||||||
|
<div class="method-name">{{ method.name }}</div>
|
||||||
|
<div v-if="method.description" class="method-desc">{{ method.description }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedPaymentMethod === method.value" class="method-selected">
|
||||||
|
<CheckCircleFilled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="action-section">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
:loading="loading"
|
||||||
|
:disabled="!canRecharge"
|
||||||
|
@click="handleRecharge"
|
||||||
|
class="recharge-btn"
|
||||||
|
>
|
||||||
|
立即充值
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 充值记录 -->
|
||||||
|
<a-card class="records-card" title="充值记录">
|
||||||
|
<!-- 筛选条件 -->
|
||||||
|
<div class="filter-section">
|
||||||
|
<a-range-picker
|
||||||
|
v-model:value="dateRange"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
placeholder="开始时间 - 结束时间"
|
||||||
|
style="width: 300px; margin-right: 16px;"
|
||||||
|
/>
|
||||||
|
<a-button type="primary" @click="handleSearch" :loading="searchLoading">
|
||||||
|
<template #icon><SearchOutlined /></template>
|
||||||
|
查询
|
||||||
|
</a-button>
|
||||||
|
<a-button style="margin-left: 8px" @click="handleReset">
|
||||||
|
重置
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 记录表格 -->
|
||||||
|
<div class="records-table">
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="rechargeRecords"
|
||||||
|
:pagination="pagination"
|
||||||
|
:loading="tableLoading"
|
||||||
|
@change="handleTableChange"
|
||||||
|
size="middle"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'amount'">
|
||||||
|
<span class="amount-cell">¥{{ record.amount }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rechargeTime'">
|
||||||
|
{{ formatDateTime(record.rechargeTime) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'paymentMethod'">
|
||||||
|
<a-tag :color="getPaymentMethodColor(record.paymentMethod)">
|
||||||
|
{{ getPaymentMethodLabel(record.paymentMethod) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'accountBalance'">
|
||||||
|
¥{{ formatCurrency(record.accountBalance) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'status'">
|
||||||
|
<a-tag :color="getStatusColor(record.status)">
|
||||||
|
{{ getStatusLabel(record.status) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<a-button type="link" size="small" @click="viewDetail(record)">详情</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #emptyText>
|
||||||
|
<div class="empty-state">
|
||||||
|
<a-empty description="暂无充值记录" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 充值确认模态框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="rechargeModalVisible"
|
||||||
|
title="确认充值"
|
||||||
|
:confirm-loading="modalLoading"
|
||||||
|
@ok="handleRechargeConfirm"
|
||||||
|
@cancel="handleRechargeCancel"
|
||||||
|
centered
|
||||||
|
>
|
||||||
|
<div class="recharge-confirm">
|
||||||
|
<div class="confirm-item">
|
||||||
|
<span class="confirm-label">充值金额:</span>
|
||||||
|
<span class="confirm-value">¥{{ selectedRechargeAmount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="confirm-item">
|
||||||
|
<span class="confirm-label">充值方式:</span>
|
||||||
|
<span class="confirm-value">{{ getPaymentMethodLabel(selectedPaymentMethod) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="confirm-item">
|
||||||
|
<span class="confirm-label">当前余额:</span>
|
||||||
|
<span class="confirm-value">¥{{ formatCurrency(balance) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="confirm-item">
|
||||||
|
<span class="confirm-label">充值后余额:</span>
|
||||||
|
<span class="confirm-value highlight">¥{{ formatCurrency(balance + selectedRechargeAmount) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="confirm-tips">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
充值成功后,金额将立即到账
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
|
import {
|
||||||
|
SearchOutlined,
|
||||||
|
CheckCircleFilled,
|
||||||
|
InfoCircleOutlined,
|
||||||
|
AlipayOutlined,
|
||||||
|
WechatOutlined,
|
||||||
|
BankOutlined
|
||||||
|
} from '@ant-design/icons-vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
// 用户余额
|
||||||
|
const balance = ref(5.00)
|
||||||
|
|
||||||
|
// 充值金额选项
|
||||||
|
const amountOptions = ref([
|
||||||
|
{ value: 100, label: '100元' },
|
||||||
|
{ value: 500, label: '500元' },
|
||||||
|
{ value: 1000, label: '1000元' },
|
||||||
|
{ value: 5000, label: '5000元' }
|
||||||
|
])
|
||||||
|
|
||||||
|
const selectedAmount = ref(0)
|
||||||
|
const customAmount = ref('')
|
||||||
|
const customAmountError = ref('')
|
||||||
|
|
||||||
|
// 充值方式
|
||||||
|
const paymentMethods = ref([
|
||||||
|
{ value: 'alipay', name: '支付宝支付', icon: AlipayOutlined, color: '#1677ff' },
|
||||||
|
{ value: 'wechat', name: '微信支付', icon: WechatOutlined, color: '#07c160' },
|
||||||
|
{ value: 'bank', name: '对公付款', icon: BankOutlined, color: '#722ed1' }
|
||||||
|
])
|
||||||
|
const selectedPaymentMethod = ref('alipay')
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableLoading = ref(false)
|
||||||
|
const searchLoading = ref(false)
|
||||||
|
const modalLoading = ref(false)
|
||||||
|
|
||||||
|
// 模态框
|
||||||
|
const rechargeModalVisible = ref(false)
|
||||||
|
|
||||||
|
// 筛选条件
|
||||||
|
const dateRange = ref([])
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
const rechargeRecords = ref([])
|
||||||
|
|
||||||
|
// 表格列
|
||||||
|
const columns = ref([
|
||||||
|
{ title: '充值金额', dataIndex: 'amount', key: 'amount', align: 'right', width: 120 },
|
||||||
|
{ title: '充值时间', dataIndex: 'rechargeTime', key: 'rechargeTime', width: 180, sorter: true },
|
||||||
|
{ title: '支付方式', dataIndex: 'paymentMethod', key: 'paymentMethod', width: 120 },
|
||||||
|
{ title: '账户余额', dataIndex: 'accountBalance', key: 'accountBalance', align: 'right', width: 140 },
|
||||||
|
{ title: '状态', dataIndex: 'status', key: 'status', width: 100 },
|
||||||
|
{ title: '操作', key: 'action', width: 80, align: 'center' }
|
||||||
|
])
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条记录`,
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100']
|
||||||
|
})
|
||||||
|
|
||||||
|
// 选中金额(优先自定义)
|
||||||
|
const selectedRechargeAmount = computed(() => {
|
||||||
|
if (selectedAmount.value > 0) return selectedAmount.value
|
||||||
|
const amount = parseFloat(customAmount.value)
|
||||||
|
return isNaN(amount) || amount <= 0 ? 0 : amount
|
||||||
|
})
|
||||||
|
|
||||||
|
const canRecharge = computed(() => {
|
||||||
|
return selectedRechargeAmount.value > 0 && selectedPaymentMethod.value && !loading.value
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化货币(带千分位)
|
||||||
|
const formatCurrency = (value) => {
|
||||||
|
return parseFloat(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化日期
|
||||||
|
const formatDateTime = (dateTime) => {
|
||||||
|
return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择预设金额
|
||||||
|
const selectAmount = (amount) => {
|
||||||
|
selectedAmount.value = amount
|
||||||
|
customAmount.value = ''
|
||||||
|
customAmountError.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义金额校验
|
||||||
|
const handleCustomAmountChange = () => {
|
||||||
|
selectedAmount.value = 0
|
||||||
|
const val = customAmount.value.trim()
|
||||||
|
if (!val) {
|
||||||
|
customAmountError.value = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const amount = parseFloat(val)
|
||||||
|
if (isNaN(amount) || amount <= 0) {
|
||||||
|
customAmountError.value = '请输入有效金额'
|
||||||
|
} else if (amount < 1) {
|
||||||
|
customAmountError.value = '充值金额不能小于1元'
|
||||||
|
} else if (amount > 50000) {
|
||||||
|
customAmountError.value = '单次最大充值金额为50000元'
|
||||||
|
} else {
|
||||||
|
customAmountError.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择支付方式
|
||||||
|
const selectPaymentMethod = (method) => {
|
||||||
|
selectedPaymentMethod.value = method
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支付方式标签 & 颜色
|
||||||
|
const getPaymentMethodLabel = (method) => {
|
||||||
|
const payment = paymentMethods.value.find(m => m.value === method)
|
||||||
|
return payment ? payment.name : method
|
||||||
|
}
|
||||||
|
const getPaymentMethodColor = (method) => {
|
||||||
|
const payment = paymentMethods.value.find(m => m.value === method)
|
||||||
|
return payment ? payment.color : 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态标签 & 颜色
|
||||||
|
const getStatusLabel = (status) => {
|
||||||
|
const map = { success: '成功', processing: '处理中', failed: '失败', pending: '待支付' }
|
||||||
|
return map[status] || status
|
||||||
|
}
|
||||||
|
const getStatusColor = (status) => {
|
||||||
|
const map = { success: 'green', processing: 'blue', failed: 'red', pending: 'orange' }
|
||||||
|
return map[status] || 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 充值主流程
|
||||||
|
const handleRecharge = () => {
|
||||||
|
if (selectedRechargeAmount.value <= 0) return message.error('请选择或输入充值金额')
|
||||||
|
if (!selectedPaymentMethod.value) return message.error('请选择支付方式')
|
||||||
|
rechargeModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认充值
|
||||||
|
const handleRechargeConfirm = () => {
|
||||||
|
modalLoading.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
balance.value += selectedRechargeAmount.value
|
||||||
|
const now = new Date()
|
||||||
|
const newRecord = {
|
||||||
|
key: rechargeRecords.value.length + 1,
|
||||||
|
amount: selectedRechargeAmount.value,
|
||||||
|
rechargeTime: now,
|
||||||
|
paymentMethod: selectedPaymentMethod.value,
|
||||||
|
accountBalance: balance.value,
|
||||||
|
status: 'success'
|
||||||
|
}
|
||||||
|
rechargeRecords.value.unshift(newRecord)
|
||||||
|
pagination.total += 1
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
selectedAmount.value = 0
|
||||||
|
customAmount.value = ''
|
||||||
|
customAmountError.value = ''
|
||||||
|
|
||||||
|
modalLoading.value = false
|
||||||
|
rechargeModalVisible.value = false
|
||||||
|
message.success(`充值成功!¥${selectedRechargeAmount.value} 已到账`)
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRechargeCancel = () => {
|
||||||
|
rechargeModalVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 充值记录查询
|
||||||
|
const handleSearch = () => {
|
||||||
|
searchLoading.value = true
|
||||||
|
pagination.current = 1
|
||||||
|
loadRechargeRecords()
|
||||||
|
}
|
||||||
|
const handleReset = () => {
|
||||||
|
dateRange.value = []
|
||||||
|
pagination.current = 1
|
||||||
|
loadRechargeRecords()
|
||||||
|
}
|
||||||
|
const handleTableChange = (pag) => {
|
||||||
|
pagination.current = pag.current
|
||||||
|
pagination.pageSize = pag.pageSize
|
||||||
|
loadRechargeRecords()
|
||||||
|
}
|
||||||
|
const viewDetail = (record) => {
|
||||||
|
message.info(`充值¥${record.amount},时间:${formatDateTime(record.rechargeTime)}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载记录(含模拟数据)
|
||||||
|
const loadRechargeRecords = () => {
|
||||||
|
tableLoading.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
const mockData = generateMockData(35)
|
||||||
|
let filtered = [...mockData]
|
||||||
|
|
||||||
|
if (dateRange.value?.length === 2) {
|
||||||
|
const start = dayjs(dateRange.value[0]).startOf('day')
|
||||||
|
const end = dayjs(dateRange.value[1]).endOf('day')
|
||||||
|
filtered = filtered.filter(r => {
|
||||||
|
const d = dayjs(r.rechargeTime)
|
||||||
|
return d.isAfter(start) && d.isBefore(end)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const startIdx = (pagination.current - 1) * pagination.pageSize
|
||||||
|
rechargeRecords.value = filtered.slice(startIdx, startIdx + pagination.pageSize)
|
||||||
|
pagination.total = filtered.length
|
||||||
|
|
||||||
|
tableLoading.value = false
|
||||||
|
searchLoading.value = false
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成模拟数据(无算力点)
|
||||||
|
const generateMockData = (count) => {
|
||||||
|
const methods = ['alipay', 'wechat', 'bank']
|
||||||
|
const statuses = ['success', 'processing', 'failed', 'pending']
|
||||||
|
let currentBalance = 5.00
|
||||||
|
const data = []
|
||||||
|
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
const amount = [100, 500, 1000, 5000][Math.floor(Math.random() * 4)]
|
||||||
|
const method = methods[Math.floor(Math.random() * methods.length)]
|
||||||
|
const status = statuses[Math.floor(Math.random() * statuses.length)]
|
||||||
|
|
||||||
|
if (status === 'success') currentBalance += amount
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
key: i,
|
||||||
|
amount: amount,
|
||||||
|
rechargeTime: dayjs().subtract(Math.floor(Math.random() * 30), 'day').toDate(),
|
||||||
|
paymentMethod: method,
|
||||||
|
accountBalance: currentBalance,
|
||||||
|
status: status
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.sort((a, b) => new Date(b.rechargeTime) - new Date(a.rechargeTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
rechargeRecords.value = generateMockData(15)
|
||||||
|
pagination.total = rechargeRecords.value.length
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.recharge-page {
|
||||||
|
padding: 24px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 余额区域 */
|
||||||
|
.balance-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-card {
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-card :deep(.ant-card-body) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.balance-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-info {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-amount {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 充值方式容器 */
|
||||||
|
.payment-methods-container {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-methods-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-methods-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.payment-methods-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-method-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #fff;
|
||||||
|
transition: all 0.2s;
|
||||||
|
min-width: 150px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.payment-method-item {
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-method-item:hover {
|
||||||
|
border-color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-method-item.selected {
|
||||||
|
border-color: #1890ff;
|
||||||
|
background: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 12px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-method-item:nth-child(1) .method-icon { color: #1677ff; }
|
||||||
|
.payment-method-item:nth-child(2) .method-icon { color: #07c160; }
|
||||||
|
.payment-method-item:nth-child(3) .method-icon { color: #722ed1; }
|
||||||
|
|
||||||
|
.method-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1f1f1f;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-desc {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-selected {
|
||||||
|
color: #52c41a;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 充值内容 */
|
||||||
|
.recharge-content {
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 金额选项 */
|
||||||
|
.amount-options {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.amount-options {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.amount-options {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-option {
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 14px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: #fff;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-option:hover {
|
||||||
|
border-color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-option.selected {
|
||||||
|
border-color: #1890ff;
|
||||||
|
background: #e6f7ff;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义金额 */
|
||||||
|
.custom-amount {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-amount :deep(.ant-input) {
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-prefix {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮 */
|
||||||
|
.action-section {
|
||||||
|
margin-top: 32px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge-btn {
|
||||||
|
width: 200px;
|
||||||
|
height: 44px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 充值记录 */
|
||||||
|
.records-card {
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.records-card :deep(.ant-card-head) {
|
||||||
|
border-bottom: none;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.records-card :deep(.ant-card-head-title) {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.records-card :deep(.ant-card-body) {
|
||||||
|
padding: 0 24px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.filter-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.records-table {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-cell {
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 模态框 */
|
||||||
|
.recharge-confirm {
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-label {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-value {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-value.highlight {
|
||||||
|
color: #52c41a;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-tips {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f6ffed;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #52c41a;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-tips .anticon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -61,6 +61,7 @@ const menuItems: MenuItem[] = [
|
|||||||
visible: true,
|
visible: true,
|
||||||
children: [
|
children: [
|
||||||
{ path: '/layout/admin/myMoney', name: '费用总览', visible: true, disabled: false },
|
{ path: '/layout/admin/myMoney', name: '费用总览', visible: true, disabled: false },
|
||||||
|
{ path: '/layout/admin/balance', name: '余额管理', visible: true, disabled: false },
|
||||||
// 消费明细设置为不可见
|
// 消费明细设置为不可见
|
||||||
{ path: '/layout/admin/exchange', name: '算力点兑换', visible: false, disabled: false },
|
{ path: '/layout/admin/exchange', name: '算力点兑换', visible: false, disabled: false },
|
||||||
{ path: '/layout/admin/myMoneyDetail', name: '消费明细', visible: false, disabled: false },
|
{ path: '/layout/admin/myMoneyDetail', name: '消费明细', visible: false, disabled: false },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user