Files
ProxyPanel/resources/views/admin/node/index.blade.php
2024-07-20 08:03:16 +08:00

416 lines
25 KiB
PHP

@extends('admin.table_layouts')
@push('css')
<style>
#swal2-content {
display: grid !important;
}
.table a {
text-decoration: none;
}
</style>
@endpush
@section('content')
<div class="page-content container-fluid">
<div class="panel">
<div class="panel-heading">
<h3 class="panel-title">{{ trans('admin.menu.node.list') }}</h3>
@canany(['admin.node.geo', 'admin.node.create'])
<div class="panel-actions btn-group">
@can('admin.node.reload')
@if ($nodeList->where('type', 4)->count())
<button class="btn btn-info" type="button" onclick="reload(0)">
<i class="icon wb-reload" id="reload_0" aria-hidden="true"></i> {{ trans('admin.node.reload_all') }}
</button>
@endif
@endcan
@can('admin.node.geo')
<button class="btn btn-outline-default" type="button" onclick="refreshGeo(0)">
<i class="icon wb-map" id="geo_0" aria-hidden="true"></i> {{ trans('admin.node.refresh_geo_all') }}
</button>
@endcan
@can('admin.node.create')
<a class="btn btn-primary" href="{{ route('admin.node.create') }}">
<i class="icon wb-plus"></i> {{ trans('common.add') }}
</a>
@endcan
</div>
@endcan
</div>
<div class="panel-body">
<table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
<thead class="thead-default">
<tr>
<th> ID</th>
<th> {{ trans('model.common.type') }}</th>
<th> {{ trans('model.node.name') }}</th>
<th> {{ trans('model.node.domain') }}</th>
<th> IP</th>
<th> {{ trans('model.node.static') }}</th>
<th> {{ trans('model.node.online_user') }}</th>
<th> {{ trans('model.node.data_consume') }}</th>
<th> {{ trans('model.node.data_rate') }}</th>
<th> {{ trans('model.common.extend') }}</th>
<th> {{ trans('common.status.attribute') }}</th>
<th> {{ trans('common.action') }}</th>
</tr>
</thead>
<tbody>
@foreach ($nodeList as $node)
<tr>
<td> {{ $node->id }} </td>
<td> {{ $node->type_label }} </td>
<td> {{ $node->name }} </td>
<td> {{ $node->server }} </td>
<td> {{ $node->is_ddns ? trans('model.node.ddns') : $node->ip }} </td>
<td> {{ $node->uptime ?: '-' }} </td>
<td> {{ $node->online_users ?: '-' }} </td>
<td> {{ $node->transfer }} </td>
<td> {{ $node->traffic_rate }} </td>
<td>
@isset($node->profile['passwd'])
{{-- 单端口 --}}
<span class="badge badge-lg badge-info"><i class="fa-solid fa-1" aria-hidden="true"></i></span>
@endisset
@if ($node->is_display === 0)
{{-- 节点完全不可见 --}}
<span class="badge badge-lg badge-danger"><i class="icon wb-eye-close" aria-hidden="true"></i></span>
@elseif($node->is_display === 1)
{{-- 节点只在页面中显示 --}}
<span class="badge badge-lg badge-danger"><i class="fa-solid fa-link-slash" aria-hidden="true"></i></span>
@elseif($node->is_display === 2)
{{-- 节点只可被订阅到 --}}
<span class="badge badge-lg badge-danger"><i class="fa-solid fa-store-slash" aria-hidden="true"></i></span>
@endif
@if ($node->ip)
<span class="badge badge-md badge-info"><i class="fa-solid fa-4" aria-hidden="true"></i></span>
@endif
@if ($node->ipv6)
<span class="badge badge-md badge-info"><i class="fa-solid fa-6" aria-hidden="true"></i></span>
@endif
</td>
<td>
@if ($node->isOnline)
@if ($node->status)
{{ $node->load }}
@else
<i class="yellow-700 icon icon-spin fa-solid fa-gear" aria-hidden="true"></i>
@endif
@else
@if ($node->status)
<i class="red-600 fa-solid fa-gear" aria-hidden="true"></i>
@else
<i class="red-600 fa-solid fa-handshake-simple-slash" aria-hidden="true"></i>
@endif
@endif
</td>
<td>
@canany(['admin.node.edit', 'admin.node.clone', 'admin.node.destroy', 'admin.node.monitor', 'admin.node.geo',
'admin.node.check', 'admin.node.reload'])
<button class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" type="button"
aria-expanded="false">
<i class="icon wb-wrench" aria-hidden="true"></i>
</button>
<div class="dropdown-menu" role="menu">
@can('admin.node.edit')
<a class="dropdown-item" href="{{ route('admin.node.edit', [$node->id, 'page' => Request::query('page', 1)]) }}"
role="menuitem">
<i class="icon wb-edit" aria-hidden="true"></i> {{ trans('common.edit') }}
</a>
@endcan
@can('admin.node.clone')
<a class="dropdown-item" href="{{ route('admin.node.clone', $node) }}" role="menuitem">
<i class="icon wb-copy" aria-hidden="true"></i> {{ trans('admin.clone') }}
</a>
@endcan
@can('admin.node.destroy')
<a class="dropdown-item red-700" href="javascript:delNode('{{ $node->id }}', '{{ $node->name }}')" role="menuitem">
<i class="icon wb-trash" aria-hidden="true"></i> {{ trans('common.delete') }}
</a>
@endcan
@can('admin.node.monitor')
<a class="dropdown-item" href="{{ route('admin.node.monitor', $node) }}" role="menuitem">
<i class="icon wb-stats-bars" aria-hidden="true"></i> {{ trans('admin.node.traffic_monitor') }}
</a>
@endcan
<hr />
@can('admin.node.geo')
<a class="dropdown-item" href="javascript:refreshGeo('{{ $node->id }}')" role="menuitem">
<i class="icon wb-map" id="geo{{ $node->id }}" aria-hidden="true"></i> {{ trans('admin.node.refresh_geo') }}
</a>
@endcan
@can('admin.node.check')
<a class="dropdown-item" href="javascript:checkNode('{{ $node->id }}')" role="menuitem">
<i class="icon wb-signal" id="node_{{ $node->id }}" aria-hidden="true"></i>
{{ trans('admin.node.connection_test') }}
</a>
@endcan
@if ($node->type === 4)
@can('admin.node.reload')
<hr />
<a class="dropdown-item" href="javascript:reload('{{ $node->id }}')" role="menuitem">
<i class="icon wb-reload" id="reload_{{ $node->id }}" aria-hidden="true"></i> {{ trans('admin.node.reload') }}
</a>
@endcan
@endif
</div>
@endcan
</td>
</tr>
@if (count($node->childNodes))
@foreach ($node->childNodes as $childNode)
<tr class="bg-blue-grey-200 grey-700 table-borderless frontlin">
<td></td>
<td><i class="float-left fa-solid fa-right-left" aria-hidden="true"></i>
<strong>{{ trans('model.node.transfer') }}</strong>
</td>
<td> {{ $childNode->name }} </td>
<td> {{ $childNode->server }} </td>
<td> {{ $childNode->is_ddns ? trans('model.node.ddns') : $childNode->ip }} </td>
<td colspan="2">
@if ($childNode->is_display === 0)
{{-- 节点完全不可见 --}}
<span class="badge badge-lg badge-danger"><i class="icon wb-eye-close" aria-hidden="true"></i></span>
@elseif($childNode->is_display === 1)
{{-- 节点只在页面中显示 --}}
<span class="badge badge-lg badge-danger"><i class="fa-solid fa-link-slash" aria-hidden="true"></i></span>
@elseif($childNode->is_display === 2)
{{-- 节点只可被订阅到 --}}
<span class="badge badge-lg badge-danger"><i class="fa-solid fa-store-slash" aria-hidden="true"></i></span>
@endif
</td>
<td colspan="2">
@if (!$childNode->status || !$node->status)
<i class="red-600 fa-solid fa-handshake-simple-slash" aria-hidden="true"></i>
@endif
</td>
<td colspan="3">
@canany(['admin.node.edit', 'admin.node.clone', 'admin.node.destroy', 'admin.node.monitor', 'admin.node.geo',
'admin.node.check'])
<button class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" type="button"
aria-expanded="false">
<i class="icon wb-wrench" aria-hidden="true"></i>
</button>
<div class="dropdown-menu" role="menu">
@can('admin.node.edit')
<a class="dropdown-item"
href="{{ route('admin.node.edit', [$childNode->id, 'page' => Request::query('page', 1)]) }}" role="menuitem">
<i class="icon wb-edit" aria-hidden="true"></i> {{ trans('common.edit') }}
</a>
@endcan
@can('admin.node.clone')
<a class="dropdown-item" href="{{ route('admin.node.clone', $childNode) }}" role="menuitem">
<i class="icon wb-copy" aria-hidden="true"></i> {{ trans('admin.clone') }}
</a>
@endcan
@can('admin.node.destroy')
<a class="dropdown-item red-700" href="javascript:delNode('{{ $childNode->id }}', '{{ $childNode->name }}')"
role="menuitem">
<i class="icon wb-trash" aria-hidden="true"></i> {{ trans('common.delete') }}
</a>
@endcan
@can('admin.node.monitor')
<a class="dropdown-item" href="{{ route('admin.node.monitor', $childNode) }}" role="menuitem">
<i class="icon wb-stats-bars" aria-hidden="true"></i> {{ trans('admin.node.traffic_monitor') }}
</a>
@endcan
<hr />
@can('admin.node.geo')
<a class="dropdown-item" href="javascript:refreshGeo('{{ $childNode->id }}')" role="menuitem">
<i class="icon wb-map" id="geo_{{ $childNode->id }}" aria-hidden="true"></i>
{{ trans('admin.node.refresh_geo') }}
</a>
@endcan
@can('admin.node.check')
<a class="dropdown-item" href="javascript:checkNode('{{ $childNode->id }}')" role="menuitem">
<i class="icon wb-signal" id="node_{{ $childNode->id }}" aria-hidden="true"></i>
{{ trans('admin.node.connection_test') }}
</a>
@endcan
</div>
@endcan
</td>
</tr>
@endforeach
@endif
@endforeach
</tbody>
</table>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-sm-4">
{!! trans('admin.node.counts', ['num' => $nodeList->total()]) !!}
</div>
<div class="col-sm-8">
<nav class="Page navigation float-right">
{{ $nodeList->links() }}
</nav>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('javascript')
<script>
@can('admin.node.check')
// 节点连通性测试
function checkNode(id) {
$.ajax({
method: 'POST',
url: '{{ route('admin.node.check', '') }}/' + id,
data: {
_token: '{{ csrf_token() }}'
},
beforeSend: function() {
$('#node_' + id).removeClass('wb-signal').addClass('wb-loop icon-spin');
},
success: function(ret) {
if (ret.status === 'success') {
let str = '';
for (let i in ret.message) {
str += '<tr><td>' + i + '</td><td>' + ret.message[i][0] + '</td><td>' + ret.message[i][1] +
'</td></tr>';
}
swal.fire({
title: ret.title,
icon: 'info',
html: '<table class="my-20"><thead class="thead-default"><tr><th> IP </th><th> ICMP </th> <th> TCP </th></thead><tbody>' +
str + '</tbody></table>',
showConfirmButton: false,
});
} else {
swal.fire({
title: ret.title,
text: ret.message,
icon: 'error'
});
}
},
complete: function() {
$('#node_' + id).removeClass('wb-loop icon-spin').addClass('wb-signal');
},
});
}
@endcan
@can('admin.node.reload')
// 发送节点重载请求
function reload(id) {
swal.fire({
text: '{{ trans('admin.node.reload_confirm') }}',
icon: 'question',
showCancelButton: true,
cancelButtonText: '{{ trans('common.close') }}',
confirmButtonText: '{{ trans('common.confirm') }}',
}).then((result) => {
if (result.value) {
$.ajax({
method: 'POST',
url: '{{ route('admin.node.reload', '') }}/' + id,
data: {
_token: '{{ csrf_token() }}'
},
beforeSend: function() {
$('#reload_' + id).removeClass('wb-reload').addClass('wb-loop icon-spin');
},
success: function(ret) {
if (ret.status === 'success') {
swal.fire({
title: ret.message,
icon: 'info',
showConfirmButton: false
});
} else {
swal.fire({
title: ret.message,
icon: 'error'
});
}
},
complete: function() {
$('#reload_' + id).removeClass('wb-loop icon-spin').addClass('wb-reload');
},
});
}
});
}
@endcan
@can('admin.node.geo')
// 刷新节点地理信息
function refreshGeo(id) {
$.ajax({
method: 'GET',
url: '{{ route('admin.node.geo', '') }}/' + id,
data: {
_token: '{{ csrf_token() }}'
},
beforeSend: function() {
$('#geo_' + id).removeClass('wb-map').addClass('wb-loop icon-spin');
},
success: function(ret) {
if (ret.status === 'success') {
swal.fire({
title: ret.message,
icon: 'info',
showConfirmButton: false
});
} else {
swal.fire({
title: ret.message,
icon: 'error'
});
}
},
complete: function() {
$('#geo_' + id).removeClass('wb-loop icon-spin').addClass('wb-map');
},
});
}
@endcan
@can('admin.node.destroy')
// 删除节点
function delNode(id, name) {
swal.fire({
title: '{{ trans('common.warning') }}',
text: '{{ trans('admin.confirm.delete.0', ['attribute' => trans('model.node.attribute')]) }}' + name +
'{{ trans('admin.confirm.delete.1') }}',
icon: 'warning',
showCancelButton: true,
cancelButtonText: '{{ trans('common.close') }}',
confirmButtonText: '{{ trans('common.confirm') }}',
}).then((result) => {
if (result.value) {
$.ajax({
method: 'DELETE',
url: '{{ route('admin.node.destroy', '') }}/' + id,
data: {
_token: '{{ csrf_token() }}'
},
dataType: 'json',
success: function(ret) {
if (ret.status === 'success') {
swal.fire({
title: ret.message,
icon: 'success',
timer: 1000,
showConfirmButton: false,
}).then(() => window.location.reload());
} else {
swal.fire({
title: ret.message,
icon: 'error'
}).then(() => window.location.reload());
}
},
});
}
});
}
@endcan
</script>
@endpush