Files
portal-api/resources/views/frontend/service/console.blade.php
T
2026-01-17 11:27:54 +07:00

226 lines
10 KiB
PHP

@extends('frontend.layouts.master')
@push('viewStyles')
<link rel="stylesheet" href="{{ asset('lib/wmks/css/wmks-all.css') }}" />
<link rel="stylesheet" href="{{ asset('css/service/console.css') }}">
@endpush
@section('content')
<div class="min-h-screen bg-gray-50">
<div class="container mx-auto px-6 py-8">
<!-- Main Layout: 2 Columns -->
<div class="flex flex-col gap-3">
<div class="w-full">
<div class="console-container">
<!-- Console Header -->
<div class="console-header">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="text-white">
<h3 class="font-medium text-base">VM Console</h3>
<p class="text-sm text-gray-400">{{ $product->name ?? 'Virtual Machine' }}</p>
</div>
</div>
<div class="flex items-center space-x-3">
<span class="status-dot status-connecting" id="statusDot"></span>
<span class="text-sm text-gray-400" id="statusText">Đang kết nối...</span>
</div>
</div>
</div>
<!-- Loading State -->
<div id="loadingState" class="w-full h-[70vh] flex items-center justify-center bg-gray-900">
<div class="text-center">
<div class="loading-spinner mx-auto mb-4"></div>
<h3 class="text-xl font-medium text-white mb-2">Đang kết nối với vCenter</h3>
<p class="text-gray-400">Vui lòng chờ...</p>
</div>
</div>
<!-- Console Display -->
<div id="wmksContainer" class="w-full h-[70vh] relative bg-black hidden">
</div>
</div>
</div>
<div class="w-full">
<div class="control-panel">
<div class="flex flex-row gap-2 items-center p-2">
<button onclick="enterFullScreen()" class="btn-secondary flex items-center justify-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
</svg>
Toàn màn hình
</button>
<button onclick="sendCAD()" class="btn-secondary flex items-center justify-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Ctrl + Alt + Del
</button>
<div class="flex flex-row gap-2 items-center">
<input type="text" id="sendStringText" placeholder="Type your message..."
class="input-field" />
<button onclick="sendInputString()" class="btn-primary flex items-center justify-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
Gửi
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="{{ asset('lib/jquery/jquery.min.js') }}"></script>
<script src="{{ asset('lib/jquery-ui/jquery-ui.min.js') }}"></script>
<script src="{{ asset('lib/wmks/wmks.min.js') }}"></script>
<script src="{{ asset('lib/wmks/wmks-sdk-example.js') }}"></script>
<script type="text/javascript">
// Show loading state initially
$(document).ready(function() {
$('#loadingState').removeClass('hidden');
$('#wmksContainer').addClass('hidden');
});
let WMKSContainer = $('#wmksContainer');
// Retry and connection state variables
var isConnected = false;
var retryCount = 0;
const maxRetries = 30;
const retryDelay = 500; // ms
var wmks = WMKS.createWMKS("wmksContainer", {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE, function(event, data) {
if (data.state === WMKS.CONST.ConnectionState.CONNECTED) {
console.log("Connected successfully");
isConnected = true;
retryCount = 0; // reset retries on success
// Update status
$('#statusDot').removeClass('status-connecting').addClass('status-connected');
$('#statusText').text('Connected');
// Hide loading and show console
$('#loadingState').addClass('hidden');
$('#wmksContainer').removeClass('hidden');
} else if (data.state === WMKS.CONST.ConnectionState.DISCONNECTED) {
console.log('WMKS disconnected');
isConnected = false;
$('#statusDot').removeClass('status-connecting status-connected').addClass('status-error');
$('#statusText').text('Disconnected');
}
});
const getTicket = new Promise((resolve, reject) => {
$.ajax({
url: '{{ route('api.user.GetConsoleTicket') }}',
type: 'get',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer {{ request()->cookie('aut_accessToken') }}'
},
data: {
product: {{ $product->id }}
},
success: function(response) {
if (response.error === false) {
resolve(response)
} else {
reject(response.message)
}
},
error: function(xhr, status, error) {
console.error('API Error:', xhr.responseText);
reject('API request failed: ' + error);
}
})
});
getTicket
.then(result => {
if (result !== false) {
const wmksHost = '{{ config('vmware.wmks_host', '10.10.10.120') }}';
wmks.connect(`wss://${wmksHost}/ticket/${result.data}`);
}
})
.catch(error => {
console.log(`Connection error: ${error}`)
// Update status
$('#statusDot').removeClass('status-connecting').addClass('status-error');
$('#statusText').text('Connection Failed');
// Hide loading state and show error
$('#loadingState').addClass('hidden');
$('#wmksContainer').removeClass('hidden');
WMKSContainer.html(`
<div class="flex items-center justify-center w-full h-full bg-gray-900">
<div class="text-center">
<div class="inline-flex items-center justify-center w-16 h-16 bg-red-100 rounded-full mb-4">
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<h3 class="text-lg font-medium text-white mb-2">Connection Failed</h3>
<p class="text-gray-400 mb-4">Unable to connect to VM console</p>
<button onclick="location.reload()"
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
Try Again
</button>
</div>
</div>
`);
})
// Control Functions
window.enterFullScreen = function() {
if (wmks) {
wmks.enterFullScreen();
}
};
window.sendCAD = function() {
if (wmks) {
wmks.sendCAD();
}
};
window.sendInputString = function() {
const text = document.getElementById('sendStringText').value;
if (text && wmks) {
wmks.sendInputString(text);
document.getElementById('sendStringText').value = '';
}
};
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.key === 'F11') {
e.preventDefault();
enterFullScreen();
}
if (e.ctrlKey && e.key === 'Enter') {
sendInputString();
}
});
// Enter key for text input
document.getElementById('sendStringText').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendInputString();
}
});
</script>
@endsection