315 lines
7.6 KiB
JavaScript
315 lines
7.6 KiB
JavaScript
/**
|
|
* Store Pinia pour la gestion des IPs
|
|
*/
|
|
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import axios from 'axios'
|
|
|
|
export const useIPStore = defineStore('ip', () => {
|
|
// État
|
|
const ips = ref([])
|
|
const selectedIP = ref(null)
|
|
const loading = ref(false)
|
|
const error = ref(null)
|
|
const stats = ref({
|
|
total: 0,
|
|
online: 0,
|
|
offline: 0,
|
|
known: 0,
|
|
unknown: 0
|
|
})
|
|
const lastScanDate = ref(null)
|
|
const scanProgress = ref({
|
|
current: 0,
|
|
total: 0,
|
|
currentIP: null
|
|
})
|
|
const isScanning = ref(false)
|
|
const uiConfig = ref({
|
|
cell_size: 30
|
|
})
|
|
|
|
// Filtres
|
|
const filters = ref({
|
|
showOnline: true,
|
|
showOffline: true,
|
|
showKnown: true,
|
|
showUnknown: true,
|
|
showFree: true
|
|
})
|
|
|
|
// WebSocket
|
|
const ws = ref(null)
|
|
const wsConnected = ref(false)
|
|
|
|
// Computed
|
|
const filteredIPs = computed(() => {
|
|
return ips.value.filter(ip => {
|
|
// Filtrer par statut
|
|
if (ip.last_status === 'online' && !filters.value.showOnline) return false
|
|
if (ip.last_status === 'offline' && !filters.value.showOffline) return false
|
|
|
|
// Filtrer par connu/inconnu
|
|
if (ip.known && !filters.value.showKnown) return false
|
|
if (!ip.known && !filters.value.showUnknown) return false
|
|
|
|
// Filtrer IP libres (pas de last_status)
|
|
if (!ip.last_status && !filters.value.showFree) return false
|
|
|
|
return true
|
|
})
|
|
})
|
|
|
|
// Actions
|
|
async function fetchUIConfig() {
|
|
try {
|
|
const response = await axios.get('/api/config/ui')
|
|
uiConfig.value = response.data
|
|
// Appliquer la taille des cellules, de la police et de l'espacement via variables CSS
|
|
document.documentElement.style.setProperty('--cell-size', `${response.data.cell_size}px`)
|
|
document.documentElement.style.setProperty('--font-size', `${response.data.font_size}px`)
|
|
document.documentElement.style.setProperty('--cell-gap', `${response.data.cell_gap}px`)
|
|
} catch (err) {
|
|
console.error('Erreur chargement config UI:', err)
|
|
}
|
|
}
|
|
|
|
async function reloadConfig() {
|
|
try {
|
|
const response = await axios.post('/api/config/reload')
|
|
if (response.data.success) {
|
|
// Appliquer la nouvelle config UI
|
|
uiConfig.value = response.data.ui
|
|
document.documentElement.style.setProperty('--cell-size', `${response.data.ui.cell_size}px`)
|
|
document.documentElement.style.setProperty('--font-size', `${response.data.ui.font_size}px`)
|
|
document.documentElement.style.setProperty('--cell-gap', `${response.data.ui.cell_gap}px`)
|
|
return response.data.message
|
|
}
|
|
} catch (err) {
|
|
console.error('Erreur rechargement config:', err)
|
|
throw err
|
|
}
|
|
}
|
|
|
|
async function fetchIPs() {
|
|
loading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
const response = await axios.get('/api/ips/')
|
|
ips.value = response.data
|
|
await fetchStats()
|
|
} catch (err) {
|
|
error.value = err.message
|
|
console.error('Erreur chargement IPs:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function fetchStats() {
|
|
try {
|
|
const response = await axios.get('/api/ips/stats/summary')
|
|
stats.value = response.data
|
|
} catch (err) {
|
|
console.error('Erreur chargement stats:', err)
|
|
}
|
|
}
|
|
|
|
async function updateIP(ipAddress, data) {
|
|
try {
|
|
const response = await axios.put(`/api/ips/${ipAddress}`, data)
|
|
|
|
// Mettre à jour dans le store
|
|
const index = ips.value.findIndex(ip => ip.ip === ipAddress)
|
|
if (index !== -1) {
|
|
ips.value[index] = response.data
|
|
}
|
|
|
|
if (selectedIP.value?.ip === ipAddress) {
|
|
selectedIP.value = response.data
|
|
}
|
|
|
|
return response.data
|
|
} catch (err) {
|
|
error.value = err.message
|
|
throw err
|
|
}
|
|
}
|
|
|
|
async function deleteIP(ipAddress) {
|
|
try {
|
|
await axios.delete(`/api/ips/${ipAddress}`)
|
|
|
|
// Retirer du store
|
|
const index = ips.value.findIndex(ip => ip.ip === ipAddress)
|
|
if (index !== -1) {
|
|
ips.value.splice(index, 1)
|
|
}
|
|
|
|
if (selectedIP.value?.ip === ipAddress) {
|
|
selectedIP.value = null
|
|
}
|
|
|
|
await fetchStats()
|
|
} catch (err) {
|
|
error.value = err.message
|
|
throw err
|
|
}
|
|
}
|
|
|
|
async function getIPHistory(ipAddress, hours = 24) {
|
|
try {
|
|
const response = await axios.get(`/api/ips/${ipAddress}/history?hours=${hours}`)
|
|
return response.data
|
|
} catch (err) {
|
|
console.error('Erreur chargement historique:', err)
|
|
throw err
|
|
}
|
|
}
|
|
|
|
async function startScan() {
|
|
try {
|
|
await axios.post('/api/scan/start')
|
|
} catch (err) {
|
|
error.value = err.message
|
|
throw err
|
|
}
|
|
}
|
|
|
|
function selectIP(ip) {
|
|
selectedIP.value = ip
|
|
}
|
|
|
|
function clearSelection() {
|
|
selectedIP.value = null
|
|
}
|
|
|
|
// WebSocket
|
|
function connectWebSocket() {
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
const wsUrl = `${protocol}//${window.location.host}/ws`
|
|
|
|
ws.value = new WebSocket(wsUrl)
|
|
|
|
ws.value.onopen = () => {
|
|
console.log('WebSocket connecté')
|
|
wsConnected.value = true
|
|
|
|
// Heartbeat toutes les 30s
|
|
setInterval(() => {
|
|
if (ws.value?.readyState === WebSocket.OPEN) {
|
|
ws.value.send('ping')
|
|
}
|
|
}, 30000)
|
|
}
|
|
|
|
ws.value.onmessage = (event) => {
|
|
try {
|
|
const message = JSON.parse(event.data)
|
|
handleWebSocketMessage(message)
|
|
} catch (err) {
|
|
console.error('Erreur parsing WebSocket:', err)
|
|
}
|
|
}
|
|
|
|
ws.value.onerror = (error) => {
|
|
console.error('Erreur WebSocket:', error)
|
|
wsConnected.value = false
|
|
}
|
|
|
|
ws.value.onclose = () => {
|
|
console.log('WebSocket déconnecté')
|
|
wsConnected.value = false
|
|
|
|
// Reconnexion après 5s
|
|
setTimeout(connectWebSocket, 5000)
|
|
}
|
|
}
|
|
|
|
function handleWebSocketMessage(message) {
|
|
console.log('Message WebSocket:', message)
|
|
|
|
switch (message.type) {
|
|
case 'scan_start':
|
|
// Notification début de scan
|
|
isScanning.value = true
|
|
scanProgress.value = {
|
|
current: 0,
|
|
total: message.total || 0,
|
|
currentIP: null
|
|
}
|
|
break
|
|
|
|
case 'scan_progress':
|
|
// Progression du scan
|
|
if (message.current) scanProgress.value.current = message.current
|
|
if (message.total) scanProgress.value.total = message.total
|
|
if (message.ip) scanProgress.value.currentIP = message.ip
|
|
break
|
|
|
|
case 'scan_complete':
|
|
// Rafraîchir les données après scan
|
|
isScanning.value = false
|
|
lastScanDate.value = new Date()
|
|
scanProgress.value = { current: 0, total: 0, currentIP: null }
|
|
fetchIPs()
|
|
if (message.stats) stats.value = message.stats
|
|
break
|
|
|
|
case 'ip_update':
|
|
// Mise à jour d'une IP
|
|
const updatedIP = ips.value.find(ip => ip.ip === message.data.ip)
|
|
if (updatedIP) {
|
|
Object.assign(updatedIP, message.data)
|
|
}
|
|
break
|
|
|
|
case 'new_ip':
|
|
// Nouvelle IP détectée
|
|
fetchIPs() // Recharger pour être sûr
|
|
break
|
|
}
|
|
}
|
|
|
|
function disconnectWebSocket() {
|
|
if (ws.value) {
|
|
ws.value.close()
|
|
ws.value = null
|
|
wsConnected.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
// État
|
|
ips,
|
|
selectedIP,
|
|
loading,
|
|
error,
|
|
stats,
|
|
filters,
|
|
wsConnected,
|
|
lastScanDate,
|
|
scanProgress,
|
|
isScanning,
|
|
uiConfig,
|
|
|
|
// Computed
|
|
filteredIPs,
|
|
|
|
// Actions
|
|
fetchUIConfig,
|
|
reloadConfig,
|
|
fetchIPs,
|
|
fetchStats,
|
|
updateIP,
|
|
deleteIP,
|
|
getIPHistory,
|
|
startScan,
|
|
selectIP,
|
|
clearSelection,
|
|
connectWebSocket,
|
|
disconnectWebSocket
|
|
}
|
|
})
|