| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- <?php
- namespace App\Module\OpenAPI\AdminControllers;
- use App\Module\OpenAPI\Models\OpenApiStats;
- use App\Module\OpenAPI\Models\OpenApiApp;
- use App\Module\OpenAPI\Models\OpenApiLog;
- use App\Module\OpenAPI\Repositorys\OpenApiStatRepository;
- use App\Module\Admin\AdminControllers\Helper\GridHelper;
- use Dcat\Admin\Grid;
- use Dcat\Admin\Show;
- use Dcat\Admin\Layout\Content;
- use Illuminate\Http\Request;
- use Spatie\RouteAttributes\Attributes\Resource;
- use UCore\DcatAdmin\AdminController;
- /**
- * OpenAPI统计分析控制器
- *
- * 用于后台管理OpenAPI统计数据
- */
- #[Resource(
- resource: 'openapi-stats',
- names: [
- 'index' => 'admin.openapi.stats.index',
- 'show' => 'admin.openapi.stats.show',
- ]
- )]
- class StatController extends AdminController
- {
- protected OpenApiStatRepository $repository;
- public function __construct(OpenApiStatRepository $repository)
- {
- $this->repository = $repository;
- }
- /**
- * 统计概览页面
- *
- * @param Content $content
- * @return Content
- */
- public function index(Content $content): Content
- {
- return $content
- ->title('OpenAPI统计分析')
- ->description('API调用统计和分析')
- ->body($this->grid());
- }
- /**
- * 统计详情页面
- *
- * @param mixed $id
- * @param Content $content
- * @return Content
- */
- public function show($id, Content $content): Content
- {
- return $content
- ->title('统计详情')
- ->description('查看详细统计信息')
- ->body($this->detail($id));
- }
- /**
- * 构建数据表格
- *
- * @return Grid
- */
- protected function grid(): Grid
- {
- return Grid::make($this->repository->query()->with('app'), function (Grid $grid) {
- $grid->column('id', 'ID')->sortable();
-
- $grid->column('app.name', '应用名称')->display(function ($name) {
- return $name ?: '未知应用';
- });
-
- $grid->column('app_id', '应用ID');
-
- $grid->column('date', '统计日期')->display(function ($date) {
- return $date ? $date->format('Y-m-d') : '';
- });
-
- $grid->column('hour', '统计小时')->display(function ($hour) {
- return $hour !== null ? sprintf('%02d:00', $hour) : '全天';
- });
-
- $grid->column('endpoint', '接口端点')->limit(30);
-
- $grid->column('request_count', '请求次数')->sortable()->totalRow();
-
- $grid->column('success_count', '成功次数')->sortable()->totalRow();
-
- $grid->column('error_count', '错误次数')->sortable()->totalRow();
-
- $grid->column('success_rate', '成功率')->display(function () {
- return $this->success_rate . '%';
- })->label('success');
-
- $grid->column('avg_response_time', '平均响应时间')->display(function ($time) {
- return $this->formatted_avg_response_time;
- });
-
- $grid->column('rate_limit_hits', '限流次数')->sortable()->totalRow();
-
- $grid->column('unique_ips', '唯一IP数')->sortable();
- // 筛选器
- $grid->filter(function (Grid\Filter $filter) {
- $filter->equal('app_id', '应用ID')->select(
- OpenApiApp::pluck('name', 'app_id')
- );
-
- $filter->between('date', '统计日期')->date();
-
- $filter->equal('hour', '统计小时')->select(
- array_combine(range(0, 23), array_map(function($h) {
- return sprintf('%02d:00', $h);
- }, range(0, 23)))
- );
-
- $filter->like('endpoint', '接口端点');
-
- $filter->between('request_count', '请求次数');
-
- $filter->scope('today', '今日')->where('date', now()->toDateString());
- $filter->scope('yesterday', '昨日')->where('date', now()->subDay()->toDateString());
- $filter->scope('this_week', '本周')->whereBetween('date', [
- now()->startOfWeek()->toDateString(),
- now()->endOfWeek()->toDateString()
- ]);
- $filter->scope('this_month', '本月')->whereBetween('date', [
- now()->startOfMonth()->toDateString(),
- now()->endOfMonth()->toDateString()
- ]);
- });
- // 工具栏
- $grid->tools(function (Grid\Tools $tools) {
- $tools->append('<a href="' . admin_route('admin.openapi.stats.dashboard') . '" class="btn btn-primary">
- <i class="fa fa-dashboard"></i> 统计仪表板
- </a>');
- });
- // 排序
- $grid->model()->orderBy('date', 'desc')->orderBy('hour', 'desc');
- // 禁用操作
- $grid->disableCreateButton();
- $grid->disableEditButton();
- $grid->disableDeleteButton();
- $grid->disableBatchActions();
- // 行操作
- $grid->actions(function (Grid\Displayers\Actions $actions) {
- $actions->disableEdit();
- $actions->disableDelete();
- });
- });
- }
- /**
- * 构建详情页面
- *
- * @param mixed $id
- * @return Show
- */
- protected function detail($id): Show
- {
- return Show::make($id, $this->repository->query()->with('app'), function (Show $show) {
- $show->field('id', 'ID');
-
- $show->field('app.name', '应用名称');
- $show->field('app_id', '应用ID');
-
- $show->field('date', '统计日期');
- $show->field('hour', '统计小时')->as(function ($hour) {
- return $hour !== null ? sprintf('%02d:00', $hour) : '全天';
- });
-
- $show->field('endpoint', '接口端点');
-
- $show->divider('请求统计');
- $show->field('request_count', '总请求次数');
- $show->field('success_count', '成功次数');
- $show->field('error_count', '错误次数');
- $show->field('success_rate', '成功率')->as(function () {
- return $this->success_rate . '%';
- })->label('success');
-
- $show->divider('响应时间统计');
- $show->field('avg_response_time', '平均响应时间')->as(function () {
- return $this->formatted_avg_response_time;
- });
- $show->field('max_response_time', '最大响应时间')->as(function ($time) {
- return $time < 1000 ? round($time, 2) . 'ms' : round($time / 1000, 2) . 's';
- });
- $show->field('min_response_time', '最小响应时间')->as(function ($time) {
- return $time < 1000 ? round($time, 2) . 'ms' : round($time / 1000, 2) . 's';
- });
-
- $show->divider('其他统计');
- $show->field('rate_limit_hits', '限流命中次数');
- $show->field('unique_ips', '唯一IP数量');
-
- $show->field('error_details', '错误详情')->json();
-
- $show->field('created_at', '创建时间');
- $show->field('updated_at', '更新时间');
- // 禁用操作
- $show->disableEditButton();
- $show->disableDeleteButton();
- });
- }
- /**
- * 统计仪表板
- *
- * @param Content $content
- * @return Content
- */
- public function dashboard(Content $content): Content
- {
- return $content
- ->title('OpenAPI统计仪表板')
- ->description('API调用统计概览')
- ->row(function ($row) {
- // 今日统计卡片
- $row->column(3, $this->todayStatsCard());
- $row->column(3, $this->yesterdayStatsCard());
- $row->column(3, $this->weekStatsCard());
- $row->column(3, $this->monthStatsCard());
- })
- ->row(function ($row) {
- // 趋势图表
- $row->column(6, $this->requestTrendChart());
- $row->column(6, $this->errorRateChart());
- })
- ->row(function ($row) {
- // 热门接口和应用
- $row->column(6, $this->topEndpointsCard());
- $row->column(6, $this->topAppsCard());
- });
- }
- /**
- * 今日统计卡片
- *
- * @return string
- */
- protected function todayStatsCard(): string
- {
- $stats = OpenApiStats::today()->selectRaw('
- SUM(request_count) as total_requests,
- SUM(success_count) as total_success,
- SUM(error_count) as total_errors,
- AVG(avg_response_time) as avg_time
- ')->first();
- $successRate = $stats->total_requests > 0
- ? round(($stats->total_success / $stats->total_requests) * 100, 2)
- : 0;
- return view('admin::widgets.info-box', [
- 'style' => 'info',
- 'title' => '今日统计',
- 'number' => number_format($stats->total_requests ?? 0),
- 'description' => "成功率: {$successRate}%",
- 'icon' => 'fa-calendar-day',
- ])->render();
- }
- /**
- * 昨日统计卡片
- *
- * @return string
- */
- protected function yesterdayStatsCard(): string
- {
- $stats = OpenApiStats::yesterday()->selectRaw('
- SUM(request_count) as total_requests,
- SUM(success_count) as total_success,
- SUM(error_count) as total_errors
- ')->first();
- $successRate = $stats->total_requests > 0
- ? round(($stats->total_success / $stats->total_requests) * 100, 2)
- : 0;
- return view('admin::widgets.info-box', [
- 'style' => 'warning',
- 'title' => '昨日统计',
- 'number' => number_format($stats->total_requests ?? 0),
- 'description' => "成功率: {$successRate}%",
- 'icon' => 'fa-calendar-minus',
- ])->render();
- }
- /**
- * 本周统计卡片
- *
- * @return string
- */
- protected function weekStatsCard(): string
- {
- $stats = OpenApiStats::thisWeek()->selectRaw('
- SUM(request_count) as total_requests,
- SUM(success_count) as total_success,
- SUM(error_count) as total_errors
- ')->first();
- $successRate = $stats->total_requests > 0
- ? round(($stats->total_success / $stats->total_requests) * 100, 2)
- : 0;
- return view('admin::widgets.info-box', [
- 'style' => 'success',
- 'title' => '本周统计',
- 'number' => number_format($stats->total_requests ?? 0),
- 'description' => "成功率: {$successRate}%",
- 'icon' => 'fa-calendar-week',
- ])->render();
- }
- /**
- * 本月统计卡片
- *
- * @return string
- */
- protected function monthStatsCard(): string
- {
- $stats = OpenApiStats::thisMonth()->selectRaw('
- SUM(request_count) as total_requests,
- SUM(success_count) as total_success,
- SUM(error_count) as total_errors
- ')->first();
- $successRate = $stats->total_requests > 0
- ? round(($stats->total_success / $stats->total_requests) * 100, 2)
- : 0;
- return view('admin::widgets.info-box', [
- 'style' => 'primary',
- 'title' => '本月统计',
- 'number' => number_format($stats->total_requests ?? 0),
- 'description' => "成功率: {$successRate}%",
- 'icon' => 'fa-calendar-alt',
- ])->render();
- }
- /**
- * 请求趋势图表
- *
- * @return string
- */
- protected function requestTrendChart(): string
- {
- // 获取最近7天的数据
- $data = OpenApiStats::whereBetween('date', [
- now()->subDays(6)->toDateString(),
- now()->toDateString()
- ])->selectRaw('
- date,
- SUM(request_count) as total_requests,
- SUM(success_count) as total_success,
- SUM(error_count) as total_errors
- ')->groupBy('date')->orderBy('date')->get();
- return view('admin::widgets.chart', [
- 'title' => '请求趋势(最近7天)',
- 'type' => 'line',
- 'data' => $data,
- ])->render();
- }
- /**
- * 错误率图表
- *
- * @return string
- */
- protected function errorRateChart(): string
- {
- // 获取最近7天的错误率数据
- $data = OpenApiStats::whereBetween('date', [
- now()->subDays(6)->toDateString(),
- now()->toDateString()
- ])->selectRaw('
- date,
- SUM(request_count) as total_requests,
- SUM(error_count) as total_errors
- ')->groupBy('date')->orderBy('date')->get()->map(function ($item) {
- $item->error_rate = $item->total_requests > 0
- ? round(($item->total_errors / $item->total_requests) * 100, 2)
- : 0;
- return $item;
- });
- return view('admin::widgets.chart', [
- 'title' => '错误率趋势(最近7天)',
- 'type' => 'bar',
- 'data' => $data,
- ])->render();
- }
- /**
- * 热门接口卡片
- *
- * @return string
- */
- protected function topEndpointsCard(): string
- {
- $endpoints = OpenApiStats::today()->selectRaw('
- endpoint,
- SUM(request_count) as total_requests
- ')->groupBy('endpoint')
- ->orderBy('total_requests', 'desc')
- ->limit(10)
- ->get();
- return view('admin::widgets.table', [
- 'title' => '今日热门接口',
- 'headers' => ['接口', '请求次数'],
- 'data' => $endpoints->map(function ($item) {
- return [$item->endpoint, number_format($item->total_requests)];
- }),
- ])->render();
- }
- /**
- * 热门应用卡片
- *
- * @return string
- */
- protected function topAppsCard(): string
- {
- $apps = OpenApiStats::today()
- ->join('openapi_apps', 'openapi_stats.app_id', '=', 'openapi_apps.app_id')
- ->selectRaw('
- openapi_apps.name,
- SUM(openapi_stats.request_count) as total_requests
- ')->groupBy('openapi_apps.name')
- ->orderBy('total_requests', 'desc')
- ->limit(10)
- ->get();
- return view('admin::widgets.table', [
- 'title' => '今日热门应用',
- 'headers' => ['应用名称', '请求次数'],
- 'data' => $apps->map(function ($item) {
- return [$item->name, number_format($item->total_requests)];
- }),
- ])->render();
- }
- }
|