Files
medical-mall/pages/mall/admin/finance-management.uvue

1583 lines
36 KiB
Plaintext
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.
<template>
<AdminLayout current-page="finance">
<view class="finance-management">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">财务管理</text>
<text class="page-subtitle">管理系统财务数据和报表</text>
</view>
<!-- Tab 切换栏 -->
<view class="tab-bar">
<view
v-for="tab in tabs"
:key="tab.key"
class="tab-item"
:class="{ 'active': activeTab === tab.key }"
@click="switchTab(tab.key)"
>
<text class="iconfont tab-icon">{{ tab.icon }}</text>
<text class="tab-title">{{ tab.title }}</text>
</view>
</view>
<!-- 财务概览Tab -->
<view v-if="activeTab === 'finance-overview'">
<!-- 财务概览 -->
<view class="finance-overview">
<view class="overview-cards">
<view class="overview-card">
<view class="card-icon">💰</view>
<view class="card-content">
<text class="card-value">¥{{ totalRevenue }}</text>
<text class="card-label">总收入</text>
</view>
</view>
<view class="overview-card">
<view class="card-icon">📈</view>
<view class="card-content">
<text class="card-value">¥{{ monthlyRevenue }}</text>
<text class="card-label">本月收入</text>
</view>
</view>
<view class="overview-card">
<view class="card-icon">📊</view>
<view class="card-content">
<text class="card-value">{{ orderCount }}</text>
<text class="card-label">订单数量</text>
</view>
</view>
<view class="overview-card">
<view class="card-icon">💳</view>
<view class="card-content">
<text class="card-value">{{ pendingWithdrawals }}</text>
<text class="card-label">待提现</text>
</view>
</view>
</view>
<!-- 收入趋势图表 -->
<view class="chart-section">
<view class="chart-header">
<text class="chart-title">收入趋势</text>
<view class="chart-controls">
<button
class="period-btn"
:class="{ 'active': chartPeriod === 'week' }"
@click="setChartPeriod('week')"
>
本周
</button>
<button
class="period-btn"
:class="{ 'active': chartPeriod === 'month' }"
@click="setChartPeriod('month')"
>
本月
</button>
<button
class="period-btn"
:class="{ 'active': chartPeriod === 'year' }"
@click="setChartPeriod('year')"
>
本年
</button>
</view>
</view>
<view class="chart-placeholder">
<text class="chart-placeholder-text">📊 图表区域 - 收入趋势可视化</text>
<text class="chart-placeholder-subtext">集成图表库后可显示实际数据</text>
</view>
</view>
</view>
<!-- 财务操作 -->
<view class="finance-actions">
<view class="action-section">
<text class="section-title">财务操作</text>
<view class="action-buttons">
<button class="action-btn primary" @click="showWithdrawalModal = true">
<text class="btn-icon">💸</text>
<text class="btn-text">申请提现</text>
</button>
<button class="action-btn secondary" @click="showTransferModal = true">
<text class="btn-icon">🔄</text>
<text class="btn-text">转账</text>
</button>
<button class="action-btn info" @click="showRechargeModal = true">
<text class="btn-icon">💳</text>
<text class="btn-text">充值</text>
</button>
</view>
</view>
<view class="action-section">
<text class="section-title">财务报表</text>
<view class="action-buttons">
<button class="action-btn success" @click="generateReport('daily')">
<text class="btn-icon">📅</text>
<text class="btn-text">日报表</text>
</button>
<button class="action-btn warning" @click="generateReport('monthly')">
<text class="btn-icon">📊</text>
<text class="btn-text">月报表</text>
</button>
<button class="action-btn danger" @click="generateReport('yearly')">
<text class="btn-icon">📈</text>
<text class="btn-text">年报表</text>
</button>
</view>
</view>
</view>
<!-- 交易记录 -->
<view class="transaction-section">
<view class="section-header">
<text class="section-title">交易记录</text>
<view class="section-controls">
<input
v-model="transactionSearch"
class="search-input"
placeholder="搜索交易..."
/>
<picker
mode="selector"
:range="transactionTypes"
:value="selectedTransactionType"
@change="handleTransactionTypeChange"
>
<view class="type-selector">
<text>{{ transactionTypes[selectedTransactionType] }}</text>
<text class="iconfont icon-down"></text>
</view>
</picker>
</view>
</view>
<view class="transaction-table">
<view class="table-header">
<view class="table-row">
<view class="col-time">时间</view>
<view class="col-type">类型</view>
<view class="col-description">描述</view>
<view class="col-amount">金额</view>
<view class="col-status">状态</view>
<view class="col-actions">操作</view>
</view>
</view>
<view class="table-body">
<view
v-for="transaction in filteredTransactions"
:key="transaction.id"
class="table-row"
>
<view class="col-time">
<text class="transaction-time">{{ formatDateTime(transaction.time) }}</text>
</view>
<view class="col-type">
<view class="type-badge" :class="transaction.type">
{{ transaction.type === 'income' ? '收入' :
transaction.type === 'expense' ? '支出' :
transaction.type === 'withdrawal' ? '提现' :
transaction.type === 'recharge' ? '充值' : '转账' }}
</view>
</view>
<view class="col-description">
<text class="transaction-desc">{{ transaction.description }}</text>
<text class="transaction-ref" v-if="transaction.reference">
{{ transaction.reference }}
</text>
</view>
<view class="col-amount">
<text
class="transaction-amount"
:class="{ 'income': transaction.type === 'income' || transaction.type === 'recharge',
'expense': transaction.type === 'expense' || transaction.type === 'withdrawal' }"
>
{{ transaction.type === 'income' || transaction.type === 'recharge' ? '+' : '-' }}¥{{ transaction.amount }}
</text>
</view>
<view class="col-status">
<view class="status-badge" :class="transaction.status">
{{ transaction.status === 'completed' ? '已完成' :
transaction.status === 'pending' ? '处理中' :
transaction.status === 'failed' ? '失败' : '已取消' }}
</view>
</view>
<view class="col-actions">
<button class="action-btn view" @click="viewTransactionDetail(transaction)">
<text class="iconfont icon-view"></text>
</button>
</view>
</view>
</view>
</view>
<!-- 分页 -->
<view class="pagination">
<view class="page-info">
<text>共 {{ totalTransactions }} 条记录,显示 {{ (currentPage - 1) * pageSize + 1 }}-{{ Math.min(currentPage * pageSize, totalTransactions) }} 条</text>
</view>
<view class="page-controls">
<button
class="page-btn"
:disabled="currentPage === 1"
@click="goToPage(currentPage - 1)"
>
上一页
</button>
<view class="page-numbers">
<button
v-for="page in visiblePages"
:key="page"
class="page-number"
:class="{ 'active': page === currentPage }"
@click="goToPage(page)"
>
{{ page }}
</button>
</view>
<button
class="page-btn"
:disabled="currentPage === totalPages"
@click="goToPage(currentPage + 1)"
>
下一页
</button>
</view>
</view>
</view>
<!-- 提现模态框 -->
<view v-if="showWithdrawalModal" class="modal-overlay" @click="closeModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">申请提现</text>
<view class="modal-close" @click="closeModal">
<text class="iconfont icon-close"></text>
</view>
</view>
<view class="modal-body">
<view class="withdrawal-info">
<view class="info-item">
<text class="info-label">可用余额:</text>
<text class="info-value">¥{{ availableBalance }}</text>
</view>
<view class="info-item">
<text class="info-label">最低提现金额:</text>
<text class="info-value">¥100.00</text>
</view>
</view>
<view class="form-group">
<text class="form-label">提现金额</text>
<input
v-model="withdrawalAmount"
class="form-input"
placeholder="请输入提现金额"
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">收款账户</text>
<picker
mode="selector"
:range="accountOptions"
:value="selectedAccount"
@change="handleAccountChange"
>
<view class="form-select">
<text>{{ accountOptions[selectedAccount] }}</text>
<text class="iconfont icon-down"></text>
</view>
</picker>
</view>
<view class="form-group">
<text class="form-label">备注</text>
<input
v-model="withdrawalNote"
class="form-input"
placeholder="可选"
/>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="closeModal">取消</button>
<button class="btn-primary" @click="submitWithdrawal">
提交申请
</button>
</view>
</view>
</view>
<!-- 转账模态框 -->
<view v-if="showTransferModal" class="modal-overlay" @click="closeModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">转账</text>
<view class="modal-close" @click="closeModal">
<text class="iconfont icon-close"></text>
</view>
</view>
<view class="modal-body">
<view class="form-group">
<text class="form-label">收款账户</text>
<input
v-model="transferToAccount"
class="form-input"
placeholder="请输入收款账户"
/>
</view>
<view class="form-group">
<text class="form-label">转账金额</text>
<input
v-model="transferAmount"
class="form-input"
placeholder="请输入转账金额"
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">备注</text>
<input
v-model="transferNote"
class="form-input"
placeholder="可选"
/>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="closeModal">取消</button>
<button class="btn-primary" @click="submitTransfer">
确认转账
</button>
</view>
</view>
</view>
<!-- 充值模态框 -->
<view v-if="showRechargeModal" class="modal-overlay" @click="closeModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">充值</text>
<view class="modal-close" @click="closeModal">
<text class="iconfont icon-close"></text>
</view>
</view>
<view class="modal-body">
<view class="form-group">
<text class="form-label">充值金额</text>
<input
v-model="rechargeAmount"
class="form-input"
placeholder="请输入充值金额"
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">支付方式</text>
<picker
mode="selector"
:range="paymentOptions"
:value="selectedPayment"
@change="handlePaymentChange"
>
<view class="form-select">
<text>{{ paymentOptions[selectedPayment] }}</text>
<text class="iconfont icon-down"></text>
</view>
</picker>
</view>
<view class="form-group">
<text class="form-label">备注</text>
<input
v-model="rechargeNote"
class="form-input"
placeholder="可选"
/>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="closeModal">取消</button>
<button class="btn-primary" @click="submitRecharge">
确认充值
</button>
</view>
</view>
<!-- 提现管理Tab -->
<view v-if="activeTab === 'withdrawals'" class="withdrawals-section">
<view class="withdrawals-management">
<view class="section-header">
<text class="section-title">提现管理</text>
<text class="section-desc">管理用户提现申请</text>
</view>
<view class="withdrawals-list">
<view class="withdrawal-item" v-for="withdrawal in withdrawalRequests" :key="withdrawal.id">
<view class="withdrawal-info">
<text class="user-name">{{ withdrawal.userName }}</text>
<text class="amount">¥{{ withdrawal.amount }}</text>
<text class="time">{{ formatDate(withdrawal.time) }}</text>
</view>
<view class="withdrawal-actions">
<button class="btn-success" @click="approveWithdrawal(withdrawal)">批准</button>
<button class="btn-danger" @click="rejectWithdrawal(withdrawal)">拒绝</button>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</AdminLayout>
</template>
<script setup lang="uts">
import { ref, computed } from 'vue'
import AdminLayout from '@/layouts/admin/index.uvue'
// Tab 相关
const activeTab = ref('finance-overview')
const tabs = ref([
{ key: 'finance-overview', title: '财务概览', icon: 'icon-overview' },
{ key: 'withdrawals', title: '提现管理', icon: 'icon-withdraw' }
])
// 响应式数据
const totalRevenue = ref(256890)
const monthlyRevenue = ref(45678)
const orderCount = ref(1247)
const pendingWithdrawals = ref(5)
const availableBalance = ref(125690.50)
const chartPeriod = ref('month')
// 交易记录相关
const transactionSearch = ref('')
const selectedTransactionType = ref(0)
const transactionTypes = ['全部类型', '收入', '支出', '提现', '充值', '转账']
const transactions = ref([
{
id: 1,
time: '2024-01-15T14:30:00Z',
type: 'income',
description: '商品销售收入',
reference: '订单 #DD202401150001',
amount: 2599.00,
status: 'completed'
},
{
id: 2,
time: '2024-01-15T10:15:00Z',
type: 'expense',
description: '供应商货款',
reference: '采购单 #CG20240115001',
amount: 1500.00,
status: 'completed'
},
{
id: 3,
time: '2024-01-14T16:45:00Z',
type: 'withdrawal',
description: '账户提现',
reference: '提现单 #TX20240114001',
amount: 5000.00,
status: 'pending'
},
{
id: 4,
time: '2024-01-14T09:20:00Z',
type: 'recharge',
description: '账户充值',
reference: '充值单 #CZ20240114001',
amount: 10000.00,
status: 'completed'
},
{
id: 5,
time: '2024-01-13T11:30:00Z',
type: 'transfer',
description: '转账支出',
reference: '转账单 #ZZ20240113001',
amount: 2000.00,
status: 'completed'
}
])
// 计算属性
const filteredTransactions = computed(() => {
let filtered = transactions.value
// 搜索过滤
if (transactionSearch.value) {
filtered = filtered.filter(t =>
t.description.toLowerCase().includes(transactionSearch.value.toLowerCase()) ||
(t.reference && t.reference.toLowerCase().includes(transactionSearch.value.toLowerCase()))
)
}
// 类型过滤
if (selectedTransactionType.value > 0) {
const typeMap = {
1: 'income',
2: 'expense',
3: 'withdrawal',
4: 'recharge',
5: 'transfer'
}
const targetType = typeMap[selectedTransactionType.value as keyof typeof typeMap]
filtered = filtered.filter(t => t.type === targetType)
}
return filtered
})
const totalTransactions = computed(() => filteredTransactions.value.length)
// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const totalPages = computed(() => Math.ceil(totalTransactions.value / pageSize.value))
const visiblePages = computed(() => {
const pages = []
const start = Math.max(1, currentPage.value - 2)
const end = Math.min(totalPages.value, currentPage.value + 2)
for (let i = start; i <= end; i++) {
pages.push(i)
}
return pages
})
// 模态框相关
const showWithdrawalModal = ref(false)
const showTransferModal = ref(false)
const showRechargeModal = ref(false)
// 提现请求数据
const withdrawalRequests = ref([
{ id: 1, userName: '张三', amount: 500.00, time: '2024-01-15T10:30:00Z', status: 'pending' },
{ id: 2, userName: '李四', amount: 1200.00, time: '2024-01-15T09:15:00Z', status: 'pending' },
{ id: 3, userName: '王五', amount: 800.00, time: '2024-01-14T16:45:00Z', status: 'pending' }
])
// 表单数据
const withdrawalAmount = ref('')
const selectedAccount = ref(0)
const accountOptions = ['支付宝', '银行卡', '微信钱包']
const withdrawalNote = ref('')
const transferToAccount = ref('')
const transferAmount = ref('')
const transferNote = ref('')
const rechargeAmount = ref('')
const selectedPayment = ref(0)
const paymentOptions = ['支付宝', '微信支付', '银行卡']
const rechargeNote = ref('')
// 方法
const setChartPeriod = (period: string) => {
chartPeriod.value = period
// TODO: 重新加载图表数据
console.log('切换图表周期:', period)
}
const generateReport = (type: string) => {
uni.showToast({
title: `${type === 'daily' ? '日报表' : type === 'monthly' ? '月报表' : '年报表'}生成中`,
icon: 'none'
})
// TODO: 实现报表生成功能
}
const handleTransactionTypeChange = (e: any) => {
selectedTransactionType.value = e.detail.value
}
const handleAccountChange = (e: any) => {
selectedAccount.value = e.detail.value
}
const handlePaymentChange = (e: any) => {
selectedPayment.value = e.detail.value
}
const viewTransactionDetail = (transaction: any) => {
uni.showModal({
title: '交易详情',
content: `交易类型: ${transaction.type}\n金额: ¥${transaction.amount}\n状态: ${transaction.status}\n时间: ${formatDateTime(transaction.time)}`,
showCancel: false
})
}
const submitWithdrawal = () => {
const amount = parseFloat(withdrawalAmount.value)
if (!amount || amount < 100) {
uni.showToast({
title: '提现金额不能少于100元',
icon: 'none'
})
return
}
if (amount > availableBalance.value) {
uni.showToast({
title: '提现金额不能超过可用余额',
icon: 'none'
})
return
}
// TODO: 实现提现申请逻辑
uni.showToast({
title: '提现申请提交成功',
icon: 'success'
})
closeModal()
}
const submitTransfer = () => {
if (!transferToAccount.value || !transferAmount.value) {
uni.showToast({
title: '请填写完整信息',
icon: 'none'
})
return
}
// TODO: 实现转账逻辑
uni.showToast({
title: '转账成功',
icon: 'success'
})
closeModal()
}
const submitRecharge = () => {
const amount = parseFloat(rechargeAmount.value)
if (!amount || amount <= 0) {
uni.showToast({
title: '请输入有效的充值金额',
icon: 'none'
})
return
}
// TODO: 实现充值逻辑
uni.showToast({
title: '充值成功',
icon: 'success'
})
closeModal()
}
const closeModal = () => {
showWithdrawalModal.value = false
showTransferModal.value = false
showRechargeModal.value = false
// 重置表单
withdrawalAmount.value = ''
selectedAccount.value = 0
withdrawalNote.value = ''
transferToAccount.value = ''
transferAmount.value = ''
transferNote.value = ''
rechargeAmount.value = ''
selectedPayment.value = 0
rechargeNote.value = ''
}
const goToPage = (page: number) => {
currentPage.value = page
// TODO: 实现分页数据加载
}
const formatDateTime = (dateString: string) => {
const date = new Date(dateString)
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN', { hour12: false })
}
// Tab 切换方法
const switchTab = (tabKey: string) => {
activeTab.value = tabKey
}
// 提现管理方法
const approveWithdrawal = (withdrawal: any) => {
uni.showModal({
title: '确认批准',
content: `确定要批准用户 ${withdrawal.userName} 的提现申请 ¥${withdrawal.amount} 吗?`,
success: (res) => {
if (res.confirm) {
withdrawal.status = 'approved'
uni.showToast({
title: '批准成功',
icon: 'success'
})
}
}
})
}
const rejectWithdrawal = (withdrawal: any) => {
uni.showModal({
title: '确认拒绝',
content: `确定要拒绝用户 ${withdrawal.userName} 的提现申请吗?`,
success: (res) => {
if (res.confirm) {
withdrawal.status = 'rejected'
uni.showToast({
title: '拒绝成功',
icon: 'none'
})
}
}
})
}
const formatDate = (dateString: string) => {
const date = new Date(dateString)
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN', { hour12: false })
}
// 页面生命周期
onLoad((options: any) => {
// 处理页面参数切换到对应的tab
if (options && options.tab) {
if (options.tab === 'withdrawals') {
activeTab.value = 'withdrawals'
} else {
activeTab.value = 'finance-overview'
}
} else {
activeTab.value = 'finance-overview'
}
console.log('财务管理页面加载,参数:', options)
})
onMounted(() => {
// 初始化数据
console.log('财务管理页面初始化')
})
</script>
<style lang="scss">
/* Tab 栏样式 */
.tab-bar {
display: flex;
background-color: #ffffff;
border-radius: 8rpx;
padding: 8rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}
.tab-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: 16rpx 24rpx;
border-radius: 6rpx;
cursor: pointer;
transition: all 0.2s;
background-color: #f5f5f5;
color: #666666;
}
.tab-item:hover {
background-color: #e8e8e8;
}
.tab-item.active {
background-color: #1890ff;
color: #ffffff;
}
.tab-icon {
font-size: 16rpx;
}
.tab-title {
font-size: 14rpx;
font-weight: 500;
}
/* 提现管理样式 */
.withdrawals-section {
background-color: #ffffff;
border-radius: 8rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}
.withdrawals-management {
padding: 32rpx;
}
.section-header {
margin-bottom: 32rpx;
}
.section-title {
display: block;
font-size: 18rpx;
font-weight: 600;
color: #262626;
margin-bottom: 8rpx;
}
.section-desc {
display: block;
font-size: 14rpx;
color: #666666;
}
.withdrawals-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.withdrawal-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 24rpx;
background-color: #fafafa;
border-radius: 6rpx;
border: 1rpx solid #e8e8e8;
}
.withdrawal-info {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.user-name {
font-size: 16rpx;
font-weight: 500;
color: #262626;
}
.amount {
font-size: 18rpx;
font-weight: 600;
color: #1890ff;
}
.time {
font-size: 14rpx;
color: #999999;
}
.withdrawal-actions {
display: flex;
gap: 12rpx;
}
.btn-success {
background-color: #52c41a;
color: #ffffff;
border: none;
border-radius: 6rpx;
padding: 8rpx 16rpx;
font-size: 14rpx;
cursor: pointer;
}
.btn-danger {
background-color: #ff4d4f;
color: #ffffff;
border: none;
border-radius: 6rpx;
padding: 8rpx 16rpx;
font-size: 14rpx;
cursor: pointer;
}
.finance-management {
padding: 20rpx;
}
.page-header {
margin-bottom: 30rpx;
}
.page-title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.page-subtitle {
display: block;
font-size: 26rpx;
color: #666;
}
.finance-overview {
margin-bottom: 40rpx;
}
.overview-cards {
display: flex;
justify-content: space-between;
margin-bottom: 40rpx;
flex-wrap: wrap;
gap: 20rpx;
}
.overview-card {
flex: 1;
min-width: 200rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16rpx;
padding: 40rpx 30rpx;
text-align: center;
color: #fff;
box-shadow: 0 4rpx 12rpx rgba(102, 126, 234, 0.3);
}
.card-icon {
font-size: 48rpx;
margin-bottom: 20rpx;
}
.card-content {
flex: 1;
}
.card-value {
display: block;
font-size: 36rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.card-label {
display: block;
font-size: 24rpx;
opacity: 0.9;
}
.chart-section {
background-color: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.chart-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.chart-controls {
display: flex;
gap: 15rpx;
}
.period-btn {
padding: 12rpx 24rpx;
border: 1rpx solid #ddd;
border-radius: 6rpx;
background-color: #fff;
color: #666;
cursor: pointer;
font-size: 24rpx;
}
.period-btn.active {
background-color: #1890ff;
color: #fff;
border-color: #1890ff;
}
.chart-placeholder {
height: 300rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #f8f9fa;
border-radius: 8rpx;
border: 2rpx dashed #ddd;
}
.chart-placeholder-text {
font-size: 32rpx;
color: #999;
margin-bottom: 10rpx;
}
.chart-placeholder-subtext {
font-size: 24rpx;
color: #ccc;
}
.finance-actions {
display: flex;
gap: 30rpx;
margin-bottom: 40rpx;
flex-wrap: wrap;
}
.action-section {
flex: 1;
min-width: 300rpx;
background-color: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.action-buttons {
display: flex;
flex-wrap: wrap;
gap: 15rpx;
}
.action-btn {
flex: 1;
min-width: 120rpx;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 15rpx;
border-radius: 8rpx;
border: none;
cursor: pointer;
transition: all 0.3s;
}
.action-btn.primary {
background-color: #1890ff;
color: #fff;
}
.action-btn.secondary {
background-color: #52c41a;
color: #fff;
}
.action-btn.info {
background-color: #13c2c2;
color: #fff;
}
.action-btn.success {
background-color: #52c41a;
color: #fff;
}
.action-btn.warning {
background-color: #faad14;
color: #fff;
}
.action-btn.danger {
background-color: #ff4d4f;
color: #fff;
}
.action-btn:hover {
transform: translateY(-2rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
}
.btn-icon {
font-size: 32rpx;
margin-bottom: 8rpx;
}
.btn-text {
font-size: 24rpx;
font-weight: 500;
}
.transaction-section {
background-color: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
flex-wrap: wrap;
gap: 20rpx;
}
.section-controls {
display: flex;
gap: 15rpx;
align-items: center;
}
.search-input {
width: 250rpx;
padding: 12rpx 16rpx;
border: 1rpx solid #ddd;
border-radius: 6rpx;
font-size: 26rpx;
}
.type-selector {
display: flex;
align-items: center;
gap: 10rpx;
padding: 12rpx 16rpx;
border: 1rpx solid #ddd;
border-radius: 6rpx;
background-color: #fff;
cursor: pointer;
font-size: 26rpx;
}
.transaction-table {
margin-bottom: 30rpx;
}
.table-header {
background-color: #f5f5f5;
border-bottom: 1rpx solid #eee;
}
.table-row {
display: flex;
align-items: center;
padding: 20rpx;
border-bottom: 1rpx solid #eee;
}
.table-row:last-child {
border-bottom: none;
}
.col-time {
flex: 1.2;
}
.col-type,
.col-status {
flex: 0.8;
}
.col-description {
flex: 2;
}
.col-amount {
flex: 1;
}
.col-actions {
width: 80rpx;
text-align: center;
}
.transaction-time {
font-size: 26rpx;
color: #666;
}
.type-badge {
display: inline-block;
padding: 4rpx 8rpx;
border-radius: 8rpx;
font-size: 22rpx;
font-weight: bold;
text-align: center;
}
.type-badge.income {
background-color: #52c41a;
color: #fff;
}
.type-badge.expense {
background-color: #ff4d4f;
color: #fff;
}
.type-badge.withdrawal {
background-color: #faad14;
color: #fff;
}
.type-badge.recharge {
background-color: #1890ff;
color: #fff;
}
.type-badge.transfer {
background-color: #722ed1;
color: #fff;
}
.transaction-desc {
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 4rpx;
display: block;
}
.transaction-ref {
font-size: 24rpx;
color: #999;
display: block;
}
.transaction-amount {
font-size: 28rpx;
font-weight: bold;
}
.transaction-amount.income {
color: #52c41a;
}
.transaction-amount.expense {
color: #ff4d4f;
}
.status-badge {
display: inline-block;
padding: 4rpx 8rpx;
border-radius: 8rpx;
font-size: 22rpx;
font-weight: bold;
text-align: center;
}
.status-badge.completed {
background-color: #52c41a;
color: #fff;
}
.status-badge.pending {
background-color: #faad14;
color: #fff;
}
.status-badge.failed {
background-color: #ff4d4f;
color: #fff;
}
.status-badge.cancelled {
background-color: #666;
color: #fff;
}
.action-btn.view {
width: 50rpx;
height: 50rpx;
border-radius: 6rpx;
background-color: #1890ff;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
font-size: 22rpx;
}
.pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 30rpx;
flex-wrap: wrap;
gap: 20rpx;
}
.page-info {
font-size: 26rpx;
color: #666;
}
.page-controls {
display: flex;
align-items: center;
gap: 15rpx;
}
.page-btn {
padding: 12rpx 20rpx;
border: 1rpx solid #ddd;
border-radius: 6rpx;
background-color: #fff;
color: #333;
cursor: pointer;
font-size: 26rpx;
}
.page-btn:disabled {
background-color: #f5f5f5;
color: #ccc;
cursor: not-allowed;
}
.page-numbers {
display: flex;
gap: 8rpx;
margin: 0 20rpx;
}
.page-number {
width: 50rpx;
height: 50rpx;
border: 1rpx solid #ddd;
border-radius: 6rpx;
background-color: #fff;
color: #333;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 26rpx;
}
.page-number.active {
background-color: #1890ff;
color: #fff;
border-color: #1890ff;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background-color: #fff;
border-radius: 12rpx;
width: 90%;
max-width: 500rpx;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.modal-close {
cursor: pointer;
font-size: 28rpx;
color: #999;
padding: 10rpx;
}
.modal-body {
padding: 30rpx;
}
.withdrawal-info {
background-color: #f8f9fa;
border-radius: 8rpx;
padding: 20rpx;
margin-bottom: 30rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.info-item:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 26rpx;
color: #666;
}
.info-value {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.form-group {
margin-bottom: 30rpx;
}
.form-label {
display: block;
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 16rpx 20rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.form-select {
padding: 16rpx 20rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
background-color: #fff;
cursor: pointer;
font-size: 28rpx;
}
.modal-footer {
display: flex;
gap: 20rpx;
justify-content: flex-end;
padding: 30rpx;
border-top: 1rpx solid #eee;
}
.btn-primary {
background-color: #1890ff;
color: #fff;
border: none;
border-radius: 8rpx;
padding: 16rpx 32rpx;
font-size: 26rpx;
cursor: pointer;
}
.btn-secondary {
background-color: #fff;
color: #666;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 16rpx 32rpx;
font-size: 26rpx;
cursor: pointer;
}
.iconfont {
font-family: 'iconfont';
font-size: 24rpx;
}
/* 响应式设计 */
@media screen and (max-width: 750rpx) {
.overview-cards {
flex-direction: column;
}
.finance-actions {
flex-direction: column;
}
.action-section {
min-width: auto;
}
.action-buttons {
flex-direction: column;
}
.action-btn {
width: 100%;
}
.section-header {
flex-direction: column;
align-items: stretch;
}
.section-controls {
justify-content: center;
}
.table-row {
flex-wrap: wrap;
gap: 10rpx;
}
.col-description {
flex: 1 1 100%;
}
.pagination {
flex-direction: column;
text-align: center;
}
}
</style>