Xboard/app/Http/Controllers/V2/Admin/StatController.php

510 lines
20 KiB
PHP
Raw Normal View History

2023-11-17 01:44:01 -05:00
<?php
namespace App\Http\Controllers\V2\Admin;
use App\Http\Controllers\Controller;
use App\Models\CommissionLog;
use App\Models\Order;
2025-01-06 12:20:11 -05:00
use App\Models\Server;
2023-11-17 01:44:01 -05:00
use App\Models\Stat;
use App\Models\StatServer;
use App\Models\StatUser;
use App\Models\Ticket;
use App\Models\User;
use App\Services\StatisticalService;
use Illuminate\Http\Request;
class StatController extends Controller
{
2025-01-06 12:20:11 -05:00
private $service;
public function __construct(StatisticalService $service)
2023-11-17 01:44:01 -05:00
{
2025-01-06 12:20:11 -05:00
$this->service = $service;
}
public function getOverride(Request $request)
{
// 获取在线节点数
$onlineNodes = Server::all()->filter(function ($server) {
$server->loadServerStatus();
return $server->is_online;
})->count();
// 获取在线设备数和在线用户数
$onlineDevices = User::where('t', '>=', time() - 600)
->sum('online_count');
$onlineUsers = User::where('t', '>=', time() - 600)
->count();
// 获取今日流量统计
$todayStart = strtotime('today');
$todayTraffic = StatServer::where('record_at', '>=', $todayStart)
->where('record_at', '<', time())
->selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
// 获取本月流量统计
$monthStart = strtotime(date('Y-m-1'));
$monthTraffic = StatServer::where('record_at', '>=', $monthStart)
->where('record_at', '<', time())
->selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
// 获取总流量统计
$totalTraffic = StatServer::selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
2025-01-06 12:20:11 -05:00
return [
'data' => [
'month_income' => Order::where('created_at', '>=', strtotime(date('Y-m-1')))
->where('created_at', '<', time())
->whereNotIn('status', [0, 2])
->sum('total_amount'),
'month_register_total' => User::where('created_at', '>=', strtotime(date('Y-m-1')))
->where('created_at', '<', time())
->count(),
'ticket_pending_total' => Ticket::where('status', 0)
->count(),
'commission_pending_total' => Order::where('commission_status', 0)
->where('invite_user_id', '!=', NULL)
->whereNotIn('status', [0, 2])
->where('commission_balance', '>', 0)
->count(),
'day_income' => Order::where('created_at', '>=', strtotime(date('Y-m-d')))
->where('created_at', '<', time())
->whereNotIn('status', [0, 2])
->sum('total_amount'),
'last_month_income' => Order::where('created_at', '>=', strtotime('-1 month', strtotime(date('Y-m-1'))))
->where('created_at', '<', strtotime(date('Y-m-1')))
->whereNotIn('status', [0, 2])
->sum('total_amount'),
'commission_month_payout' => CommissionLog::where('created_at', '>=', strtotime(date('Y-m-1')))
->where('created_at', '<', time())
->sum('get_amount'),
'commission_last_month_payout' => CommissionLog::where('created_at', '>=', strtotime('-1 month', strtotime(date('Y-m-1'))))
->where('created_at', '<', strtotime(date('Y-m-1')))
->sum('get_amount'),
// 新增统计数据
'online_nodes' => $onlineNodes,
'online_devices' => $onlineDevices,
'online_users' => $onlineUsers,
'today_traffic' => [
'upload' => $todayTraffic->upload ?? 0,
'download' => $todayTraffic->download ?? 0,
'total' => $todayTraffic->total ?? 0
],
'month_traffic' => [
'upload' => $monthTraffic->upload ?? 0,
'download' => $monthTraffic->download ?? 0,
'total' => $monthTraffic->total ?? 0
],
'total_traffic' => [
'upload' => $totalTraffic->upload ?? 0,
'download' => $totalTraffic->download ?? 0,
'total' => $totalTraffic->total ?? 0
]
2025-01-06 12:20:11 -05:00
]
];
}
2023-11-17 01:44:01 -05:00
2025-01-07 22:07:13 -05:00
/**
* Get order statistics with filtering and pagination
*
* @param Request $request
* @return array
*/
2025-01-06 12:20:11 -05:00
public function getOrder(Request $request)
{
2025-01-07 22:07:13 -05:00
$request->validate([
'start_date' => 'nullable|date_format:Y-m-d',
'end_date' => 'nullable|date_format:Y-m-d',
'type' => 'nullable|in:paid_total,paid_count,commission_total,commission_count',
]);
$query = Stat::where('record_type', 'd');
// Apply date filters
if ($request->input('start_date')) {
$query->where('record_at', '>=', strtotime($request->input('start_date')));
}
if ($request->input('end_date')) {
$query->where('record_at', '<=', strtotime($request->input('end_date') . ' 23:59:59'));
}
$statistics = $query->orderBy('record_at', 'DESC')
2025-01-08 13:06:32 -05:00
->get();
2025-01-07 22:07:13 -05:00
$summary = [
'paid_total' => 0,
'paid_count' => 0,
'commission_total' => 0,
'commission_count' => 0,
2025-01-09 02:58:32 -05:00
'start_date' => $request->input('start_date', date('Y-m-d', $statistics->last()?->record_at)),
'end_date' => $request->input('end_date', date('Y-m-d', $statistics->first()?->record_at)),
2025-01-07 22:07:13 -05:00
'avg_paid_amount' => 0,
'avg_commission_amount' => 0
];
$dailyStats = [];
2025-01-06 12:20:11 -05:00
foreach ($statistics as $statistic) {
2025-01-07 22:07:13 -05:00
$date = date('Y-m-d', $statistic['record_at']);
// Update summary
$summary['paid_total'] += $statistic['paid_total'];
$summary['paid_count'] += $statistic['paid_count'];
$summary['commission_total'] += $statistic['commission_total'];
$summary['commission_count'] += $statistic['commission_count'];
// Calculate daily stats
$dailyData = [
2025-01-06 12:20:11 -05:00
'date' => $date,
2025-01-07 22:07:13 -05:00
'paid_total' => $statistic['paid_total'],
'paid_count' => $statistic['paid_count'],
'commission_total' => $statistic['commission_total'],
'commission_count' => $statistic['commission_count'],
'avg_order_amount' => $statistic['paid_count'] > 0 ? round($statistic['paid_total'] / $statistic['paid_count'], 2) : 0,
'avg_commission_amount' => $statistic['commission_count'] > 0 ? round($statistic['commission_total'] / $statistic['commission_count'], 2) : 0
2023-11-17 01:44:01 -05:00
];
2025-01-07 22:07:13 -05:00
if ($request->input('type')) {
$dailyStats[] = [
'date' => $date,
'value' => $statistic[$request->input('type')],
'type' => $this->getTypeLabel($request->input('type'))
];
} else {
$dailyStats[] = $dailyData;
}
}
// Calculate averages for summary
if ($summary['paid_count'] > 0) {
$summary['avg_paid_amount'] = round($summary['paid_total'] / $summary['paid_count'], 2);
}
if ($summary['commission_count'] > 0) {
$summary['avg_commission_amount'] = round($summary['commission_total'] / $summary['commission_count'], 2);
2023-11-17 01:44:01 -05:00
}
2025-01-07 22:07:13 -05:00
// Add percentage calculations to summary
$summary['commission_rate'] = $summary['paid_total'] > 0
? round(($summary['commission_total'] / $summary['paid_total']) * 100, 2)
: 0;
2023-11-17 01:44:01 -05:00
return [
2025-01-07 22:07:13 -05:00
'code' => 0,
'message' => 'success',
'data' => [
'list' => array_reverse($dailyStats),
'summary' => $summary,
]
2023-11-17 01:44:01 -05:00
];
}
2025-01-07 22:07:13 -05:00
/**
* Get human readable label for statistic type
*
* @param string $type
* @return string
*/
private function getTypeLabel(string $type): string
{
return match ($type) {
'paid_total' => '收款金额',
'paid_count' => '收款笔数',
'commission_total' => '佣金金额(已发放)',
'commission_count' => '佣金笔数(已发放)',
default => $type
};
}
2025-01-06 12:20:11 -05:00
// 获取当日实时流量排行
public function getServerLastRank()
{
$data = $this->service->getServerRank();
return $this->success(data: $data);
}
// 获取昨日节点流量排行
public function getServerYesterdayRank()
{
$data = $this->service->getServerRank('yesterday');
return $this->success($data);
}
public function getStatUser(Request $request)
2023-11-17 01:44:01 -05:00
{
$request->validate([
2025-01-06 12:20:11 -05:00
'user_id' => 'required|integer'
2023-11-17 01:44:01 -05:00
]);
2025-01-06 12:20:11 -05:00
$pageSize = $request->input('pageSize', 10);
$records = StatUser::orderBy('record_at', 'DESC')
->where('user_id', $request->input('user_id'))
->paginate($pageSize);
$data = $records->items();
return [
'data' => $data,
'total' => $records->total(),
];
}
public function getStatRecord(Request $request)
{
return [
'data' => $this->service->getStatRecord($request->input('type'))
];
}
/**
* Get comprehensive statistics data including income, users, and growth rates
*/
public function getStats()
{
$currentMonthStart = strtotime(date('Y-m-01'));
$lastMonthStart = strtotime('-1 month', $currentMonthStart);
$twoMonthsAgoStart = strtotime('-2 month', $currentMonthStart);
// Today's start timestamp
$todayStart = strtotime('today');
$yesterdayStart = strtotime('-1 day', $todayStart);
// 获取在线节点数
$onlineNodes = Server::all()->filter(function ($server) {
$server->loadServerStatus();
return $server->is_online;
})->count();
// 获取在线设备数和在线用户数
$onlineDevices = User::where('t', '>=', time() - 600)
->sum('online_count');
$onlineUsers = User::where('t', '>=', time() - 600)
->count();
// 获取今日流量统计
$todayTraffic = StatServer::where('record_at', '>=', $todayStart)
->where('record_at', '<', time())
->selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
// 获取本月流量统计
$monthTraffic = StatServer::where('record_at', '>=', $currentMonthStart)
->where('record_at', '<', time())
->selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
// 获取总流量统计
$totalTraffic = StatServer::selectRaw('SUM(u) as upload, SUM(d) as download, SUM(u + d) as total')
->first();
// Today's income
$todayIncome = Order::where('created_at', '>=', $todayStart)
->where('created_at', '<', time())
->whereNotIn('status', [0, 2])
->sum('total_amount');
// Yesterday's income for day growth calculation
$yesterdayIncome = Order::where('created_at', '>=', $yesterdayStart)
->where('created_at', '<', $todayStart)
->whereNotIn('status', [0, 2])
->sum('total_amount');
2025-01-06 12:20:11 -05:00
// Current month income
$currentMonthIncome = Order::where('created_at', '>=', $currentMonthStart)
->where('created_at', '<', time())
->whereNotIn('status', [0, 2])
->sum('total_amount');
// Last month income
$lastMonthIncome = Order::where('created_at', '>=', $lastMonthStart)
->where('created_at', '<', $currentMonthStart)
->whereNotIn('status', [0, 2])
->sum('total_amount');
// Last month commission payout
$lastMonthCommissionPayout = CommissionLog::where('created_at', '>=', $lastMonthStart)
->where('created_at', '<', $currentMonthStart)
->sum('get_amount');
// Current month commission payout
$currentMonthCommissionPayout = CommissionLog::where('created_at', '>=', $currentMonthStart)
->where('created_at', '<', time())
->sum('get_amount');
2025-01-06 12:20:11 -05:00
// Current month new users
$currentMonthNewUsers = User::where('created_at', '>=', $currentMonthStart)
->where('created_at', '<', time())
->count();
// Total users
$totalUsers = User::count();
// Active users (users with valid subscription)
$activeUsers = User::where(function ($query) {
$query->where('expired_at', '>=', time())
->orWhere('expired_at', NULL);
})->count();
// Previous month income for growth calculation
$twoMonthsAgoIncome = Order::where('created_at', '>=', $twoMonthsAgoStart)
->where('created_at', '<', $lastMonthStart)
->whereNotIn('status', [0, 2])
->sum('total_amount');
// Previous month commission for growth calculation
$twoMonthsAgoCommission = CommissionLog::where('created_at', '>=', $twoMonthsAgoStart)
->where('created_at', '<', $lastMonthStart)
->sum('get_amount');
// Previous month users for growth calculation
$lastMonthNewUsers = User::where('created_at', '>=', $lastMonthStart)
->where('created_at', '<', $currentMonthStart)
->count();
// Calculate growth rates
$monthIncomeGrowth = $lastMonthIncome > 0 ? round(($currentMonthIncome - $lastMonthIncome) / $lastMonthIncome * 100, 1) : 0;
$lastMonthIncomeGrowth = $twoMonthsAgoIncome > 0 ? round(($lastMonthIncome - $twoMonthsAgoIncome) / $twoMonthsAgoIncome * 100, 1) : 0;
$commissionGrowth = $twoMonthsAgoCommission > 0 ? round(($lastMonthCommissionPayout - $twoMonthsAgoCommission) / $twoMonthsAgoCommission * 100, 1) : 0;
$userGrowth = $lastMonthNewUsers > 0 ? round(($currentMonthNewUsers - $lastMonthNewUsers) / $lastMonthNewUsers * 100, 1) : 0;
$dayIncomeGrowth = $yesterdayIncome > 0 ? round(($todayIncome - $yesterdayIncome) / $yesterdayIncome * 100, 1) : 0;
2025-01-06 12:20:11 -05:00
// 获取待处理工单和佣金数据
$ticketPendingTotal = Ticket::where('status', 0)->count();
$commissionPendingTotal = Order::where('commission_status', 0)
->where('invite_user_id', '!=', NULL)
->whereIn('status', [Order::STATUS_COMPLETED])
->where('commission_balance', '>', 0)
->count();
2023-11-17 01:44:01 -05:00
return [
2025-01-06 12:20:11 -05:00
'data' => [
// 收入相关
'todayIncome' => $todayIncome,
'dayIncomeGrowth' => $dayIncomeGrowth,
2025-01-06 12:20:11 -05:00
'currentMonthIncome' => $currentMonthIncome,
'lastMonthIncome' => $lastMonthIncome,
'monthIncomeGrowth' => $monthIncomeGrowth,
'lastMonthIncomeGrowth' => $lastMonthIncomeGrowth,
// 佣金相关
'currentMonthCommissionPayout' => $currentMonthCommissionPayout,
2025-01-06 12:20:11 -05:00
'lastMonthCommissionPayout' => $lastMonthCommissionPayout,
'commissionGrowth' => $commissionGrowth,
'commissionPendingTotal' => $commissionPendingTotal,
// 用户相关
2025-01-06 12:20:11 -05:00
'currentMonthNewUsers' => $currentMonthNewUsers,
'totalUsers' => $totalUsers,
'activeUsers' => $activeUsers,
'userGrowth' => $userGrowth,
'onlineUsers' => $onlineUsers,
'onlineDevices' => $onlineDevices,
// 工单相关
'ticketPendingTotal' => $ticketPendingTotal,
// 节点相关
'onlineNodes' => $onlineNodes,
// 流量统计
'todayTraffic' => [
'upload' => $todayTraffic->upload ?? 0,
'download' => $todayTraffic->download ?? 0,
'total' => $todayTraffic->total ?? 0
],
'monthTraffic' => [
'upload' => $monthTraffic->upload ?? 0,
'download' => $monthTraffic->download ?? 0,
'total' => $monthTraffic->total ?? 0
],
'totalTraffic' => [
'upload' => $totalTraffic->upload ?? 0,
'download' => $totalTraffic->download ?? 0,
'total' => $totalTraffic->total ?? 0
]
2025-01-06 12:20:11 -05:00
]
2023-11-17 01:44:01 -05:00
];
}
2025-01-06 12:20:11 -05:00
/**
* Get traffic ranking data for nodes or users
*
* @param Request $request
* @return array
*/
public function getTrafficRank(Request $request)
2023-11-17 01:44:01 -05:00
{
$request->validate([
2025-01-06 12:20:11 -05:00
'type' => 'required|in:node,user',
'start_time' => 'nullable|integer|min:1000000000|max:9999999999',
'end_time' => 'nullable|integer|min:1000000000|max:9999999999'
2023-11-17 01:44:01 -05:00
]);
2025-01-06 12:20:11 -05:00
$type = $request->input('type');
$startDate = $request->input('start_time', strtotime('-7 days'));
$endDate = $request->input('end_time', time());
$previousStartDate = $startDate - ($endDate - $startDate);
$previousEndDate = $startDate;
if ($type === 'node') {
// Get node traffic data
$currentData = StatServer::selectRaw('server_id as id, SUM(u + d) as value')
->where('record_at', '>=', $startDate)
->where('record_at', '<=', $endDate)
->groupBy('server_id')
->orderBy('value', 'DESC')
->limit(10)
->get();
// Get previous period data for comparison
$previousData = StatServer::selectRaw('server_id as id, SUM(u + d) as value')
->where('record_at', '>=', $previousStartDate)
->where('record_at', '<', $previousEndDate)
->whereIn('server_id', $currentData->pluck('id'))
->groupBy('server_id')
->get()
->keyBy('id');
} else {
// Get user traffic data
$currentData = StatUser::selectRaw('user_id as id, SUM(u + d) as value')
->where('record_at', '>=', $startDate)
->where('record_at', '<=', $endDate)
->groupBy('user_id')
->orderBy('value', 'DESC')
->limit(10)
->get();
// Get previous period data for comparison
$previousData = StatUser::selectRaw('user_id as id, SUM(u + d) as value')
->where('record_at', '>=', $previousStartDate)
->where('record_at', '<', $previousEndDate)
->whereIn('user_id', $currentData->pluck('id'))
->groupBy('user_id')
->get()
->keyBy('id');
}
$result = [];
foreach ($currentData as $data) {
$previousValue = isset($previousData[$data->id]) ? $previousData[$data->id]->value : 0;
$change = $previousValue > 0 ? round(($data->value - $previousValue) / $previousValue * 100, 1) : 0;
$name = $type === 'node'
? optional(Server::find($data->id))->name ?? "Node {$data->id}"
: optional(User::find($data->id))->email ?? "User {$data->id}";
$result[] = [
'id' => (string) $data->id,
'name' => $name,
2025-01-07 22:07:13 -05:00
'value' => $data->value, // Convert to GB
'previousValue' => $previousValue, // Convert to GB
2025-01-06 12:20:11 -05:00
'change' => $change,
'timestamp' => date('c', $endDate)
];
}
2023-11-17 01:44:01 -05:00
return [
2025-01-06 12:20:11 -05:00
'timestamp' => date('c'),
'data' => $result
2023-11-17 01:44:01 -05:00
];
}
}