ThirdPartyLogController.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. namespace App\Module\ThirdParty\AdminControllers;
  3. use UCore\DcatAdmin\AdminController;
  4. use App\Module\ThirdParty\Models\ThirdPartyLog;
  5. use App\Module\ThirdParty\Models\ThirdPartyService;
  6. use App\Module\ThirdParty\Repositorys\ThirdPartyLogRepository;
  7. use App\Module\ThirdParty\Enums\LOG_LEVEL;
  8. use Dcat\Admin\Grid;
  9. use Dcat\Admin\Show;
  10. use Spatie\RouteAttributes\Attributes\Resource;
  11. /**
  12. * 第三方服务调用日志管理控制器
  13. *
  14. * 路由: /admin/thirdparty/logs
  15. */
  16. #[Resource('thirdparty/logs', names: 'dcat.admin.thirdparty.logs')]
  17. class ThirdPartyLogController extends AdminController
  18. {
  19. /**
  20. * 页面标题
  21. *
  22. * @var string
  23. */
  24. protected $title = '调用日志管理';
  25. /**
  26. * 数据仓库
  27. *
  28. * @return string
  29. */
  30. protected function repository()
  31. {
  32. return ThirdPartyLogRepository::class;
  33. }
  34. /**
  35. * 列表页面
  36. *
  37. * @return Grid
  38. */
  39. protected function grid(): Grid
  40. {
  41. return Grid::make(new ThirdPartyLogRepository(), function (Grid $grid) {
  42. // 基础设置
  43. $grid->column('id', 'ID')->sortable();
  44. // 关联服务
  45. $grid->column('service.name', '服务名称')->sortable();
  46. $grid->column('service.code', '服务代码');
  47. $grid->column('request_id', '请求ID')->copyable();
  48. // HTTP方法
  49. $grid->column('method', '方法')->display(function ($method) {
  50. $colors = [
  51. 'GET' => 'success',
  52. 'POST' => 'primary',
  53. 'PUT' => 'warning',
  54. 'DELETE' => 'danger',
  55. 'PATCH' => 'info',
  56. ];
  57. $color = $colors[$method] ?? 'secondary';
  58. return "<span class='badge badge-{$color}'>{$method}</span>";
  59. });
  60. // URL(截断显示)
  61. $grid->column('url', 'URL')->display(function ($url) {
  62. $shortUrl = strlen($url) > 50 ? substr($url, 0, 50) . '...' : $url;
  63. return "<span title='{$url}'>{$shortUrl}</span>";
  64. });
  65. // 响应状态码
  66. $grid->column('response_status', '状态码')->display(function ($status) {
  67. if (!$status) {
  68. return '<span class="badge badge-secondary">-</span>';
  69. }
  70. $color = 'secondary';
  71. if ($status >= 200 && $status < 300) {
  72. $color = 'success';
  73. } elseif ($status >= 300 && $status < 400) {
  74. $color = 'info';
  75. } elseif ($status >= 400 && $status < 500) {
  76. $color = 'warning';
  77. } elseif ($status >= 500) {
  78. $color = 'danger';
  79. }
  80. return "<span class='badge badge-{$color}'>{$status}</span>";
  81. });
  82. // 响应时间
  83. $grid->column('response_time', '响应时间')->display(function ($time) {
  84. if (!$time) {
  85. return '-';
  86. }
  87. $color = 'success';
  88. if ($time > 5000) {
  89. $color = 'danger';
  90. } elseif ($time > 2000) {
  91. $color = 'warning';
  92. } elseif ($time > 1000) {
  93. $color = 'info';
  94. }
  95. return "<span class='badge badge-{$color}'>{$time}ms</span>";
  96. })->sortable();
  97. // 日志级别
  98. $grid->column('level', '级别')->display(function ($level) {
  99. $logLevel = LOG_LEVEL::tryFrom($level);
  100. if ($logLevel) {
  101. $color = $logLevel->getColor();
  102. $icon = $logLevel->getIcon();
  103. $label = $logLevel->getLabel();
  104. return "<span class='badge badge-{$color}'><i class='{$icon}'></i> {$label}</span>";
  105. }
  106. return $level;
  107. });
  108. // 错误信息(截断显示)
  109. $grid->column('error_message', '错误信息')->display(function ($error) {
  110. if (!$error) {
  111. return '-';
  112. }
  113. $shortError = strlen($error) > 30 ? substr($error, 0, 30) . '...' : $error;
  114. return "<span class='text-danger' title='{$error}'>{$shortError}</span>";
  115. });
  116. // 用户信息
  117. $grid->column('user_id', '用户ID');
  118. $grid->column('ip_address', 'IP地址');
  119. // 创建时间
  120. $grid->column('created_at', '调用时间')->sortable();
  121. // 过滤器
  122. $grid->filter(function (Grid\Filter $filter) {
  123. $filter->equal('service_id', '服务')->select(
  124. ThirdPartyService::pluck('name', 'id')->toArray()
  125. );
  126. $filter->equal('method', 'HTTP方法')->select([
  127. 'GET' => 'GET',
  128. 'POST' => 'POST',
  129. 'PUT' => 'PUT',
  130. 'DELETE' => 'DELETE',
  131. 'PATCH' => 'PATCH',
  132. ]);
  133. $filter->equal('level', '日志级别')->select(LOG_LEVEL::getOptions());
  134. $filter->between('response_status', '状态码');
  135. $filter->between('response_time', '响应时间(ms)');
  136. $filter->like('request_id', '请求ID');
  137. $filter->like('url', 'URL');
  138. $filter->like('error_message', '错误信息');
  139. $filter->equal('user_id', '用户ID');
  140. $filter->like('ip_address', 'IP地址');
  141. $filter->between('created_at', '调用时间')->datetime();
  142. });
  143. // 批量操作
  144. $grid->batchActions(function (Grid\Tools\BatchActions $batch) {
  145. // TODO: 创建批量操作类
  146. // $batch->add('批量删除', new \App\Module\ThirdParty\AdminActions\BatchDeleteLogAction());
  147. });
  148. // 工具栏
  149. $grid->tools(function (Grid\Tools $tools) {
  150. $tools->append('<a href="/admin/thirdparty/logs/stats" class="btn btn-sm btn-info"><i class="fa fa-chart-bar"></i> 统计分析</a>');
  151. $tools->append('<a href="/admin/thirdparty/logs/export" class="btn btn-sm btn-success"><i class="fa fa-download"></i> 导出日志</a>');
  152. $tools->append('<a href="/admin/thirdparty/logs/cleanup" class="btn btn-sm btn-warning"><i class="fa fa-trash"></i> 清理日志</a>');
  153. });
  154. // 行操作
  155. $grid->actions(function (Grid\Displayers\Actions $actions) {
  156. // 移除编辑按钮,日志只读
  157. $actions->disableEdit();
  158. if ($actions->row->error_message) {
  159. $actions->append('<a href="/admin/thirdparty/logs/' . $actions->getKey() . '/retry" class="btn btn-xs btn-warning"><i class="fa fa-redo"></i> 重试</a>');
  160. }
  161. });
  162. // 默认排序(最新的在前)
  163. $grid->model()->orderBy('created_at', 'desc');
  164. // 禁用创建按钮
  165. $grid->disableCreateButton();
  166. });
  167. }
  168. /**
  169. * 详情页面
  170. *
  171. * @return Show
  172. */
  173. protected function detail($id): Show
  174. {
  175. return Show::make($id, new ThirdPartyLogRepository(), function (Show $show) {
  176. $show->field('id', 'ID');
  177. $show->field('service.name', '服务名称');
  178. $show->field('service.code', '服务代码');
  179. $show->field('credential.name', '使用凭证');
  180. $show->field('request_id', '请求ID');
  181. $show->field('method', 'HTTP方法');
  182. $show->field('url', '请求URL');
  183. $show->field('headers', '请求头')->json();
  184. $show->field('params', '请求参数')->json();
  185. $show->field('body', '请求体')->code();
  186. $show->field('response_status', '响应状态码');
  187. $show->field('response_headers', '响应头')->json();
  188. $show->field('response_body', '响应体')->code();
  189. $show->field('response_time', '响应时间')->as(function ($time) {
  190. return $time ? $time . ' ms' : '-';
  191. });
  192. $show->field('level', '日志级别')->as(function ($level) {
  193. $logLevel = LOG_LEVEL::tryFrom($level);
  194. return $logLevel ? $logLevel->getLabel() : $level;
  195. });
  196. $show->field('error_message', '错误信息');
  197. $show->field('user_id', '用户ID');
  198. $show->field('ip_address', 'IP地址');
  199. $show->field('user_agent', 'User Agent');
  200. $show->field('created_at', '调用时间');
  201. // 相关日志
  202. $show->relation('relatedLogs', '相关日志', function ($model) {
  203. $grid = new Grid(new ThirdPartyLog());
  204. $grid->model()->where('service_id', $model->service_id)
  205. ->where('id', '!=', $model->id)
  206. ->orderBy('created_at', 'desc')
  207. ->limit(10);
  208. $grid->column('request_id', '请求ID');
  209. $grid->column('method', '方法');
  210. $grid->column('response_status', '状态码');
  211. $grid->column('response_time', '响应时间(ms)');
  212. $grid->column('level', '级别');
  213. $grid->column('created_at', '时间');
  214. $grid->disableCreateButton();
  215. $grid->disableActions();
  216. $grid->disableFilter();
  217. $grid->disableBatchActions();
  218. return $grid;
  219. });
  220. });
  221. }
  222. }