120 lines
3.3 KiB
Vue
120 lines
3.3 KiB
Vue
<template>
|
|
<div class="h-full flex flex-col bg-monokai-bg border-l border-monokai-comment">
|
|
<!-- Header -->
|
|
<div class="p-4 border-b border-monokai-comment">
|
|
<h2 class="text-xl font-bold text-monokai-pink">Nouvelles Détections</h2>
|
|
</div>
|
|
|
|
<!-- Liste -->
|
|
<div class="flex-1 overflow-auto p-4">
|
|
<div v-if="newIPs.length > 0" class="space-y-3">
|
|
<div
|
|
v-for="ip in newIPs"
|
|
:key="ip.ip"
|
|
@click="selectIP(ip)"
|
|
class="p-3 rounded border-2 border-monokai-pink bg-monokai-pink/10 cursor-pointer hover:bg-monokai-pink/20 transition-colors"
|
|
>
|
|
<!-- IP -->
|
|
<div class="font-mono font-bold text-monokai-text">
|
|
{{ ip.ip }}
|
|
</div>
|
|
|
|
<!-- État -->
|
|
<div class="text-sm mt-1">
|
|
<span
|
|
:class="[
|
|
'px-2 py-1 rounded text-xs',
|
|
ip.last_status === 'online'
|
|
? 'bg-monokai-green/20 text-monokai-green'
|
|
: 'bg-monokai-comment/20 text-monokai-comment'
|
|
]"
|
|
>
|
|
{{ ip.last_status || 'Inconnu' }}
|
|
</span>
|
|
<span
|
|
v-if="!ip.known"
|
|
class="ml-2 px-2 py-1 rounded text-xs bg-monokai-purple/20 text-monokai-purple"
|
|
>
|
|
Inconnue
|
|
</span>
|
|
</div>
|
|
|
|
<!-- MAC et Vendor -->
|
|
<div v-if="ip.mac" class="text-xs text-monokai-comment mt-2 font-mono">
|
|
{{ ip.mac }}
|
|
<span v-if="ip.vendor" class="ml-1">({{ ip.vendor }})</span>
|
|
</div>
|
|
|
|
<!-- Timestamp -->
|
|
<div class="text-xs text-monokai-comment mt-2">
|
|
{{ formatTime(ip.first_seen) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Placeholder -->
|
|
<div v-else class="text-center text-monokai-comment mt-10">
|
|
<p>Aucune nouvelle IP détectée</p>
|
|
<p class="text-sm mt-2">Les nouvelles IPs apparaîtront ici</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
import { storeToRefs } from 'pinia'
|
|
import { useIPStore } from '@/stores/ipStore'
|
|
|
|
const ipStore = useIPStore()
|
|
const { ips } = storeToRefs(ipStore)
|
|
|
|
// IPs nouvellement détectées (dans les dernières 24h)
|
|
const newIPs = computed(() => {
|
|
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
|
|
|
|
return ips.value
|
|
.filter(ip => {
|
|
if (!ip.first_seen) return false
|
|
const firstSeen = new Date(ip.first_seen)
|
|
return firstSeen > oneDayAgo
|
|
})
|
|
.sort((a, b) => {
|
|
const dateA = new Date(a.first_seen)
|
|
const dateB = new Date(b.first_seen)
|
|
return dateB - dateA // Plus récent en premier
|
|
})
|
|
.slice(0, 20) // Limiter à 20
|
|
})
|
|
|
|
function selectIP(ip) {
|
|
ipStore.selectIP(ip)
|
|
}
|
|
|
|
function formatTime(dateString) {
|
|
if (!dateString) return ''
|
|
const date = new Date(dateString)
|
|
const now = new Date()
|
|
const diff = now - date
|
|
|
|
// Moins d'une minute
|
|
if (diff < 60000) {
|
|
return 'À l\'instant'
|
|
}
|
|
|
|
// Moins d'une heure
|
|
if (diff < 3600000) {
|
|
const minutes = Math.floor(diff / 60000)
|
|
return `Il y a ${minutes} min`
|
|
}
|
|
|
|
// Moins de 24h
|
|
if (diff < 86400000) {
|
|
const hours = Math.floor(diff / 3600000)
|
|
return `Il y a ${hours}h`
|
|
}
|
|
|
|
return date.toLocaleString('fr-FR')
|
|
}
|
|
</script>
|