* @Date: 2026-07-17 17:02:05 * @LastEditors: YwxApp * @LastEditTime: 2026-08-03 13:33:07 * @Description: * @FilePath: \ywxapp_dev\app\backend\controller\AddonMonitor.php * @CustomString: Copyright (c) 2026 YwxApp */ declare(strict_types=1); namespace app\backend\controller; use think\facade\View; use ywxapp\controller\BackendBase; use ywxapp\service\AddonPerformanceMonitor; use ywxapp\service\AddonHotReload; /** * AddonMonitor 类 * * @author ywxapp */ class AddonMonitor extends BackendBase { protected $noNeedLogin = []; protected $noNeedVerify = []; public function index() { if ($this->request->isAjax()) { $action = $this->request->param('action', 'overview'); switch ($action) { case 'overview': return $this->getOverview(); case 'performance': return $this->getPerformance(); case 'health': return $this->getHealth(); case 'reload': return $this->getReloadStats(); case 'reload_addon': return $this->reloadAddon(); case 'clear_performance': return $this->clearPerformanceData(); default: return $this->result->error('未知操作'); } } return View::fetch('addon_monitor/index'); } /** * 获取概览数据 */ private function getOverview() { $overview = AddonPerformanceMonitor::getAllPerformanceOverview(); $problematic = AddonPerformanceMonitor::getProblematicaddon(); $reloadStats = AddonHotReload::getReloadStatistics(); // 统计数据 $totaladdon = count($overview); $healthyaddon = 0; $problematicaddon = count($problematic); $totalCalls = 0; $avgExecutionTime = 0; $avgSuccessRate = 0; foreach ($overview as $stats) { if ($stats['success_rate'] > 95 && $stats['avg_execution_time'] < 1.0) { $healthyaddon++; } $totalCalls += $stats['total_calls']; $avgExecutionTime += $stats['avg_execution_time']; $avgSuccessRate += $stats['success_rate']; } if ($totaladdon > 0) { $avgExecutionTime = $avgExecutionTime / $totaladdon; $avgSuccessRate = $avgSuccessRate / $totaladdon; } return $this->result->success([ 'total_addon' => $totaladdon, 'healthy_addon' => $healthyaddon, 'problematic_addon' => $problematicaddon, 'total_calls' => $totalCalls, 'avg_execution_time' => round($avgExecutionTime * 1000, 2), 'avg_success_rate' => round($avgSuccessRate, 2), 'reload_stats' => $reloadStats ]); } /** * 获取性能详情 */ private function getPerformance() { $addon = $this->request->param('addon', ''); if (empty($addon)) { // 返回所有插件性能数据 $overview = AddonPerformanceMonitor::getAllPerformanceOverview(); return $this->result->success($overview); } else { // 返回指定插件性能数据 $stats = AddonPerformanceMonitor::getPerformanceStats($addon); return $this->result->success($stats); } } /** * 获取健康状态 */ private function getHealth() { $problematic = AddonPerformanceMonitor::getProblematicaddon(); $overview = AddonPerformanceMonitor::getAllPerformanceOverview(); // 生成健康报告 $healthReport = []; foreach ($overview as $addon => $stats) { $isHealthy = true; $issues = []; if ($stats['avg_execution_time'] > AddonPerformanceMonitor::PERFORMANCE_THRESHOLD) { $isHealthy = false; $issues[] = '执行时间过长'; } if ($stats['avg_memory_usage'] > AddonPerformanceMonitor::MEMORY_THRESHOLD) { $isHealthy = false; $issues[] = '内存使用过多'; } if ($stats['success_rate'] < 90) { $isHealthy = false; $issues[] = '成功率过低'; } $healthReport[$addon] = [ 'healthy' => $isHealthy, 'issues' => $issues, 'stats' => $stats ]; } return $this->result->success([ 'health_report' => $healthReport, 'problematic_addon' => $problematic ]); } /** * 获取热重载统计 */ private function getReloadStats() { $stats = AddonHotReload::getReloadStatistics(); return $this->result->success($stats); } /** * 重载插件 */ private function reloadAddon() { $addon = $this->request->param('addon', ''); $force = $this->request->param('force', false); if (empty($addon)) { return $this->result->error('请指定插件名称'); } if (!config('app.app_debug')) { return $this->result->error('热重载功能仅在开发环境可用'); } try { $reloaded = AddonHotReload::reloadAddon($addon, $force); if ($reloaded) { $status = AddonHotReload::getReloadStatus($addon); return $this->result->success([ 'reloaded' => true, 'status' => $status ], '插件重载成功'); } else { return $this->result->success([ 'reloaded' => false ], '插件无文件变更,无需重载'); } } catch (\Exception $e) { return $this->result->error('插件重载失败:' . $e->getMessage()); } } /** * 清除性能数据 */ private function clearPerformanceData() { $addon = $this->request->param('addon', ''); try { if (empty($addon)) { AddonPerformanceMonitor::clearPerformanceData(); return $this->result->success([], '已清除所有插件性能数据'); } else { AddonPerformanceMonitor::clearPerformanceData($addon); return $this->result->success([], "已清除插件 {$addon} 的性能数据"); } } catch (\Exception $e) { return $this->result->error('清除性能数据失败:' . $e->getMessage()); } } /** * 性能图表数据 */ public function chart() { $type = $this->request->param('type', 'execution_time'); $period = $this->request->param('period', 'day'); // day, week, month $overview = AddonPerformanceMonitor::getAllPerformanceOverview(); $chartData = []; foreach ($overview as $addon => $stats) { if ($stats['total_calls'] === 0) { continue; } switch ($type) { case 'execution_time': $chartData[] = [ 'name' => $addon, 'value' => round($stats['avg_execution_time'] * 1000, 2) ]; break; case 'memory_usage': $chartData[] = [ 'name' => $addon, 'value' => round($stats['avg_memory_usage'] / 1024, 2) ]; break; case 'success_rate': $chartData[] = [ 'name' => $addon, 'value' => round($stats['success_rate'], 2) ]; break; case 'call_count': $chartData[] = [ 'name' => $addon, 'value' => $stats['total_calls'] ]; break; } } // 按值排序 usort($chartData, function($a, $b) { return $b['value'] - $a['value']; }); // 只返回前10个 $chartData = array_slice($chartData, 0, 10); return $this->result->success([ 'chart_data' => $chartData, 'type' => $type, 'period' => $period ]); } }