488 lines
15 KiB
Vue
488 lines
15 KiB
Vue
<template>
|
|
<UDashboardPanel id="data-centres">
|
|
<template #header>
|
|
<UDashboardNavbar title="Data Centres">
|
|
<template #leading>
|
|
<UDashboardSidebarCollapse />
|
|
</template>
|
|
|
|
<template #right>
|
|
<UButton to="/connect/clouds" size="sm">
|
|
Connecter Cloud
|
|
</UButton>
|
|
</template>
|
|
</UDashboardNavbar>
|
|
|
|
<UDashboardToolbar>
|
|
<template #left>
|
|
<UBadge variant="subtle" size="lg">
|
|
{{ dataCentres.length }} centres mondiaux
|
|
</UBadge>
|
|
</template>
|
|
|
|
<template #right>
|
|
<UBadge variant="subtle" class="text-xs">
|
|
{{ dataCentres.filter(dc => dc.status === 'active').length }} actifs
|
|
</UBadge>
|
|
<UBadge variant="subtle" class="text-xs">
|
|
99.9% uptime
|
|
</UBadge>
|
|
</template>
|
|
</UDashboardToolbar>
|
|
</template>
|
|
|
|
<template #body>
|
|
<div class="space-y-12">
|
|
<!-- Header Section -->
|
|
<div class="text-center mb-8">
|
|
<h1 class="text-3xl font-bold mb-4">
|
|
Réseau Global de Data Centres
|
|
</h1>
|
|
<p class="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
|
Connectez-vous à notre infrastructure mondiale avec plus de {{ dataCentres.length }} data centres dans {{ regions.length }} régions
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Statistiques -->
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
|
<UCard class="text-center">
|
|
<div class="p-6">
|
|
<div class="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
|
<UIcon name="i-lucide-server" class="w-6 h-6 text-primary" />
|
|
</div>
|
|
<div class="text-2xl font-bold mb-1">
|
|
{{ dataCentres.length }}+
|
|
</div>
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
Data Centres
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="text-center">
|
|
<div class="p-6">
|
|
<div class="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
|
<UIcon name="i-lucide-globe" class="w-6 h-6 text-primary" />
|
|
</div>
|
|
<div class="text-2xl font-bold mb-1">
|
|
{{ regions.length }}
|
|
</div>
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
Régions
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="text-center">
|
|
<div class="p-6">
|
|
<div class="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
|
<UIcon name="i-lucide-shield-check" class="w-6 h-6 text-primary" />
|
|
</div>
|
|
<div class="text-2xl font-bold mb-1">
|
|
99.9%
|
|
</div>
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
Uptime SLA
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="text-center">
|
|
<div class="p-6">
|
|
<div class="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center mx-auto mb-3">
|
|
<UIcon name="i-lucide-leaf" class="w-6 h-6 text-primary" />
|
|
</div>
|
|
<div class="text-2xl font-bold mb-1">
|
|
100%
|
|
</div>
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
Énergie verte
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
|
|
<!-- Carte Interactive -->
|
|
<UCard>
|
|
<template #header>
|
|
<h2 class="text-xl font-semibold">
|
|
Carte Interactive des Data Centres
|
|
</h2>
|
|
</template>
|
|
|
|
<div class="space-y-4">
|
|
<!-- Filtres -->
|
|
<div>
|
|
<UTabs v-model="selectedRegion" :items="tabs" class="w-full" />
|
|
</div>
|
|
|
|
<!-- Carte Leaflet -->
|
|
<div id="map" class="h-[500px] w-full rounded-lg" />
|
|
</div>
|
|
</UCard>
|
|
|
|
<!-- Liste des Data Centres -->
|
|
<div>
|
|
<h2 class="text-2xl font-bold mb-8">
|
|
Nos Data Centres
|
|
</h2>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<UCard
|
|
v-for="dc in filteredDataCentres"
|
|
:key="dc.id"
|
|
class="hover:shadow-lg transition-shadow duration-300"
|
|
>
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="font-semibold">
|
|
{{ dc.name }}
|
|
</h3>
|
|
<UBadge
|
|
:variant="dc.status === 'active' ? 'solid' : 'outline'"
|
|
size="xs"
|
|
>
|
|
{{ dc.status === 'active' ? 'Actif' : 'En construction' }}
|
|
</UBadge>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="space-y-3">
|
|
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
|
|
<UIcon name="i-lucide-map-pin" class="w-4 h-4" />
|
|
{{ dc.city }}, {{ dc.country }}
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
|
|
<UIcon name="i-lucide-building" class="w-4 h-4" />
|
|
{{ dc.floors }} étages, {{ dc.racks }} racks
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
|
|
<UIcon name="i-lucide-zap" class="w-4 h-4" />
|
|
{{ dc.power }} MW de puissance
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
|
|
<UIcon name="i-lucide-users" class="w-4 h-4" />
|
|
{{ dc.carriers }}+ opérateurs
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-1 pt-2">
|
|
<UBadge
|
|
v-for="certification in dc.certifications"
|
|
:key="certification"
|
|
variant="subtle"
|
|
size="xs"
|
|
>
|
|
{{ certification }}
|
|
</UBadge>
|
|
</div>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<UButton variant="outline" block>
|
|
Demander un devis
|
|
</UButton>
|
|
</template>
|
|
</UCard>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Avantages -->
|
|
<div>
|
|
<h2 class="text-2xl font-bold mb-8 text-center">
|
|
Pourquoi choisir nos Data Centres ?
|
|
</h2>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div class="text-center">
|
|
<div class="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<UIcon name="i-lucide-shield" size="24" class="text-primary" />
|
|
</div>
|
|
<h3 class="font-semibold mb-2">
|
|
Sécurité
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-300">
|
|
Sécurité physique 24/7, biométrie, vidéosurveillance
|
|
</p>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<div class="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<UIcon name="i-lucide-activity" size="24" class="text-primary" />
|
|
</div>
|
|
<h3 class="font-semibold mb-2">
|
|
Fiabilité
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-300">
|
|
99.9% de disponibilité, alimentation redondante
|
|
</p>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<div class="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<UIcon name="i-lucide-network" size="24" class="text-primary" />
|
|
</div>
|
|
<h3 class="font-semibold mb-2">
|
|
Connectivité
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-300">
|
|
Accès à 500+ opérateurs, peering direct
|
|
</p>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<div class="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<UIcon name="i-lucide-leaf" size="24" class="text-primary" />
|
|
</div>
|
|
<h3 class="font-semibold mb-2">
|
|
Éco-responsable
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-300">
|
|
100% énergie renouvelable, PUE < 1.3
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</UDashboardPanel>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
// Imports côté client uniquement
|
|
let L: any = null
|
|
if (process.client) {
|
|
L = await import('leaflet')
|
|
await import('leaflet/dist/leaflet.css')
|
|
}
|
|
|
|
// Métadonnées de la page
|
|
useSeoMeta({
|
|
title: 'Data Centres - Wibx Tour Layer 2',
|
|
description: 'Découvrez notre réseau mondial de data centres sécurisés et connectés. Plus de 50 centres dans 25 régions avec 99.9% de disponibilité.'
|
|
})
|
|
|
|
// Données des data centres
|
|
const dataCentres = ref([
|
|
{
|
|
id: 1,
|
|
name: 'Paris-Aubervilliers',
|
|
city: 'Paris',
|
|
country: 'France',
|
|
region: 'Europe',
|
|
lat: 48.8566,
|
|
lng: 2.3522,
|
|
status: 'active',
|
|
floors: 4,
|
|
racks: 2000,
|
|
power: 12,
|
|
certifications: ['ISO 27001', 'SOC 2', 'Tier III'],
|
|
carriers: 150,
|
|
latency: 2
|
|
},
|
|
{
|
|
id: 2,
|
|
name: 'London-Docklands',
|
|
city: 'Londres',
|
|
country: 'Royaume-Uni',
|
|
region: 'Europe',
|
|
lat: 51.5074,
|
|
lng: -0.1278,
|
|
status: 'active',
|
|
floors: 6,
|
|
racks: 3000,
|
|
power: 18,
|
|
certifications: ['ISO 27001', 'SOC 2', 'Tier IV'],
|
|
carriers: 200,
|
|
latency: 1
|
|
},
|
|
{
|
|
id: 3,
|
|
name: 'Frankfurt-Main',
|
|
city: 'Francfort',
|
|
country: 'Allemagne',
|
|
region: 'Europe',
|
|
lat: 50.1109,
|
|
lng: 8.6821,
|
|
status: 'active',
|
|
floors: 5,
|
|
racks: 2500,
|
|
power: 15,
|
|
certifications: ['ISO 27001', 'SOC 2', 'Tier III'],
|
|
carriers: 180,
|
|
latency: 1.5
|
|
},
|
|
{
|
|
id: 4,
|
|
name: 'New York-Manhattan',
|
|
city: 'New York',
|
|
country: 'États-Unis',
|
|
region: 'Amérique du Nord',
|
|
lat: 40.7128,
|
|
lng: -74.0060,
|
|
status: 'active',
|
|
floors: 8,
|
|
racks: 4000,
|
|
power: 25,
|
|
certifications: ['ISO 27001', 'SOC 2', 'Tier IV'],
|
|
carriers: 300,
|
|
latency: 0.5
|
|
},
|
|
{
|
|
id: 5,
|
|
name: 'Tokyo-Shibuya',
|
|
city: 'Tokyo',
|
|
country: 'Japon',
|
|
region: 'Asie-Pacifique',
|
|
lat: 35.6762,
|
|
lng: 139.6503,
|
|
status: 'active',
|
|
floors: 10,
|
|
racks: 3500,
|
|
power: 22,
|
|
certifications: ['ISO 27001', 'SOC 2', 'Tier IV'],
|
|
carriers: 250,
|
|
latency: 0.8
|
|
}
|
|
])
|
|
|
|
// Filtres
|
|
const selectedRegion = ref('all')
|
|
const regions = computed(() => [...new Set(dataCentres.value.map(dc => dc.region))])
|
|
|
|
const tabs = computed(() => [
|
|
{ value: 'all', label: 'Toutes les régions' },
|
|
...regions.value.map(region => ({ value: region, label: region }))
|
|
])
|
|
|
|
const filteredDataCentres = computed(() => {
|
|
if (selectedRegion.value === 'all') {
|
|
return dataCentres.value
|
|
}
|
|
return dataCentres.value.filter(dc => dc.region === selectedRegion.value)
|
|
})
|
|
|
|
// Initialisation de la carte
|
|
let map: L.Map | null = null
|
|
let markers: L.Marker[] = []
|
|
let currentTileLayer: L.TileLayer | null = null
|
|
|
|
const colorMode = useColorMode()
|
|
|
|
const initMap = async () => {
|
|
if (!process.client || !L) return
|
|
|
|
// Charger Leaflet si pas encore fait
|
|
if (!L.map) {
|
|
const leafletModule = await import('leaflet')
|
|
L = leafletModule.default
|
|
await import('leaflet/dist/leaflet.css')
|
|
}
|
|
|
|
// Corriger les icônes Leaflet par défaut
|
|
delete (L.Icon.Default.prototype as any)._getIconUrl
|
|
L.Icon.Default.mergeOptions({
|
|
iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png',
|
|
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',
|
|
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png'
|
|
})
|
|
|
|
// Initialiser la carte
|
|
map = L.map('map', {
|
|
center: [20, 0],
|
|
zoom: 2
|
|
})
|
|
|
|
// Ajouter les tuiles selon le mode
|
|
updateTileLayer()
|
|
|
|
// Ajouter les marqueurs
|
|
updateMarkers()
|
|
}
|
|
|
|
const updateTileLayer = () => {
|
|
if (!map || !L || !process.client) return
|
|
|
|
// Supprimer l'ancienne couche de tuiles
|
|
if (currentTileLayer) {
|
|
map.removeLayer(currentTileLayer)
|
|
}
|
|
|
|
// Ajouter la nouvelle couche selon le mode
|
|
if (colorMode.value === 'dark') {
|
|
// Mode sombre - utiliser CartoDB Dark Matter
|
|
currentTileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
|
attribution: '© OpenStreetMap © CartoDB',
|
|
subdomains: 'abcd',
|
|
maxZoom: 19
|
|
})
|
|
} else {
|
|
// Mode clair - utiliser OpenStreetMap
|
|
currentTileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© OpenStreetMap contributors',
|
|
maxZoom: 19
|
|
})
|
|
}
|
|
|
|
currentTileLayer.addTo(map)
|
|
}
|
|
|
|
const updateMarkers = () => {
|
|
if (!map || !L || !process.client) return
|
|
|
|
// Supprimer les anciens marqueurs
|
|
markers.forEach(marker => map?.removeLayer(marker))
|
|
markers = []
|
|
|
|
// Ajouter les nouveaux marqueurs
|
|
filteredDataCentres.value.forEach(dc => {
|
|
const marker = L.marker([dc.lat, dc.lng])
|
|
.bindPopup(`
|
|
<div class="p-2">
|
|
<h3 class="font-bold text-sm">${dc.name}</h3>
|
|
<p class="text-xs text-gray-600">${dc.city}, ${dc.country}</p>
|
|
<p class="text-xs mt-1">
|
|
<span class="inline-block w-2 h-2 rounded-full ${dc.status === 'active' ? 'bg-green-500' : 'bg-orange-500'} mr-1"></span>
|
|
${dc.status === 'active' ? 'Actif' : 'En construction'}
|
|
</p>
|
|
<p class="text-xs mt-1">${dc.carriers}+ opérateurs</p>
|
|
</div>
|
|
`)
|
|
|
|
if (map) {
|
|
marker.addTo(map)
|
|
markers.push(marker)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Mise à jour de la carte quand les filtres changent
|
|
watch(filteredDataCentres, updateMarkers, { deep: true })
|
|
|
|
// Mise à jour des tuiles quand le mode dark change
|
|
watch(() => colorMode.value, updateTileLayer)
|
|
|
|
// Initialisation côté client
|
|
onMounted(() => {
|
|
nextTick(() => {
|
|
initMap()
|
|
})
|
|
})
|
|
|
|
// Nettoyage
|
|
onUnmounted(() => {
|
|
if (map) {
|
|
map.remove()
|
|
map = null
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
/* Fix pour les icônes Leaflet */
|
|
.leaflet-default-icon-path {
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbXNfN1+3bBZFvbOkg9vJLJsJU6vKKUHVQmCQNkzQyGpHJfVgZcwKjGhgqCGHYRiRPUHBDOtklmZmcpjPXJBL8/PdFqZBHxhASNQAyBfOaOWIhAMCCGHaB0hAKIRBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5AYhBSCAABYBBEAKARAGCYhBBbGGQBkKCCGg5A');
|
|
}
|
|
</style> |