agent后台finance和users添加服务端分页和统计

This commit is contained in:
2026-05-10 08:41:49 +08:00
parent 3cbb607ff3
commit f3b9feca6a
5 changed files with 203 additions and 69 deletions
@@ -16,6 +16,7 @@ import DataTableToolbar from '@/pages/agent/finance/components/data-table-toolba
const props = defineProps<Omit<DataTableProps<Transaction>, 'columns'> & {
typeFilter?: string
serverPagination?: DataTableProps<Transaction>['serverPagination']
}>()
const emit = defineEmits<{
@@ -34,6 +35,7 @@ const table = generateVueTable<Transaction>({
get data() { return props.data },
get loading() { return props.loading },
columns: columns.value,
serverPagination: props.serverPagination,
})
const columnLabels: Record<string, string> = {
@@ -51,7 +53,7 @@ defineExpose({
</script>
<template>
<DataTable :columns="columns" :data :loading :table @refresh="emit('refresh')">
<DataTable :columns="columns" :data :loading :table :server-pagination @refresh="emit('refresh')">
<template #toolbar>
<div class="space-y-3">
<div class="flex flex-wrap items-center justify-between gap-2">
+45 -34
View File
@@ -16,42 +16,48 @@ const balance = ref(0)
const transactions = ref<Transaction[]>([])
const tableRef = ref()
const typeFilter = ref('')
const currentPage = ref(1)
const pageSize = ref(20)
const total = ref(0)
const rechargeCount = ref(0)
const consumeCount = ref(0)
const totalRecharge = ref(0)
const totalConsume = ref(0)
const filteredTransactions = computed(() => {
let result = transactions.value.filter(tx => tx)
if (typeFilter.value) {
result = result.filter(tx => tx.type === typeFilter.value)
}
return result
})
const serverPagination = computed(() => ({
page: currentPage.value,
pageSize: pageSize.value,
total: total.value,
onPageChange: (newPage: number) => {
currentPage.value = newPage
fetchFinance()
},
onPageSizeChange: (newPageSize: number) => {
pageSize.value = newPageSize
currentPage.value = 1
fetchFinance()
},
}))
const totalRecharge = computed(() => {
return transactions.value
.filter(tx => tx.type === 'recharge' || tx.type === 'refund')
.reduce((sum, tx) => sum + (tx.amount || 0), 0)
})
const totalConsume = computed(() => {
return transactions.value
.filter(tx => tx.type === 'consume')
.reduce((sum, tx) => sum + (tx.amount || 0), 0)
})
const rechargeCount = computed(() => transactions.value.filter(tx => tx.type === 'recharge' || tx.type === 'refund').length)
const consumeCount = computed(() => transactions.value.filter(tx => tx.type === 'consume').length)
onMounted(async () => {
async function fetchFinance() {
loading.value = true
try {
const data = await api.get<any>('/agent/finance')
const params = new URLSearchParams()
params.append('page', String(currentPage.value))
params.append('page_size', String(pageSize.value))
if (typeFilter.value) {
params.append('type', typeFilter.value)
}
const data = await api.get<any>(`/agent/finance?${params.toString()}`)
if (data) {
balance.value = data.balance || 0
if (Array.isArray(data.transactions)) {
transactions.value = data.transactions
} else if (Array.isArray(data.data)) {
transactions.value = data.data
} else {
transactions.value = []
}
transactions.value = data.transactions || []
total.value = data.total || 0
rechargeCount.value = data.recharge_count || 0
consumeCount.value = data.consume_count || 0
totalRecharge.value = data.total_recharge || 0
totalConsume.value = data.total_consume || 0
}
}
catch (error) {
@@ -61,6 +67,10 @@ onMounted(async () => {
finally {
loading.value = false
}
}
onMounted(() => {
fetchFinance()
})
</script>
@@ -166,10 +176,11 @@ onMounted(async () => {
v-else
ref="tableRef"
:loading
:data="filteredTransactions"
:data="transactions"
:server-pagination="serverPagination"
:type-filter="typeFilter"
@refresh="() => {}"
@update:typeFilter="typeFilter = $event"
@refresh="fetchFinance"
@update:typeFilter="typeFilter = $event; currentPage = 1; fetchFinance()"
/>
</UiCardContent>
</UiCard>
@@ -16,6 +16,7 @@ import DataTableToolbar from '@/pages/agent/users/components/data-table-toolbar.
const props = defineProps<Omit<DataTableProps<User>, 'columns'> & {
searchFilter?: string
serverPagination?: DataTableProps<User>['serverPagination']
}>()
const emit = defineEmits<{
@@ -34,6 +35,7 @@ const table = generateVueTable<User>({
get data() { return props.data },
get loading() { return props.loading },
columns: columns.value,
serverPagination: props.serverPagination,
})
const columnLabels: Record<string, string> = {
@@ -51,7 +53,7 @@ defineExpose({
</script>
<template>
<DataTable :columns="columns" :data :loading :table @refresh="emit('refresh')">
<DataTable :columns="columns" :data :loading :table :server-pagination @refresh="emit('refresh')">
<template #toolbar>
<div class="space-y-3">
<div class="flex flex-wrap items-center justify-between gap-2">
+36 -27
View File
@@ -15,36 +15,44 @@ const loading = ref(true)
const users = ref<User[]>([])
const tableRef = ref()
const searchFilter = ref('')
const currentPage = ref(1)
const pageSize = ref(20)
const total = ref(0)
const activeCount = ref(0)
const disabledCount = ref(0)
const bannedCount = ref(0)
const filteredUsers = computed(() => {
let result = users.value.filter(u => u)
if (searchFilter.value) {
const query = searchFilter.value.toLowerCase()
result = result.filter(u =>
u.username?.toLowerCase().includes(query)
|| u.email?.toLowerCase().includes(query),
)
}
return result
})
const activeCount = computed(() => users.value.filter(user => user.status === 'active').length)
const disabledCount = computed(() => users.value.filter(user => user.status === 'disabled').length)
const bannedCount = computed(() => users.value.filter(user => user.status === 'banned').length)
const serverPagination = computed(() => ({
page: currentPage.value,
pageSize: pageSize.value,
total: total.value,
onPageChange: (newPage: number) => {
currentPage.value = newPage
fetchUsers()
},
onPageSizeChange: (newPageSize: number) => {
pageSize.value = newPageSize
currentPage.value = 1
fetchUsers()
},
}))
async function fetchUsers() {
loading.value = true
try {
const data = await api.get<any>('/agent/users')
if (Array.isArray(data)) {
users.value = data
} else if (data?.users) {
users.value = data.users
} else if (data?.data) {
users.value = Array.isArray(data.data) ? data.data : []
} else {
users.value = []
const params = new URLSearchParams()
params.append('page', String(currentPage.value))
params.append('page_size', String(pageSize.value))
if (searchFilter.value) {
params.append('search', searchFilter.value.trim())
}
const data = await api.get<any>(`/agent/users?${params.toString()}`)
users.value = data?.users || []
total.value = data?.total || 0
activeCount.value = data?.active_count || 0
disabledCount.value = data?.disabled_count || 0
bannedCount.value = data?.banned_count || 0
}
catch (error) {
console.error('Load users failed:', error)
@@ -81,7 +89,7 @@ onMounted(() => {
</UiCardHeader>
<UiCardContent>
<div class="text-2xl font-bold">
{{ users.length }}
{{ total }}
</div>
</UiCardContent>
</UiCard>
@@ -139,10 +147,11 @@ onMounted(() => {
v-else
ref="tableRef"
:loading
:data="filteredUsers"
:data="users"
:server-pagination="serverPagination"
:search-filter="searchFilter"
@refresh="fetchUsers"
@update:search-filter="searchFilter = $event"
@update:search-filter="searchFilter = $event; currentPage = 1; fetchUsers()"
/>
</UiCardContent>
</UiCard>