option('period'); $appId = $this->option('app'); $exportFile = $this->option('export'); $this->info("Transfer模块统计报告 - {$period}"); $this->line(str_repeat('=', 60)); try { // 获取时间范围 [$startDate, $endDate] = $this->getDateRange($period); $this->info("统计时间: {$startDate} 至 {$endDate}"); $this->line(''); // 基础统计 $this->showBasicStats($startDate, $endDate, $appId); // 按应用统计 $this->showAppStats($startDate, $endDate, $appId); // 按状态统计 $this->showStatusStats($startDate, $endDate, $appId); // 按小时统计(仅当日) if ($period === 'today') { $this->showHourlyStats($startDate, $endDate, $appId); } // 导出数据 if ($exportFile) { $this->exportStats($startDate, $endDate, $appId, $exportFile); } return 0; } catch (\Exception $e) { $this->error("统计失败: " . $e->getMessage()); return 1; } } /** * 获取日期范围 */ private function getDateRange(string $period): array { return match ($period) { 'today' => [ now()->startOfDay()->toDateTimeString(), now()->endOfDay()->toDateTimeString() ], 'yesterday' => [ now()->subDay()->startOfDay()->toDateTimeString(), now()->subDay()->endOfDay()->toDateTimeString() ], 'week' => [ now()->startOfWeek()->toDateTimeString(), now()->endOfWeek()->toDateTimeString() ], 'month' => [ now()->startOfMonth()->toDateTimeString(), now()->endOfMonth()->toDateTimeString() ], default => throw new \InvalidArgumentException("无效的统计周期: {$period}") }; } /** * 显示基础统计 */ private function showBasicStats(string $startDate, string $endDate, ?string $appId): void { $query = TransferOrder::whereBetween('created_at', [$startDate, $endDate]); if ($appId) { $query->where('transfer_app_id', $appId); } $totalOrders = $query->count(); $totalAmount = $query->sum('amount'); $inOrders = (clone $query)->where('type', TransferType::IN)->count(); $outOrders = (clone $query)->where('type', TransferType::OUT)->count(); $inAmount = (clone $query)->where('type', TransferType::IN)->sum('amount'); $outAmount = (clone $query)->where('type', TransferType::OUT)->sum('amount'); $completedOrders = (clone $query)->where('status', TransferStatus::COMPLETED)->count(); $failedOrders = (clone $query)->where('status', TransferStatus::FAILED)->count(); $this->info('基础统计:'); $this->table( ['指标', '数值'], [ ['总订单数', number_format($totalOrders)], ['总金额', number_format($totalAmount, 2)], ['转入订单', number_format($inOrders)], ['转出订单', number_format($outOrders)], ['转入金额', number_format($inAmount, 2)], ['转出金额', number_format($outAmount, 2)], ['成功订单', number_format($completedOrders)], ['失败订单', number_format($failedOrders)], ['成功率', $totalOrders > 0 ? number_format($completedOrders / $totalOrders * 100, 2) . '%' : '0%'], ] ); $this->line(''); } /** * 显示按应用统计 */ private function showAppStats(string $startDate, string $endDate, ?string $appId): void { $query = DB::table('transfer_orders as o') ->join('transfer_apps as a', 'o.transfer_app_id', '=', 'a.id') ->whereBetween('o.created_at', [$startDate, $endDate]) ->select([ 'a.title as app_name', DB::raw('COUNT(*) as total_orders'), DB::raw('SUM(o.amount) as total_amount'), DB::raw('SUM(CASE WHEN o.type = 1 THEN 1 ELSE 0 END) as in_orders'), DB::raw('SUM(CASE WHEN o.type = 2 THEN 1 ELSE 0 END) as out_orders'), DB::raw('SUM(CASE WHEN o.status = 100 THEN 1 ELSE 0 END) as completed_orders'), ]) ->groupBy('a.id', 'a.title') ->orderBy('total_amount', 'desc'); if ($appId) { $query->where('a.id', $appId); } $stats = $query->get(); if ($stats->isNotEmpty()) { $this->info('按应用统计:'); $this->table( ['应用名称', '总订单', '总金额', '转入', '转出', '成功', '成功率'], $stats->map(function ($stat) { $successRate = $stat->total_orders > 0 ? number_format($stat->completed_orders / $stat->total_orders * 100, 1) . '%' : '0%'; return [ $stat->app_name, number_format($stat->total_orders), number_format($stat->total_amount, 2), number_format($stat->in_orders), number_format($stat->out_orders), number_format($stat->completed_orders), $successRate, ]; }) ); $this->line(''); } } /** * 显示按状态统计 */ private function showStatusStats(string $startDate, string $endDate, ?string $appId): void { $query = TransferOrder::whereBetween('created_at', [$startDate, $endDate]) ->select([ 'status', DB::raw('COUNT(*) as count'), DB::raw('SUM(amount) as amount') ]) ->groupBy('status') ->orderBy('status'); if ($appId) { $query->where('transfer_app_id', $appId); } $stats = $query->get(); if ($stats->isNotEmpty()) { $this->info('按状态统计:'); $this->table( ['状态', '订单数', '金额'], $stats->map(function ($stat) { $status = TransferStatus::from($stat->status); return [ $status->getDescription(), number_format($stat->count), number_format($stat->amount, 2), ]; }) ); $this->line(''); } } /** * 显示按小时统计 */ private function showHourlyStats(string $startDate, string $endDate, ?string $appId): void { $query = TransferOrder::whereBetween('created_at', [$startDate, $endDate]) ->select([ DB::raw('HOUR(created_at) as hour'), DB::raw('COUNT(*) as count'), DB::raw('SUM(amount) as amount') ]) ->groupBy(DB::raw('HOUR(created_at)')) ->orderBy('hour'); if ($appId) { $query->where('transfer_app_id', $appId); } $stats = $query->get(); if ($stats->isNotEmpty()) { $this->info('按小时统计:'); $this->table( ['小时', '订单数', '金额'], $stats->map(function ($stat) { return [ sprintf('%02d:00', $stat->hour), number_format($stat->count), number_format($stat->amount, 2), ]; }) ); $this->line(''); } } /** * 导出统计数据 */ private function exportStats(string $startDate, string $endDate, ?string $appId, string $filename): void { $this->info("正在导出统计数据到 {$filename}..."); // 这里可以实现CSV或Excel导出逻辑 $this->info('导出功能待实现'); } }