Files
portal-api/resources/views/frontend/service/console.blade.php
T
2025-07-24 16:18:27 +07:00

345 lines
14 KiB
PHP

@extends('frontend.layouts.master')
@push('viewStyles')
<link rel="stylesheet" href="{{ asset('lib/wmks/css/wmks-all.css') }}" />
<link rel="stylesheet" href="{{ asset('lib/adminlte/adminlte.css') }}">
<style>
.console-container {
background: #1a1a1a;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.console-header {
background: #2a2a2a;
border-bottom: 1px solid #3a3a3a;
padding: 12px 20px;
}
.control-panel {
background: white;
border-radius: 8px;
border: 1px solid #e5e7eb;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.btn-primary {
background: #3b82f6;
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
font-weight: 500;
transition: background-color 0.2s;
}
.btn-primary:hover {
background: #2563eb;
}
.btn-secondary {
background: #f8f9fa;
color: #374151;
border: 1px solid #d1d5db;
padding: 8px 16px;
border-radius: 6px;
font-weight: 500;
transition: all 0.2s;
}
.btn-secondary:hover {
background: #e5e7eb;
}
.input-field {
width: 100%;
padding: 8px 12px;
border: 1px solid #d1d5db;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.2s;
}
.input-field:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #e5e7eb;
border-top: 3px solid #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #111827;
margin-bottom: 16px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
display: inline-block;
}
.status-connecting { background: #f59e0b; }
.status-connected { background: #10b981; }
.status-error { background: #ef4444; }
</style>
@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="grid grid-cols-1 lg:grid-cols-4 gap-6">
<!-- Console Display - Main Column (3/4) -->
<div class="lg:col-span-3">
<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">Connecting...</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">Connecting to vCenter</h3>
<p class="text-gray-400">Please wait...</p>
</div>
</div>
<!-- Console Display -->
<div id="wmksContainer" class="w-full h-[70vh] relative bg-black hidden">
</div>
</div>
</div>
<!-- Control Panel - Sidebar (1/4) -->
<div class="lg:col-span-1">
<div class="space-y-6">
<!-- Quick Actions -->
<div class="control-panel p-6">
<h3 class="section-title">Control Panel</h3>
<div class="space-y-3">
<button onclick="enterFullScreen()"
class="btn-secondary w-full 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>
Full Screen
</button>
<button onclick="sendCAD()"
class="btn-secondary w-full 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>
</div>
<!-- Text Input -->
<div class="control-panel p-6">
<h4 class="section-title">Send Text</h4>
<div class="space-y-3">
<input type="text"
id="sendStringText"
placeholder="Type your message..."
class="input-field"/>
<button onclick="sendInputString()"
class="btn-primary w-full 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>
Send
</button>
</div>
</div>
<!-- Help -->
<div class="control-panel p-6">
<h4 class="section-title">Keyboard Shortcuts</h4>
<div class="space-y-2 text-sm text-gray-600">
<div class="flex justify-between">
<span>Full Screen</span>
<code class="bg-gray-100 px-2 py-1 rounded text-xs">F11</code>
</div>
<div class="flex justify-between">
<span>Send Text</span>
<code class="bg-gray-100 px-2 py-1 rounded text-xs">Ctrl+Enter</code>
</div>
</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');
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");
// 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) {
$('#statusDot').removeClass('status-connecting status-connected').addClass('status-error');
$('#statusText').text('Disconnected');
}
});
const getTicket = new Promise((resolve, reject) => {
$.ajax({
url: '{{ route('api.GetConsoleTicket') }}',
type: 'get',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'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)
}
}
})
});
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