增加 提现列表 页面

页面优化调整。
This commit is contained in:
aaron 2025-01-29 13:52:07 +08:00
parent 904bc76b41
commit 8a934ca93d
4 changed files with 404 additions and 118 deletions

View File

@ -27,6 +27,26 @@
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="order">
<template #icon>
<shopping-outlined />
</template>
<template #title>订单管理</template>
<a-menu-item key="order-delivery">
<router-link to="/order/delivery">配送订单</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="finance">
<template #icon>
<money-collect-outlined />
</template>
<template #title>财务管理</template>
<a-menu-item key="finance-withdraw">
<router-link to="/finance/withdraw">提现管理</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="community">
<template #icon>
<home-outlined />
@ -43,16 +63,6 @@
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="order">
<template #icon>
<shopping-outlined />
</template>
<template #title>订单管理</template>
<a-menu-item key="order-delivery">
<router-link to="/order/delivery">配送订单</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="merchant">
<template #icon>
<shop-outlined />
@ -131,6 +141,7 @@ import {
ShopOutlined,
SettingOutlined,
ShoppingOutlined,
MoneyCollectOutlined
} from '@ant-design/icons-vue'
import { useRouter } from 'vue-router'
@ -147,12 +158,13 @@ export default defineComponent({
ShopOutlined,
SettingOutlined,
ShoppingOutlined,
MoneyCollectOutlined
},
setup() {
const router = useRouter()
const collapsed = ref(false)
const selectedKeys = ref(['dashboard'])
const openKeys = ref(['user', 'community', 'merchant', 'system'])
const openKeys = ref([])
const userInfo = ref(JSON.parse(localStorage.getItem('userInfo') || '{}'))
@ -187,6 +199,30 @@ export default defineComponent({
}
]
},
{
key: 'order',
icon: () => h(ShoppingOutlined),
title: '订单管理',
children: [
{
key: 'order-delivery',
title: '配送订单',
path: '/order/delivery'
}
]
},
{
key: 'finance',
icon: () => h(MoneyCollectOutlined),
title: '财务管理',
children: [
{
key: 'finance-withdraw',
title: '提现管理',
path: '/finance/withdraw'
}
]
},
{
key: 'community',
icon: () => h(HomeOutlined),
@ -209,18 +245,6 @@ export default defineComponent({
}
]
},
{
key: 'order',
icon: () => h(ShoppingOutlined),
title: '订单管理',
children: [
{
key: 'order-delivery',
title: '配送订单',
path: '/order/delivery'
}
]
},
{
key: 'merchant',
icon: () => h(ShopOutlined),
@ -254,7 +278,7 @@ export default defineComponent({
path: '/system/logs'
}
]
}
},
])
return {

View File

@ -89,6 +89,17 @@ const routes = [
meta: { title: '配送订单' }
}
]
},
{
path: '/finance',
component: BasicLayout,
children: [
{
path: 'withdraw',
component: () => import('@/views/finance/WithdrawList.vue'),
meta: { title: '提现管理' }
}
]
}
]

View File

