feat: Implement VM console with dedicated layout, WMKS integration, and jQuery 3 compatibility.

This commit is contained in:
pbao9
2026-03-02 00:27:18 +07:00
parent 1cfcaee871
commit 2c8c3d14cd
7 changed files with 137 additions and 15 deletions
+1 -3
View File
@@ -1461,11 +1461,9 @@ PS;
"type" => "WEBMKS"
])->json();
if (!isset($response['error_type'])) {
$start = strpos($response['ticket'], '/ticket/');
$ticket = str_replace('/ticket/', '', substr($response['ticket'], $start));
return [
'error' => false,
'data' => $ticket
'data' => $response['ticket']
];
}
return [
@@ -158,11 +158,9 @@ class PowerManagementService
"type" => "WEBMKS"
])->json();
if (!isset($response['error_type'])) {
$start = strpos($response['ticket'], '/ticket/');
$ticket = str_replace('/ticket/', '', substr($response['ticket'], $start));
return [
'error' => false,
'data' => $ticket
'data' => $response['ticket']
];
}
return [
-1
View File
@@ -7,7 +7,6 @@ return [
],
'js' => [
'resources/js/app-vite.js',
// 'build/plugins/jquery/jquery.min.js',
'resources/js/pages/template.js',
],
],
+1 -1
View File
@@ -36,7 +36,7 @@
"fullcalendar": "^6.1.20",
"inputmask": "^5.0.9",
"javascript-obfuscator": "^4.1.1",
"jquery": "^4.0.0",
"jquery": "3.6.0",
"jquery-mousewheel": "^3.2.2",
"jquery-sparkline": "^2.4.0",
"jquery-steps": "^1.1.0",
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description"
content="Thế Giới Số cung cấp dịch vụ thiết kế website, phát triển ứng dụng, phân tích dữ liệu, triển khai & quản lý server, VPS, dedicated, email hosting và hệ thống portal quản lý dịch vụ cho doanh nghiệp.">
<meta name="author" content="Thế Giới Số">
<meta name="keywords"
content="thế giới số, thiết kế website, phát triển ứng dụng, phân tích dữ liệu, vps, hosting, dedicated server, email hosting, quản trị server, portal dịch vụ, laravel, nextjs, cloud, hạ tầng CNTT">
<title>Thế Giới Số Admin | VM Console</title>
<script>
(function() {
const theme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ?
'dark' : 'light');
document.documentElement.setAttribute('data-bs-theme', theme);
})();
</script>
<!-- CSRF Token -->
<meta name="_token" content="{{ csrf_token() }}">
<link rel="shortcut icon" href="{{ asset('/images/favi.svg') }}">
<!-- Static CSS — no jQuery dependency -->
@foreach (config('assets.static.css') as $css)
<link href="{{ asset($css) }}" rel="stylesheet" />
@endforeach
@stack('plugin-styles')
<!-- Vite CSS only — intentionally excludes Vite JS bundle (which carries jQuery 4) -->
@vite(config('assets.vite.css'))
@stack('style')
<!--
jQuery 3 — loaded here in <head> for WMKS compatibility.
WMKS (wmks.min.js) requires jQuery 3.x; jQuery 4 removed $.now()
which WMKS depends on via jQuery UI.
The main admin layout uses jQuery 4 via Vite — never load both on the same page.
-->
<script src="{{ asset('lib/jquery/jquery.min.js') }}"></script>
<script src="{{ asset('lib/jquery-ui/jquery-ui.min.js') }}"></script>
</head>
<body data-base-url="{{ url('/') }}">
<div class="main-wrapper" id="app">
@include('administrator.layout.partials.sidebar')
<div class="page-wrapper">
@include('administrator.layout.partials.header')
<div class="page-content">
<div class="card mb-4 bg-white rounded-4 shadow-none">
<div class="card-body p-3">
@yield('breadcrumb')
@yield('tab')
</div>
</div>
@yield('content')
</div>
@include('administrator.layout.partials.footer')
</div>
</div>
<!--
UI scripts — Bootstrap, Lucide, PerfectScrollbar are vanilla JS,
no jQuery 4 dependency. Select2 and DataTables are intentionally
excluded (they require jQuery and are not needed on the console page).
-->
<script src="{{ asset('build/plugins/bootstrap/bootstrap.bundle.min.js') }}"></script>
<script src="{{ asset('build/plugins/lucide/lucide.min.js') }}"></script>
<script src="{{ asset('build/plugins/perfect-scrollbar/perfect-scrollbar.min.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
var sidebarBody = document.querySelector('.sidebar-body');
if (sidebarBody && typeof PerfectScrollbar !== 'undefined') {
new PerfectScrollbar(sidebarBody);
}
});
</script>
@stack('plugin-scripts')
@include('administrator.layout.partials.toast')
@stack('custom-scripts')
</body>
</html>
@@ -1,4 +1,4 @@
@extends('administrator.layout.master')
@extends('administrator.layout.console')
@push('style')
<link rel="stylesheet" href="{{ asset('lib/wmks/css/wmks-all.css') }}">
@@ -161,10 +161,8 @@ $breadcrumbItems = [
</div>
</div>
<script src="{{ asset('lib/jquery/jquery.min.js') }}"></script>
<script src="{{ asset('lib/jquery-ui/jquery-ui.min.js') }}"></script>
{{-- jQuery 3 and jQuery UI are loaded in administrator.layout.console <head> --}}
<script src="{{ asset('lib/wmks/wmks.min.js') }}"></script>
<script src="{{ asset('lib/wmks/wmks-sdk-example.js') }}"></script>
<script type="text/javascript">
let loadingSteps = [
@@ -238,10 +236,16 @@ $breadcrumbItems = [
let WMKSContainer = $('#wmksContainer');
var wmks = WMKS.createWMKS("wmksContainer", {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE, function(event, data) {
console.log("WMKS state:", data.state, data);
if (data.state === WMKS.CONST.ConnectionState.CONNECTED) {
console.log("connection state change : connected");
hideLoadingAndShowConsole();
} else if (data.state === WMKS.CONST.ConnectionState.DISCONNECTED) {
showErrorState('{{ __('Mất kết nối WebSocket') }} (code: ' + data.code + ', reason: ' + data.reason + ')');
}
})
.register(WMKS.CONST.Events.ERROR, function(event, data) {
console.error("WMKS error:", data);
showErrorState('{{ __('Lỗi WMKS') }}: ' + (data.errorType || JSON.stringify(data)));
});
const getTicket = new Promise((resolve, reject) => {
@@ -275,8 +279,7 @@ $breadcrumbItems = [
.then(result => {
if (result !== false) {
updateConnectionStatus('{{ __('Đang kết nối đến Console...') }}');
const wmksHost = '{{ config('vmware.wmks_host', '10.10.10.120') }}';
wmks.connect(`wss://${wmksHost}/ticket/${result.data}`);
wmks.connect(result.data);
}
})
.catch(error => {
+25
View File
@@ -0,0 +1,25 @@
<?php
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$vCenter = app(\App\Http\Services\vCenter::class);
$vm = \App\Models\VirtualMachines::with('datacenter.vCenter')->first();
if (!$vm) {
echo "No VM found\n";
exit;
}
$vcenter_model = $vm->datacenter->vCenter;
echo "Logging in to vCenter: " . $vcenter_model->host . "\n";
$loggedIn = $vCenter->loginServer($vcenter_model);
if (!$loggedIn) {
echo "Failed to login to vCenter\n";
exit;
}
echo "Logged in successfully\n";
$ticket = $vCenter->GetConsoleTickets($vm->vm_id);
print_r($ticket);