优化主页数据统计

This commit is contained in:
2026-03-10 12:42:29 +08:00
parent fdd8f6dffa
commit 6f56574aac
8 changed files with 279 additions and 89 deletions

View File

@@ -1,31 +1,32 @@
import request from '@/utils/http'
/**
* 基础数据统计
* 大富翁工作台卡片统计(玩家注册、充值、提现、游玩次数,含较上周对比)
* @returns 响应
*/
export function fetchStatistics() {
return request.get<any>({
url: '/core/system/statistics'
url: '/core/dice/dashboard/statistics'
})
}
/**
* 登录统计图表数据
* 近期玩家充值统计近10天每日充值金额
* @returns 响应
*/
export function fetchLoginChart() {
export function fetchRechargeChart() {
return request.get<any>({
url: '/core/system/loginChart'
url: '/core/dice/dashboard/rechargeChart'
})
}
/**
* 登录统计图表数据
* 月度玩家充值汇总当年1-12月每月充值金额
* @returns 响应
*/
export function fetchLoginBarChart() {
export function fetchRechargeBarChart() {
return request.get<any>({
url: '/core/system/loginBarChart'
url: '/core/dice/dashboard/rechargeBarChart'
})
}

View File

@@ -28,7 +28,6 @@
</ElRow>
</template>
<AboutProject />
</div>
</template>
@@ -36,7 +35,6 @@
import CardList from './modules/card-list.vue'
import ActiveUser from './modules/active-user.vue'
import SalesOverview from './modules/sales-overview.vue'
import AboutProject from './modules/about-project.vue'
import NewUser from './modules/new-user.vue'
import Dynamic from './modules/dynamic-stats.vue'
import TodoList from './modules/todo-list.vue'

View File

@@ -1,43 +0,0 @@
<template>
<div class="art-card p-5 flex-b mb-5 max-sm:mb-4">
<div>
<h2 class="text-2xl font-medium">关于项目</h2>
<p class="text-g-700 mt-1">{{ systemName }} 是一款兼具设计美学与高效开发的后台系统</p>
<p class="text-g-700 mt-1">使用了 webman + Vue3 + Element Plus 高性能高颜值技术栈</p>
<div class="flex flex-wrap gap-3.5 max-w-150 mt-9">
<div
class="w-60 flex-cb h-12.5 px-3.5 border border-g-300 c-p rounded-lg text-sm bg-g-100 duration-300 hover:-translate-y-1 max-sm:w-full"
v-for="link in linkList"
:key="link.label"
@click="goPage(link.url)"
>
<span class="text-g-700">{{ link.label }}</span>
<ArtSvgIcon icon="ri:arrow-right-s-line" class="text-lg text-g-600" />
</div>
</div>
</div>
<img class="w-75 max-md:!hidden" src="@imgs/draw/draw1.png" alt="draw1" />
</div>
</template>
<script setup lang="ts">
import AppConfig from '@/config'
const systemName = AppConfig.systemInfo.name
const linkList = [
{ label: '项目官网', url: 'https://saithink.top/' },
{ label: '文档', url: 'https://saithink.top/documents/' },
{ label: 'Github', url: 'https://github.com/saithink/saiadmin' },
{ label: '插件市场', url: 'https://saas.saithink.top/' }
]
/**
* 在新标签页中打开指定 URL
* @param url 要打开的网页地址
*/
const goPage = (url: string): void => {
window.open(url, '_blank', 'noopener,noreferrer')
}
</script>

View File

@@ -2,7 +2,7 @@
<div class="art-card h-105 p-4 box-border mb-5 max-sm:mb-4">
<div class="art-card-header">
<div class="title">
<h4>月度登录汇总</h4>
<h4>月度玩家充值汇总</h4>
</div>
</div>
<ArtBarChart
@@ -17,22 +17,22 @@
</template>
<script setup lang="ts">
import { fetchLoginBarChart } from '@/api/dashboard'
import { fetchRechargeBarChart } from '@/api/dashboard'
/**
* 登录数据
* 充值金额数据
*/
const yData = ref<number[]>([])
/**
* 时间数据
* 月份数据
*/
const xData = ref<string[]>([])
onMounted(async () => {
fetchLoginBarChart().then((data) => {
yData.value = data.login_count
xData.value = data.login_month
fetchRechargeBarChart().then((data: any) => {
yData.value = data?.recharge_amount ?? []
xData.value = data?.recharge_month ?? []
})
})
</script>

View File

@@ -2,73 +2,95 @@
<ElRow :gutter="20" class="flex">
<ElCol :sm="12" :md="6" :lg="6">
<div class="art-card relative flex flex-col justify-center h-35 px-5 mb-5 max-sm:mb-4">
<span class="text-g-700 text-sm">用户统计</span>
<ArtCountTo class="text-[26px] font-medium mt-2" :target="statData.user" :duration="1300" />
<span class="text-g-700 text-sm">玩家注册</span>
<ArtCountTo class="text-[26px] font-medium mt-2" :target="statData.player_count" :duration="1300" />
<div class="flex-c mt-1">
<span class="text-xs text-g-600">较上周</span>
<span class="ml-1 text-xs font-semibold text-success">+10%</span>
<span
class="ml-1 text-xs font-semibold"
:class="changeClass(statData.player_count_change)"
>
{{ formatChange(statData.player_count_change) }}
</span>
</div>
<div
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
>
<ArtSvgIcon icon="ri:group-line" class="text-xl text-theme" />
<ArtSvgIcon icon="ri:user-add-line" class="text-xl text-theme" />
</div>
</div>
</ElCol>
<ElCol :sm="12" :md="6" :lg="6">
<div class="art-card relative flex flex-col justify-center h-35 px-5 mb-5 max-sm:mb-4">
<span class="text-g-700 text-sm">附件统计</span>
<span class="text-g-700 text-sm">玩家充值</span>
<ArtCountTo
class="text-[26px] font-medium mt-2"
:target="statData.attach"
:target="statData.charge_amount"
:duration="1300"
:decimals="2"
/>
<div class="flex-c mt-1">
<span class="text-xs text-g-600">较上周</span>
<span class="ml-1 text-xs font-semibold text-success">+10%</span>
<span
class="ml-1 text-xs font-semibold"
:class="changeClass(statData.charge_amount_change)"
>
{{ formatChange(statData.charge_amount_change) }}
</span>
</div>
<div
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
>
<ArtSvgIcon icon="ri:attachment-line" class="text-xl text-theme" />
<ArtSvgIcon icon="ri:money-dollar-circle-line" class="text-xl text-theme" />
</div>
</div>
</ElCol>
<ElCol :sm="12" :md="6" :lg="6">
<div class="art-card relative flex flex-col justify-center h-35 px-5 mb-5 max-sm:mb-4">
<span class="text-g-700 text-sm">登录统计</span>
<span class="text-g-700 text-sm">玩家提现</span>
<ArtCountTo
class="text-[26px] font-medium mt-2"
:target="statData.login"
:target="statData.withdraw_amount"
:duration="1300"
:decimals="2"
/>
<div class="flex-c mt-1">
<span class="text-xs text-g-600">较上周</span>
<span class="ml-1 text-xs font-semibold text-success">+12%</span>
<span
class="ml-1 text-xs font-semibold"
:class="changeClass(statData.withdraw_amount_change)"
>
{{ formatChange(statData.withdraw_amount_change) }}
</span>
</div>
<div
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
>
<ArtSvgIcon icon="ri:fire-line" class="text-xl text-theme" />
<ArtSvgIcon icon="ri:bank-card-line" class="text-xl text-theme" />
</div>
</div>
</ElCol>
<ElCol :sm="12" :md="6" :lg="6">
<div class="art-card relative flex flex-col justify-center h-35 px-5 mb-5 max-sm:mb-4">
<span class="text-g-700 text-sm">操作统计</span>
<span class="text-g-700 text-sm">玩家游玩次数</span>
<ArtCountTo
class="text-[26px] font-medium mt-2"
:target="statData.operate"
:target="statData.play_count"
:duration="1300"
/>
<div class="flex-c mt-1">
<span class="text-xs text-g-600">较上周</span>
<span class="ml-1 text-xs font-semibold text-danger">-5%</span>
<span
class="ml-1 text-xs font-semibold"
:class="changeClass(statData.play_count_change)"
>
{{ formatChange(statData.play_count_change) }}
</span>
</div>
<div
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
>
<ArtSvgIcon icon="ri:pie-chart-line" class="text-xl text-theme" />
<ArtSvgIcon icon="ri:gamepad-line" class="text-xl text-theme" />
</div>
</div>
</ElCol>
@@ -79,15 +101,40 @@
import { fetchStatistics } from '@/api/dashboard'
const statData = ref({
user: 0,
attach: 0,
login: 0,
operate: 0
player_count: 0,
player_count_change: 0,
charge_amount: 0,
charge_amount_change: 0,
withdraw_amount: 0,
withdraw_amount_change: 0,
play_count: 0,
play_count_change: 0
})
function formatChange(val: number): string {
if (val > 0) return `+${val}%`
if (val < 0) return `${val}%`
return '0%'
}
function changeClass(val: number): string {
if (val > 0) return 'text-success'
if (val < 0) return 'text-danger'
return 'text-g-600'
}
onMounted(() => {
fetchStatistics().then((data) => {
statData.value = data
fetchStatistics().then((data: any) => {
statData.value = {
player_count: data?.player_count ?? 0,
player_count_change: data?.player_count_change ?? 0,
charge_amount: data?.charge_amount ?? 0,
charge_amount_change: data?.charge_amount_change ?? 0,
withdraw_amount: data?.withdraw_amount ?? 0,
withdraw_amount_change: data?.withdraw_amount_change ?? 0,
play_count: data?.play_count ?? 0,
play_count_change: data?.play_count_change ?? 0
}
})
})
</script>

View File

@@ -2,7 +2,7 @@
<div class="art-card h-105 p-5 mb-5 max-sm:mb-4">
<div class="art-card-header">
<div class="title">
<h4>近期登录统计</h4>
<h4>近期玩家充值统计</h4>
</div>
</div>
<ArtLineChart
@@ -16,22 +16,22 @@
</template>
<script setup lang="ts">
import { fetchLoginChart } from '@/api/dashboard'
import { fetchRechargeChart } from '@/api/dashboard'
/**
* 登录数据
* 充值金额数据
*/
const yData = ref<number[]>([])
/**
* 时间数据
* 日期数据
*/
const xData = ref<string[]>([])
onMounted(async () => {
fetchLoginChart().then((data) => {
yData.value = data.login_count
xData.value = data.login_date
fetchRechargeChart().then((data: any) => {
yData.value = data?.recharge_amount ?? []
xData.value = data?.recharge_date ?? []
})
})
</script>