优化主页数据统计
This commit is contained in:
@@ -1,31 +1,32 @@
|
|||||||
import request from '@/utils/http'
|
import request from '@/utils/http'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础数据统计
|
* 大富翁工作台卡片统计(玩家注册、充值、提现、游玩次数,含较上周对比)
|
||||||
* @returns 响应
|
* @returns 响应
|
||||||
*/
|
*/
|
||||||
export function fetchStatistics() {
|
export function fetchStatistics() {
|
||||||
return request.get<any>({
|
return request.get<any>({
|
||||||
url: '/core/system/statistics'
|
url: '/core/dice/dashboard/statistics'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录统计图表数据
|
* 近期玩家充值统计(近10天每日充值金额)
|
||||||
* @returns 响应
|
* @returns 响应
|
||||||
*/
|
*/
|
||||||
export function fetchLoginChart() {
|
export function fetchRechargeChart() {
|
||||||
return request.get<any>({
|
return request.get<any>({
|
||||||
url: '/core/system/loginChart'
|
url: '/core/dice/dashboard/rechargeChart'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录统计图表数据
|
* 月度玩家充值汇总(当年1-12月每月充值金额)
|
||||||
* @returns 响应
|
* @returns 响应
|
||||||
*/
|
*/
|
||||||
export function fetchLoginBarChart() {
|
export function fetchRechargeBarChart() {
|
||||||
return request.get<any>({
|
return request.get<any>({
|
||||||
url: '/core/system/loginBarChart'
|
url: '/core/dice/dashboard/rechargeBarChart'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
</ElRow>
|
</ElRow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<AboutProject />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -36,7 +35,6 @@
|
|||||||
import CardList from './modules/card-list.vue'
|
import CardList from './modules/card-list.vue'
|
||||||
import ActiveUser from './modules/active-user.vue'
|
import ActiveUser from './modules/active-user.vue'
|
||||||
import SalesOverview from './modules/sales-overview.vue'
|
import SalesOverview from './modules/sales-overview.vue'
|
||||||
import AboutProject from './modules/about-project.vue'
|
|
||||||
import NewUser from './modules/new-user.vue'
|
import NewUser from './modules/new-user.vue'
|
||||||
import Dynamic from './modules/dynamic-stats.vue'
|
import Dynamic from './modules/dynamic-stats.vue'
|
||||||
import TodoList from './modules/todo-list.vue'
|
import TodoList from './modules/todo-list.vue'
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="art-card h-105 p-4 box-border mb-5 max-sm:mb-4">
|
<div class="art-card h-105 p-4 box-border mb-5 max-sm:mb-4">
|
||||||
<div class="art-card-header">
|
<div class="art-card-header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h4>月度登录汇总</h4>
|
<h4>月度玩家充值汇总</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ArtBarChart
|
<ArtBarChart
|
||||||
@@ -17,22 +17,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { fetchLoginBarChart } from '@/api/dashboard'
|
import { fetchRechargeBarChart } from '@/api/dashboard'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录数据
|
* 充值金额数据
|
||||||
*/
|
*/
|
||||||
const yData = ref<number[]>([])
|
const yData = ref<number[]>([])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间数据
|
* 月份数据
|
||||||
*/
|
*/
|
||||||
const xData = ref<string[]>([])
|
const xData = ref<string[]>([])
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
fetchLoginBarChart().then((data) => {
|
fetchRechargeBarChart().then((data: any) => {
|
||||||
yData.value = data.login_count
|
yData.value = data?.recharge_amount ?? []
|
||||||
xData.value = data.login_month
|
xData.value = data?.recharge_month ?? []
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,73 +2,95 @@
|
|||||||
<ElRow :gutter="20" class="flex">
|
<ElRow :gutter="20" class="flex">
|
||||||
<ElCol :sm="12" :md="6" :lg="6">
|
<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">
|
<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.user" :duration="1300" />
|
<ArtCountTo class="text-[26px] font-medium mt-2" :target="statData.player_count" :duration="1300" />
|
||||||
<div class="flex-c mt-1">
|
<div class="flex-c mt-1">
|
||||||
<span class="text-xs text-g-600">较上周</span>
|
<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>
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
|
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>
|
||||||
</div>
|
</div>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :sm="12" :md="6" :lg="6">
|
<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">
|
<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
|
<ArtCountTo
|
||||||
class="text-[26px] font-medium mt-2"
|
class="text-[26px] font-medium mt-2"
|
||||||
:target="statData.attach"
|
:target="statData.charge_amount"
|
||||||
:duration="1300"
|
:duration="1300"
|
||||||
|
:decimals="2"
|
||||||
/>
|
/>
|
||||||
<div class="flex-c mt-1">
|
<div class="flex-c mt-1">
|
||||||
<span class="text-xs text-g-600">较上周</span>
|
<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>
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
|
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>
|
||||||
</div>
|
</div>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :sm="12" :md="6" :lg="6">
|
<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">
|
<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
|
<ArtCountTo
|
||||||
class="text-[26px] font-medium mt-2"
|
class="text-[26px] font-medium mt-2"
|
||||||
:target="statData.login"
|
:target="statData.withdraw_amount"
|
||||||
:duration="1300"
|
:duration="1300"
|
||||||
|
:decimals="2"
|
||||||
/>
|
/>
|
||||||
<div class="flex-c mt-1">
|
<div class="flex-c mt-1">
|
||||||
<span class="text-xs text-g-600">较上周</span>
|
<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>
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
|
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>
|
||||||
</div>
|
</div>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :sm="12" :md="6" :lg="6">
|
<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">
|
<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
|
<ArtCountTo
|
||||||
class="text-[26px] font-medium mt-2"
|
class="text-[26px] font-medium mt-2"
|
||||||
:target="statData.operate"
|
:target="statData.play_count"
|
||||||
:duration="1300"
|
:duration="1300"
|
||||||
/>
|
/>
|
||||||
<div class="flex-c mt-1">
|
<div class="flex-c mt-1">
|
||||||
<span class="text-xs text-g-600">较上周</span>
|
<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>
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 bottom-0 right-5 m-auto size-12.5 rounded-xl flex-cc bg-theme/10"
|
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>
|
||||||
</div>
|
</div>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
@@ -79,15 +101,40 @@
|
|||||||
import { fetchStatistics } from '@/api/dashboard'
|
import { fetchStatistics } from '@/api/dashboard'
|
||||||
|
|
||||||
const statData = ref({
|
const statData = ref({
|
||||||
user: 0,
|
player_count: 0,
|
||||||
attach: 0,
|
player_count_change: 0,
|
||||||
login: 0,
|
charge_amount: 0,
|
||||||
operate: 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(() => {
|
onMounted(() => {
|
||||||
fetchStatistics().then((data) => {
|
fetchStatistics().then((data: any) => {
|
||||||
statData.value = data
|
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>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="art-card h-105 p-5 mb-5 max-sm:mb-4">
|
<div class="art-card h-105 p-5 mb-5 max-sm:mb-4">
|
||||||
<div class="art-card-header">
|
<div class="art-card-header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h4>近期登录统计</h4>
|
<h4>近期玩家充值统计</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ArtLineChart
|
<ArtLineChart
|
||||||
@@ -16,22 +16,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { fetchLoginChart } from '@/api/dashboard'
|
import { fetchRechargeChart } from '@/api/dashboard'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录数据
|
* 充值金额数据
|
||||||
*/
|
*/
|
||||||
const yData = ref<number[]>([])
|
const yData = ref<number[]>([])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间数据
|
* 日期数据
|
||||||
*/
|
*/
|
||||||
const xData = ref<string[]>([])
|
const xData = ref<string[]>([])
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
fetchLoginChart().then((data) => {
|
fetchRechargeChart().then((data: any) => {
|
||||||
yData.value = data.login_count
|
yData.value = data?.recharge_amount ?? []
|
||||||
xData.value = data.login_date
|
xData.value = data?.recharge_date ?? []
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
183
server/app/dice/controller/DiceDashboardController.php
Normal file
183
server/app/dice/controller/DiceDashboardController.php
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\dice\controller;
|
||||||
|
|
||||||
|
use app\dice\helper\AdminScopeHelper;
|
||||||
|
use app\dice\model\player\DicePlayer;
|
||||||
|
use app\dice\model\player_wallet_record\DicePlayerWalletRecord;
|
||||||
|
use app\dice\model\play_record\DicePlayRecord;
|
||||||
|
use plugin\saiadmin\basic\BaseController;
|
||||||
|
use plugin\saiadmin\service\Permission;
|
||||||
|
use support\Response;
|
||||||
|
use support\think\Db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 大富翁工作台数据统计
|
||||||
|
*/
|
||||||
|
class DiceDashboardController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 工作台卡片统计:玩家注册、充值、提现、游玩次数(含较上周对比)
|
||||||
|
*/
|
||||||
|
#[Permission('工作台数据统计', 'core:console:list')]
|
||||||
|
public function statistics(): Response
|
||||||
|
{
|
||||||
|
$thisWeekStart = date('Y-m-d 00:00:00', strtotime('monday this week'));
|
||||||
|
$thisWeekEnd = date('Y-m-d 23:59:59', strtotime('sunday this week'));
|
||||||
|
$lastWeekStart = date('Y-m-d 00:00:00', strtotime('monday last week'));
|
||||||
|
$lastWeekEnd = date('Y-m-d 23:59:59', strtotime('sunday last week'));
|
||||||
|
|
||||||
|
$adminInfo = $this->adminInfo ?? null;
|
||||||
|
|
||||||
|
$playerQueryThis = DicePlayer::whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
|
||||||
|
$playerQueryLast = DicePlayer::whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
|
||||||
|
AdminScopeHelper::applyAdminScope($playerQueryThis, $adminInfo);
|
||||||
|
AdminScopeHelper::applyAdminScope($playerQueryLast, $adminInfo);
|
||||||
|
$playerThis = $playerQueryThis->count();
|
||||||
|
$playerLast = $playerQueryLast->count();
|
||||||
|
|
||||||
|
$chargeQueryThis = DicePlayerWalletRecord::where('type', 0)
|
||||||
|
->where('coin', '>', 0)
|
||||||
|
->whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
|
||||||
|
$chargeQueryLast = DicePlayerWalletRecord::where('type', 0)
|
||||||
|
->where('coin', '>', 0)
|
||||||
|
->whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
|
||||||
|
AdminScopeHelper::applyAdminScope($chargeQueryThis, $adminInfo);
|
||||||
|
AdminScopeHelper::applyAdminScope($chargeQueryLast, $adminInfo);
|
||||||
|
$chargeThis = $chargeQueryThis->sum('coin');
|
||||||
|
$chargeLast = $chargeQueryLast->sum('coin');
|
||||||
|
|
||||||
|
$withdrawQueryThis = DicePlayerWalletRecord::where('type', 1)
|
||||||
|
->whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
|
||||||
|
$withdrawQueryLast = DicePlayerWalletRecord::where('type', 1)
|
||||||
|
->whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
|
||||||
|
AdminScopeHelper::applyAdminScope($withdrawQueryThis, $adminInfo);
|
||||||
|
AdminScopeHelper::applyAdminScope($withdrawQueryLast, $adminInfo);
|
||||||
|
$withdrawThis = $withdrawQueryThis->sum(Db::raw('ABS(coin)'));
|
||||||
|
$withdrawLast = $withdrawQueryLast->sum(Db::raw('ABS(coin)'));
|
||||||
|
|
||||||
|
$playQueryThis = DicePlayRecord::whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
|
||||||
|
$playQueryLast = DicePlayRecord::whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
|
||||||
|
AdminScopeHelper::applyAdminScope($playQueryThis, $adminInfo);
|
||||||
|
AdminScopeHelper::applyAdminScope($playQueryLast, $adminInfo);
|
||||||
|
$playThis = $playQueryThis->count();
|
||||||
|
$playLast = $playQueryLast->count();
|
||||||
|
|
||||||
|
$playerChange = $this->calcWeekChange($playerThis, $playerLast);
|
||||||
|
$chargeChange = $this->calcWeekChange((float) $chargeThis, (float) $chargeLast);
|
||||||
|
$withdrawChange = $this->calcWeekChange((float) $withdrawThis, (float) $withdrawLast);
|
||||||
|
$playChange = $this->calcWeekChange($playThis, $playLast);
|
||||||
|
|
||||||
|
return $this->success([
|
||||||
|
'player_count' => $playerThis,
|
||||||
|
'player_count_change' => $playerChange,
|
||||||
|
'charge_amount' => (float) $chargeThis,
|
||||||
|
'charge_amount_change' => $chargeChange,
|
||||||
|
'withdraw_amount' => (float) $withdrawThis,
|
||||||
|
'withdraw_amount_change' => $withdrawChange,
|
||||||
|
'play_count' => $playThis,
|
||||||
|
'play_count_change' => $playChange,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近期玩家充值统计(近10天每日充值金额)
|
||||||
|
*/
|
||||||
|
#[Permission('工作台数据统计', 'core:console:list')]
|
||||||
|
public function rechargeChart(): Response
|
||||||
|
{
|
||||||
|
$adminInfo = $this->adminInfo ?? null;
|
||||||
|
$allowedIds = AdminScopeHelper::getAllowedAdminIds($adminInfo);
|
||||||
|
$adminCondition = '';
|
||||||
|
if ($allowedIds !== null) {
|
||||||
|
if (empty($allowedIds)) {
|
||||||
|
$data = [];
|
||||||
|
foreach (range(0, 9) as $n) {
|
||||||
|
$data[] = ['recharge_date' => date('Y-m-d', strtotime("-{$n} days")), 'recharge_amount' => 0];
|
||||||
|
}
|
||||||
|
$data = array_reverse($data);
|
||||||
|
return $this->success([
|
||||||
|
'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
|
||||||
|
'recharge_date' => array_column($data, 'recharge_date'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$idsStr = implode(',', array_map('intval', $allowedIds));
|
||||||
|
$adminCondition = " AND w.admin_id IN ({$idsStr})";
|
||||||
|
}
|
||||||
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
d.date AS recharge_date,
|
||||||
|
IFNULL(SUM(w.coin), 0) AS recharge_amount
|
||||||
|
FROM
|
||||||
|
(SELECT CURDATE() - INTERVAL (a.N) DAY AS date
|
||||||
|
FROM (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
|
||||||
|
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
|
||||||
|
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
|
||||||
|
) d
|
||||||
|
LEFT JOIN dice_player_wallet_record w
|
||||||
|
ON DATE(w.create_time) = d.date AND w.type = 0 AND w.coin > 0 {$adminCondition}
|
||||||
|
GROUP BY d.date
|
||||||
|
ORDER BY d.date ASC
|
||||||
|
";
|
||||||
|
$data = Db::query($sql);
|
||||||
|
return $this->success([
|
||||||
|
'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
|
||||||
|
'recharge_date' => array_column($data, 'recharge_date'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 月度玩家充值汇总(当年1-12月每月充值金额)
|
||||||
|
*/
|
||||||
|
#[Permission('工作台数据统计', 'core:console:list')]
|
||||||
|
public function rechargeBarChart(): Response
|
||||||
|
{
|
||||||
|
$adminInfo = $this->adminInfo ?? null;
|
||||||
|
$allowedIds = AdminScopeHelper::getAllowedAdminIds($adminInfo);
|
||||||
|
$adminCondition = '';
|
||||||
|
if ($allowedIds !== null) {
|
||||||
|
if (empty($allowedIds)) {
|
||||||
|
$data = [];
|
||||||
|
for ($m = 1; $m <= 12; $m++) {
|
||||||
|
$data[] = ['recharge_month' => sprintf('%02d月', $m), 'recharge_amount' => 0];
|
||||||
|
}
|
||||||
|
return $this->success([
|
||||||
|
'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
|
||||||
|
'recharge_month' => array_column($data, 'recharge_month'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$idsStr = implode(',', array_map('intval', $allowedIds));
|
||||||
|
$adminCondition = " AND w.admin_id IN ({$idsStr})";
|
||||||
|
}
|
||||||
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
CONCAT(LPAD(m.month_num, 2, '0'), '月') AS recharge_month,
|
||||||
|
IFNULL(SUM(w.coin), 0) AS recharge_amount
|
||||||
|
FROM
|
||||||
|
(SELECT 1 AS month_num UNION ALL SELECT 2 UNION ALL SELECT 3
|
||||||
|
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
|
||||||
|
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
|
||||||
|
UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) m
|
||||||
|
LEFT JOIN dice_player_wallet_record w
|
||||||
|
ON YEAR(w.create_time) = YEAR(CURDATE())
|
||||||
|
AND MONTH(w.create_time) = m.month_num
|
||||||
|
AND w.type = 0 AND w.coin > 0 {$adminCondition}
|
||||||
|
GROUP BY m.month_num
|
||||||
|
ORDER BY m.month_num ASC
|
||||||
|
";
|
||||||
|
$data = Db::query($sql);
|
||||||
|
return $this->success([
|
||||||
|
'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
|
||||||
|
'recharge_month' => array_column($data, 'recharge_month'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calcWeekChange($current, $last): float
|
||||||
|
{
|
||||||
|
if ($last == 0) {
|
||||||
|
return $current > 0 ? 100.0 : 0.0;
|
||||||
|
}
|
||||||
|
return round((($current - $last) / $last) * 100, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,10 @@ Route::group('/core', function () {
|
|||||||
Route::get('/system/statistics', [plugin\saiadmin\app\controller\SystemController::class, 'statistics']);
|
Route::get('/system/statistics', [plugin\saiadmin\app\controller\SystemController::class, 'statistics']);
|
||||||
Route::get('/system/loginChart', [plugin\saiadmin\app\controller\SystemController::class, 'loginChart']);
|
Route::get('/system/loginChart', [plugin\saiadmin\app\controller\SystemController::class, 'loginChart']);
|
||||||
Route::get('/system/loginBarChart', [plugin\saiadmin\app\controller\SystemController::class, 'loginBarChart']);
|
Route::get('/system/loginBarChart', [plugin\saiadmin\app\controller\SystemController::class, 'loginBarChart']);
|
||||||
|
// 大富翁工作台统计(覆盖默认统计)
|
||||||
|
Route::get('/dice/dashboard/statistics', [\app\dice\controller\DiceDashboardController::class, 'statistics']);
|
||||||
|
Route::get('/dice/dashboard/rechargeChart', [\app\dice\controller\DiceDashboardController::class, 'rechargeChart']);
|
||||||
|
Route::get('/dice/dashboard/rechargeBarChart', [\app\dice\controller\DiceDashboardController::class, 'rechargeBarChart']);
|
||||||
Route::get('/system/clearAllCache', [plugin\saiadmin\app\controller\SystemController::class, 'clearAllCache']);
|
Route::get('/system/clearAllCache', [plugin\saiadmin\app\controller\SystemController::class, 'clearAllCache']);
|
||||||
|
|
||||||
Route::get("/system/getResourceCategory", [plugin\saiadmin\app\controller\SystemController::class, 'getResourceCategory']);
|
Route::get("/system/getResourceCategory", [plugin\saiadmin\app\controller\SystemController::class, 'getResourceCategory']);
|
||||||
|
|||||||
Reference in New Issue
Block a user