diff --git a/app/Http/Controllers/Admin/Menu/SystemStatus/Children/GateAbilitiesMenuItemController.php b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/GateAbilitiesMenuItemController.php new file mode 100644 index 0000000..bd88be1 --- /dev/null +++ b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/GateAbilitiesMenuItemController.php @@ -0,0 +1,25 @@ +name = 'adminMenu.items.systemStatus.gateAbilities'; + + $this->slug = 'gates'; + + $this->iconClasses = 'nav-icon icon-wrench'; + } + + public function handle(Request $request) + { + $gates = Gate::abilities(); + return view('admin.menu.systemStatus.gates')->with(compact('gates')); + } +} diff --git a/app/Http/Controllers/Admin/Menu/SystemStatus/Children/RouteListMenuItemController.php b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/RouteListMenuItemController.php new file mode 100644 index 0000000..c0db2de --- /dev/null +++ b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/RouteListMenuItemController.php @@ -0,0 +1,39 @@ +name = 'adminMenu.items.systemStatus.routes'; + + $this->slug = 'routes'; + + $this->iconClasses = 'nav-icon icon-wrench'; + } + + public function handle(Request $request) + { + $routes = Route::getRoutes()->getRoutes(); + $routes = collect($routes)->map(function($route){ + /** @var \Illuminate\Routing\Route $route */ + $action = explode('@', $route->getActionName()); + return [ + 'methods' => $route->methods(), + 'uri' => $route->uri(), + 'name' => $route->getName(), + 'action' => [ + 'controller' => isset($action[0]) ? $action[0] : '', + 'method' => isset($action[1]) ? $action[1] : '', + ], + 'middlewares' => $route->middleware(), + ]; + })->all(); + return view('admin.menu.systemStatus.routes')->with(compact('routes')); + } +} diff --git a/app/Http/Controllers/Admin/Menu/SystemStatus/Children/SystemMenuItemController.php b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/SystemMenuItemController.php new file mode 100644 index 0000000..b5d2638 --- /dev/null +++ b/app/Http/Controllers/Admin/Menu/SystemStatus/Children/SystemMenuItemController.php @@ -0,0 +1,118 @@ +name = 'adminMenu.items.systemStatus.system'; + + $this->slug = 'system'; + + $this->iconClasses = 'nav-icon icon-wrench'; + } + + public function handle(Request $request) + { + $systemInfo = collect([ + [ + 'name' => 'OS', + 'value' => php_uname('s') . ' ' . php_uname('r'), + ], + [ + 'name' => 'OS Version', + 'value' => php_uname('v'), + ], + [ + 'name' => 'Server', + 'value' => $_SERVER['SERVER_SOFTWARE'] + ], + [ + 'name' => 'Timezone', + 'value' => date_default_timezone_get() + ], + [ + 'name' => 'PHP Version', + 'value' => phpversion() + ], + [ + 'name' => 'PHP Post Max Size', + 'value' => ini_get('post_max_size') + ], + [ + 'name' => 'PHP Upload Max Filesize', + 'value' => ini_get('upload_max_filesize') + ], + [ + 'name' => 'PHP Max Execution Time', + 'value' => ini_get('max_execution_time') + ], + [ + 'name' => 'PHP Max Input Vars', + 'value' => ini_get('max_input_vars') + ], + [ + 'name' => 'PHP Memory Limit', + 'value' => ini_get('memory_limit') + ], + [ + 'name' => 'PHP Xdebug Enabled', + 'value' => function_exists('xdebug_get_code_coverage') + ] + ]); + + $systemInfo->push([ + 'name' => 'DBMS', + 'value'=> DB::getDriverName(), + ])->push([ + 'name' => 'DB', + 'value'=> DB::getDatabaseName(), + ]); + + if(DB::getDriverName() == 'mysql') { + $query = DB::raw("SHOW VARIABLES LIKE 'version'"); + $version = Arr::first(DB::select($query)); + if($version) { + $systemInfo->push([ + 'name' => 'DB Version', + 'value' => $version->Value + ]); + } + } + + $systemInfo->push([ + 'name' => 'Cache', + 'value'=> Cache::getDefaultDriver(), + ])->push([ + 'name' => 'Cache Time', + 'value'=> Cache::getDefaultCacheTime(), + ]); + + + if(Cache::getDefaultDriver() == 'redis') { + $redisStatus = false; + + try { + $redisConfig = config('database.redis.default'); + $redis = Redis::connect($redisConfig['host'],$redisConfig['port']); + $redisStatus = true; + } catch(\Exception $e){ } + + $systemInfo->push([ + 'name' => 'Redis Connected', + 'value' => $redisStatus + ]); + } + + + return view('admin.menu.systemStatus.system', ['systemInfo' => $systemInfo->all()]); + } +} diff --git a/app/Http/Controllers/Admin/Menu/SystemStatus/SystemStatusMenuItemController.php b/app/Http/Controllers/Admin/Menu/SystemStatus/SystemStatusMenuItemController.php new file mode 100644 index 0000000..569921e --- /dev/null +++ b/app/Http/Controllers/Admin/Menu/SystemStatus/SystemStatusMenuItemController.php @@ -0,0 +1,20 @@ +name = 'adminMenu.items.systemStatus.systemStatus'; + + $this->slug = 'system-status'; + + $this->permissions = ['admin manage system status']; + + $this->iconClasses = 'nav-icon icon-wrench'; + } +} diff --git a/app/Services/AppJsObjectService.php b/app/Services/AppJsObjectService.php new file mode 100644 index 0000000..60f06fa --- /dev/null +++ b/app/Services/AppJsObjectService.php @@ -0,0 +1,49 @@ + app()->getLocale(), + 'csrfToken' => csrf_token(), + 'user' => null, + 'options' => [ + 'googleApiKey' => $option->google_api_key, + 'fbAppId' => $option->fb_app_id, + ], + 'translations' => [ + + ], + 'methods' => new \stdClass, + 'utils' => new \stdClass + ]; + if(Auth::check()) { + $user = Auth::user(); + $obj['user'] = [ + 'id' => $user->id, + 'apiToken' => $user->api_token + ]; + } + + if($siteState->isAdminArea) { + $obj['admin']['translations'] = [ + 'dataTables' => trans('datatables'), + ]; + } + return $obj; + } +} diff --git a/config/admin.php b/config/admin.php index 187e4b4..af3b5bd 100644 --- a/config/admin.php +++ b/config/admin.php @@ -17,6 +17,15 @@ return [ Menu\Options\Children\DevelopmentMenuItemController::class, ] ], + [ + 'type' => 'item', + 'controller' => Menu\SystemStatus\SystemStatusMenuItemController::class, + 'children' => [ + Menu\SystemStatus\Children\SystemMenuItemController::class, + Menu\SystemStatus\Children\RouteListMenuItemController::class, + Menu\SystemStatus\Children\GateAbilitiesMenuItemController::class, + ] + ], ], // 設定的項目 'options' => [ diff --git a/config/data-presets.php b/config/data-presets.php index 86f3c35..ffd2feb 100644 --- a/config/data-presets.php +++ b/config/data-presets.php @@ -37,6 +37,12 @@ return [ 'displayName' => 'adminManageOptionsDevelopment', 'assignTo' => [] ], + [ + //管理系統狀態 + 'name' => 'admin manage system status', + 'displayName' => 'adminManageSystemStatus', + 'assignTo' => [] + ], ], // 預設的設定值 'options' => [ diff --git a/config/languages.php b/config/languages.php index 7707530..63ec4ff 100644 --- a/config/languages.php +++ b/config/languages.php @@ -2,7 +2,5 @@ return [ 'en' => 'English', 'zh-tw' => '繁體中文', - 'zh-cn' => '简体中文', - 'ja' => '日本語', 'ko' => '한국어' ]; diff --git a/resources/js/admin/lib.js b/resources/js/admin/lib.js index 25c35b9..3fd3a45 100644 --- a/resources/js/admin/lib.js +++ b/resources/js/admin/lib.js @@ -21,6 +21,8 @@ import 'perfect-scrollbar'; import '@coreui/coreui'; import 'chart.js'; import '@coreui/coreui-plugin-chartjs-custom-tooltips'; +import 'datatables.net-bs4'; +import 'datatables.net-responsive-bs4'; try { diff --git a/resources/js/admin/page/system-status.js b/resources/js/admin/page/system-status.js new file mode 100644 index 0000000..2744955 --- /dev/null +++ b/resources/js/admin/page/system-status.js @@ -0,0 +1,13 @@ +$(function(){ + //路由表表格套用datatable + app.utils.dataTable('.table.routes', { + paginate: false, + responsive: true, + }); + + //Gate Ability表格套用datatable + app.utils.dataTable('.table.gate-abilities', { + paginate: false, + responsive: true, + }); +}); diff --git a/resources/js/app-common.js b/resources/js/app-common.js index a877e83..0245804 100644 --- a/resources/js/app-common.js +++ b/resources/js/app-common.js @@ -1,4 +1,14 @@ +import {dataTable} from "./utils/datatable"; + + $('.logout-btn').on('click', e => { e.preventDefault() $('#logout-form').submit() }) + +/** + * 第三方工具 + */ +app.utils = { + dataTable: dataTable, +} diff --git a/resources/js/utils/datatable.js b/resources/js/utils/datatable.js new file mode 100644 index 0000000..9a123b2 --- /dev/null +++ b/resources/js/utils/datatable.js @@ -0,0 +1,5 @@ +export const dataTable = function(ele, options = {}){ + return $(ele).dataTable(Object.assign({}, { + language: app.admin.translations.dataTables + }, options)); +}; diff --git a/resources/lang/en/adminMenu.php b/resources/lang/en/adminMenu.php index f948090..ceedf30 100644 --- a/resources/lang/en/adminMenu.php +++ b/resources/lang/en/adminMenu.php @@ -7,5 +7,11 @@ return array( 'development' => 'Development', 'platform' => 'Platform', ], + 'systemStatus' => [ + 'systemStatus' => 'System Status', + 'routes' => 'Route List', + 'system' => 'System', + 'gateAbilities' => 'Gate Abilities', + ] ], ); diff --git a/resources/lang/en/datatables.php b/resources/lang/en/datatables.php new file mode 100644 index 0000000..0136ba4 --- /dev/null +++ b/resources/lang/en/datatables.php @@ -0,0 +1,26 @@ + 'Processing...', + 'search' => 'Search:', + 'lengthMenu' => 'Display _MENU_ items', + 'info' => 'Showing _START_ to _END_ on _TOTAL_ items', + 'infoEmpty' => 'Showing empty items', + 'infoFiltered' => '(filter of _MAX_ total items)', + 'infoPostFix' => '', + 'loadingRecords' => 'Loading...', + 'zeroRecords' => 'No item to display', + 'emptyTable' => 'Table is empty', + 'paginate' => + array ( + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + ), + 'aria' => + array ( + 'sortAscending' => ': activate to sort the column in ascending order', + 'sortDescending' => ': activate to sort the column in descending order', + ), +); diff --git a/resources/lang/zh-tw/datatables.php b/resources/lang/zh-tw/datatables.php new file mode 100644 index 0000000..70321ab --- /dev/null +++ b/resources/lang/zh-tw/datatables.php @@ -0,0 +1,26 @@ + '處理中...', + 'search' => '查詢:', + 'lengthMenu' => '顯示 _MENU_ 筆資料', + 'info' => '顯示第 _START_ 至 _END_ 筆資料,共 _TOTAL_ 筆', + 'infoEmpty' => '顯示 0 筆資料', + 'infoFiltered' => '(從 _MAX_ 筆資料中過濾)', + 'infoPostFix' => '', + 'loadingRecords' => '載入中...', + 'zeroRecords' => '查無資料', + 'emptyTable' => '無資料', + 'paginate' => + array ( + 'first' => '第一頁', + 'previous' => '上一頁', + 'next' => '下一頁', + 'last' => '最後一頁', + ), + 'aria' => + array ( + 'sortAscending' => ': 將資料以正序排序', + 'sortDescending' => ': 將資料以倒序排序', + ), +); diff --git a/resources/sass/admin/page/system-status.scss b/resources/sass/admin/page/system-status.scss new file mode 100644 index 0000000..1c44ba1 --- /dev/null +++ b/resources/sass/admin/page/system-status.scss @@ -0,0 +1,50 @@ +//Boostrap函式庫 +@import "../bootstrap"; + +body.system-status { + &.routes { + table.routes { + font-size: 1.1em; + @include media-breakpoint-down(lg) { + font-size: 1em; + } + @include media-breakpoint-down(md) { + font-size: .9em; + } + &.collapsed { + .dtr-data { + word-break: break-all; + .badge { + white-space: unset; + } + } + } + td { + &.uri { + * { + color: #baffc6; + } + } + &.action { + word-break: break-all; + } + &.middleware { + .badge { + margin-right: 2px; + font-size: .9em; + } + } + } + } + } + &.system { + table.system { + font-size: 1.1em; + } + } + &.gates { + table { + font-size: 1.2em; + } + } +} diff --git a/resources/views/admin/layouts/app.blade.php b/resources/views/admin/layouts/app.blade.php index 8a8949e..170c0a1 100644 --- a/resources/views/admin/layouts/app.blade.php +++ b/resources/views/admin/layouts/app.blade.php @@ -7,6 +7,9 @@ + @section('admin-app-head-scripts') + @include('components.head.appJsObject') + @show @stack('admin-app-head-scripts') @section('admin-app-styles') diff --git a/resources/views/admin/menu/systemStatus/gates.blade.php b/resources/views/admin/menu/systemStatus/gates.blade.php new file mode 100644 index 0000000..da78775 --- /dev/null +++ b/resources/views/admin/menu/systemStatus/gates.blade.php @@ -0,0 +1,36 @@ +@extends('admin.layouts.app') + +@section('title', 'Gate Abilities') + +@push('admin-app-scripts') + +@endpush + +@push('admin-app-styles') + +@endpush + +@section('admin-page-content') +
+
+