@ -1,81 +1,37 @@
<template>
<page-container>
<h2>欢迎使用后台管理系统</h2>
<p class="time">{{ currentTime }}</p>
<div class="stats-section">
<div class="stat-item">
<div class="stat-label">小区总数</div>
<div class="stat-value">{{ stats.communityCount }}</div>
</div>
<div class="stat-item">
<div class="stat-label">楼栋总数</div>
<div class="stat-value">{{ stats.buildingCount }}</div>
</div>
<div class="stat-item">
<div class="stat-label">用户总数</div>
<div class="stat-value">{{ stats.userCount }}</div>
</div>
<div class="stat-item">
<div class="stat-label">今日活跃</div>
<div class="stat-value">{{ stats.activeCount }}</div>
<div class="dashboard">
<div class="welcome-card">
<h1>欢迎使用蜂快运营管理系统</h1>
<p>{{ greeting }}</p>
</div>
</div>
</page-container>
</template>
<script>
import { defineComponent, ref, onMounted, onUnmounted } from 'vue'
import dayjs from 'dayjs'
import { defineComponent, computed } from 'vue'
import PageContainer from '@/components/PageContainer.vue'
export default defineComponent({
name: 'Dashboard',
components: {
PageContainer
},
setup() {
const currentTime = ref('')
const stats = ref({
communityCount: 0,
buildingCount: 0,
userCount: 0,
activeCount: 0
})
//
const updateTime = () => {
currentTime.value = dayjs().format('YYYY年MM月DD日 HH:mm:ss')
}
//
let timer = null
onMounted(() => {
//
updateTime()
//
timer = setInterval(updateTime, 1000)
// TODO: API
// 使
stats.value = {
communityCount: 25,
buildingCount: 168,
userCount: 1280,
activeCount: 368
}
})
onUnmounted(() => {
//
if (timer) {
clearInterval(timer)
}
const greeting = computed(() => {
const hour = new Date().getHours()
if (hour < 6) return '夜深了,请注意休息'
if (hour < 9) return '早上好'
if (hour < 12) return '上午好'
if (hour < 14) return '中午好'
if (hour < 17) return '下午好'
if (hour < 19) return '傍晚好'
return '晚上好'
})
return {
currentTime,
stats
greeting
}
}
})
@ -83,45 +39,24 @@ export default defineComponent({
<style scoped>
.dashboard {
/* 移除 background、padding、margin 等样式 */
}
.dashboard h2 {
margin: 0;
font-size: 20px;
font-weight: normal;
color: #000;
}
.time {
margin: 8px 0 24px;
font-size: 13px;
color: #999;
}
.stats-section {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
padding: 24px;
background: #fff;
min-height: 400px;
}
.stat-item {
background: #fff;
padding: 20px;
border: 1px solid #eee;
border-radius: 2px;
.welcome-card {
text-align: center;
padding: 48px 0;
}
.stat-label {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.stat-value {
font-size: 24px;
.welcome-card h1 {
font-size: 28px;
color: #1890ff;
font-weight: normal;
margin-bottom: 16px;
}
.welcome-card p {
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
}
</style>

View File

@ -0,0 +1,316 @@
<template>
<page-container>
<div class="withdraw-list">
<div class="table-header">
<h1>提现管理</h1>
</div>
<!-- 过滤区域 -->
<div class="table-filter">
<a-form layout="inline">
<a-form-item label="提现状态">
<a-select
v-model:value="filterForm.status"
style="width: 200px"
placeholder="请选择状态"
allowClear
@change="handleFilterChange"
>
<a-select-option value="PENDING">待审核</a-select-option>
<a-select-option value="APPROVED">已通过</a-select-option>
<a-select-option value="REJECTED">已拒绝</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">
查询
</a-button>
<a-button @click="handleReset">
重置
</a-button>
</a-space>
</a-form-item>
</a-form>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
row-key="id"
>
<template #bodyCell="{ column, record }">
<!-- 状态列 -->
<template v-if="column.key === 'status'">
<a-tag :color="getStatusColor(record.status)">
{{ getStatusText(record.status) }}
</a-tag>
</template>
<!-- 姓名列 -->
<template v-if="column.key === 'name'">
<span>{{ record.name }}</span>
<a-button
type="link"
size="small"
@click="copyText(record.name)"
>
复制
</a-button>
</template>
<!-- 银行列 -->
<template v-if="column.key === 'bank_name'">
<span>{{ record.bank_name }}</span>
<a-button
type="link"
size="small"
@click="copyText(record.bank_name)"
>
复制
</a-button>
</template>
<!-- 卡号列 -->
<template v-if="column.key === 'bank_card_number'">
<span>{{ record.bank_card_number }}</span>
<a-button
type="link"
size="small"
@click="copyText(record.bank_card_number)"
>
复制
</a-button>
</template>
</template>
</a-table>
</div>
</page-container>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import PageContainer from '@/components/PageContainer.vue'
import request from '@/utils/request'
export default defineComponent({
components: {
PageContainer
},
setup() {
const loading = ref(false)
const tableData = ref([])
const filterForm = ref({
status: undefined
})
const pagination = ref({
current: 1,
pageSize: 20,
total: 0,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`
})
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 80,
align: 'center'
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
width: 120
},
{
title: '银行',
dataIndex: 'bank_name',
key: 'bank_name',
width: 160
},
{
title: '卡号',
dataIndex: 'bank_card_number',
key: 'bank_card_number',
width: 200
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
align: 'center'
},
{
title: '申请时间',
dataIndex: 'create_time',
key: 'create_time',
width: 180
}
]
//
const fetchData = async () => {
try {
loading.value = true
const params = {
skip: (pagination.value.current - 1) * pagination.value.pageSize,
limit: pagination.value.pageSize
}
if (filterForm.value.status) {
params.status = filterForm.value.status
}
const res = await request.get('/api/withdraw', { params })
if (res.code === 200) {
tableData.value = res.data.items
pagination.value.total = res.data.total
}
} catch (error) {
console.error('获取提现列表失败:', error)
message.error('获取提现列表失败')
} finally {
loading.value = false
}
}
//
const getStatusText = (status) => {
const statusMap = {
'PENDING': '待审核',
'APPROVED': '已通过',
'REJECTED': '已拒绝'
}
return statusMap[status] || status
}
//
const getStatusColor = (status) => {
const colorMap = {
'PENDING': 'orange',
'APPROVED': '#87d068',
'REJECTED': 'red'
}
return colorMap[status] || 'default'
}
//
const handleTableChange = (pag) => {
pagination.value.current = pag.current
pagination.value.pageSize = pag.pageSize
fetchData()
}
//
const handleFilterChange = () => {
pagination.value.current = 1
}
//
const handleSearch = () => {
pagination.value.current = 1
fetchData()
}
//
const handleReset = () => {
filterForm.value.status = undefined
pagination.value.current = 1
fetchData()
}
//
const copyText = (text) => {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
message.success('复制成功')
}).catch(() => {
message.error('复制失败')
})
} else {
//
const textarea = document.createElement('textarea')
textarea.value = text
document.body.appendChild(textarea)
textarea.select()
try {
document.execCommand('copy')
message.success('复制成功')
} catch (err) {
message.error('复制失败')
}
document.body.removeChild(textarea)
}
}
onMounted(() => {
fetchData()
})
return {
loading,
columns,
tableData,
pagination,
filterForm,
handleTableChange,
handleFilterChange,
handleSearch,
handleReset,
getStatusText,
getStatusColor,
copyText
}
}
})
</script>
<style scoped>
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-header h1 {
margin: 0;
}
.table-filter {
margin-bottom: 16px;
padding: 16px 24px;
background: #fff;
border-radius: 2px;
}
:deep(.ant-form-item) {
margin-bottom: 0;
margin-right: 16px;
}
:deep(.ant-form-item:last-child) {
margin-right: 0;
}
:deep(.ant-tag) {
min-width: 60px;
text-align: center;
}
:deep(.ant-table-cell) {
.ant-btn-link {
padding: 0 4px;
height: 24px;
margin-left: 8px;
}
}
</style>