diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index 4ac42c3..c930316 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -19,6 +19,16 @@ const stats = ref([ const userCount = ref(null) let statsTimer: ReturnType | null = null +interface ClientInfo { + user_id: number + username: string + ip: string + ip6?: string + connected_at: string +} +const vpnClients = ref([]) +const kickError = ref('') + function formatUptime(seconds: number): string { if (seconds <= 0) return '0m' const d = Math.floor(seconds / 86400) @@ -61,11 +71,42 @@ async function fetchStats() { } catch {} } +async function fetchVpnStatus() { + try { + const res = await fetch('/api/admin/vpn/status', { + headers: { Authorization: `Bearer ${authStore.token}` }, + }) + if (!res.ok) return + const data = await res.json() + vpnClients.value = data.clients || [] + } catch {} +} + +async function handleKick(userId: number, username: string) { + if (!confirm(t('vpn.confirmKick', { username }))) return + kickError.value = '' + try { + const res = await fetch(`/api/admin/vpn/clients/${userId}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${authStore.token}` }, + }) + const data = await res.json() + if (!res.ok) throw new Error(data.error || t('vpn.kickFailed')) + await fetchVpnStatus() + } catch (e: any) { + kickError.value = e.message + } +} + onMounted(async () => { await authStore.fetchUser() fetchUserCount() fetchStats() - statsTimer = setInterval(fetchStats, 30000) + fetchVpnStatus() + statsTimer = setInterval(() => { + fetchStats() + fetchVpnStatus() + }, 30000) }) onUnmounted(() => { @@ -75,11 +116,6 @@ onUnmounted(() => { function handleStatClick(route: string) { if (route) router.push(route) } - -function handleLogout() { - authStore.logout() - router.push('/') -} diff --git a/frontend/src/views/VpnView.vue b/frontend/src/views/VpnView.vue index 22636f9..e7f786f 100644 --- a/frontend/src/views/VpnView.vue +++ b/frontend/src/views/VpnView.vue @@ -202,21 +202,6 @@ async function handleDeleteResv(id: number) { } } -async function handleKick(userId: number, username: string) { - if (!confirm(t('vpn.confirmKick', { username }))) return - try { - const res = await fetch(`/api/admin/vpn/clients/${userId}`, { - method: 'DELETE', - headers: authHeader(), - }) - const data = await res.json() - if (!res.ok) throw new Error(data.error || t('vpn.kickFailed')) - await fetchStatus() - } catch (e: any) { - error.value = e.message - } -} - function checkTunCreate(): boolean | null { if (!diag.value) return null return diag.value.tun_create.startsWith('ok') @@ -431,41 +416,6 @@ onMounted(() => { - -
-

{{ t('vpn.onlineClients') }}

- - - - - - - - - - - - - - - - - - - - - - -
{{ t('vpn.user') }}{{ t('vpn.ipv4') }}{{ t('vpn.ipv6') }}{{ t('vpn.connectTime') }}{{ t('common.actions') }}
{{ t('vpn.noOnlineClients') }}
{{ c.username }}{{ c.ip }}{{ c.ip6 || '—' }}{{ c.connected_at }} - -
-
-