Gate Abilities

+
+
+
+
+ + + + + + @foreach($gates as $ability => $gate) + + + + @endforeach + +
Ability
{{ $ability }}
+ +
+
+@endsection diff --git a/resources/views/admin/menu/systemStatus/routes.blade.php b/resources/views/admin/menu/systemStatus/routes.blade.php new file mode 100644 index 0000000..3ac626f --- /dev/null +++ b/resources/views/admin/menu/systemStatus/routes.blade.php @@ -0,0 +1,85 @@ +@extends('admin.layouts.app') + +@section('title', 'Route List') + +@push('admin-app-scripts') + +@endpush + +@push('admin-app-styles') + +@endpush + +@section('admin-page-content') +
+
+

Route List

+
+
+
+
+ + + + + + + + + + + + @foreach($routes as $route) + + + + + + + + @endforeach + +
MethodURINameActionMiddleware
+ {!! + collect($route['methods']) + ->map(function($method){ + $badgeType = ''; + switch(strtolower($method)) { + case 'get': + $badgeType = 'success'; + break; + case 'post': + $badgeType = 'primary'; + break; + case 'put': + case 'patch': + $badgeType = 'warning'; + break; + case 'delete': + $badgeType = 'danger'; + break; + } + return app('Html')->bs()->badge($method, $badgeType); + }) + ->join('
') + !!} +
+ @if(in_array('GET', $route['methods'])) + {{ $route['uri'] }} + @else + {{ $route['uri'] }} + @endif + {{ $route['name'] }} + {{ $route['action']['controller'] }}@{{ $route['action']['method'] }} + + {!! + collect($route['middlewares']) + ->map(function($name){ + return app('Html')->bs()->badge($name, 'secondary'); + }) + ->join('') + !!} +
+
+
+@endsection diff --git a/resources/views/admin/menu/systemStatus/system.blade.php b/resources/views/admin/menu/systemStatus/system.blade.php new file mode 100644 index 0000000..1bb92b1 --- /dev/null +++ b/resources/views/admin/menu/systemStatus/system.blade.php @@ -0,0 +1,33 @@ +@extends('admin.layouts.app') + +@section('title', 'System Status') + +@push('admin-app-scripts') + +@endpush + +@push('admin-app-styles') + +@endpush + +@section('admin-page-content') +
+
+

System Status

+
+
+
+
+ + + @foreach($systemInfo as $info) + + + + + @endforeach + +
{{ $info['name'] }}{{ $info['value'] }}
+
+
+@endsection diff --git a/resources/views/components/head/appJsObject.blade.php b/resources/views/components/head/appJsObject.blade.php new file mode 100644 index 0000000..d2a3d8a --- /dev/null +++ b/resources/views/components/head/appJsObject.blade.php @@ -0,0 +1,4 @@ +@inject('js', App\Services\AppJsObjectService) + diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 50dfc49..c0d30f3 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -12,6 +12,9 @@ @endif @yield('head-meta') + @section('app-head-scripts') + @include('components.head.appJsObject') + @show @stack('app-head-scripts') @section('app-styles') diff --git a/webpack.mix.js b/webpack.mix.js index abd5d0a..d8eee85 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -21,6 +21,8 @@ mix.js('resources/js/app.js', publicJsDir) mix.sass('resources/sass/app.scss', publicCssDir); mix.js('resources/js/admin/app.js', publicAdminJsDir) + .js('resources/js/admin/page/system-status.js', publicAdminJsDir + '/page') mix.sass('resources/sass/admin/lib.scss', publicAdminCssDir) .sass('resources/sass/admin/app.scss', publicAdminCssDir) + .sass('resources/sass/admin/page/system-status.scss', publicAdminCssDir + '/page')