first commit
This commit is contained in:
151
frontend/src/components/NetworkPanel.vue
Normal file
151
frontend/src/components/NetworkPanel.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
import type { NetworkTelemetry } from '@/types'
|
||||
|
||||
const props = defineProps<{
|
||||
network: NetworkTelemetry | null
|
||||
}>()
|
||||
|
||||
const updatedAt = computed(() => {
|
||||
if (!props.network?.updated_at) {
|
||||
return '暂无'
|
||||
}
|
||||
return new Date(props.network.updated_at).toLocaleString('zh-CN', { hour12: false })
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="panel network-panel">
|
||||
<div class="panel-head">
|
||||
<div>
|
||||
<p class="eyebrow">Network</p>
|
||||
<h2>链路状态</h2>
|
||||
</div>
|
||||
<span class="badge">{{ network?.peer_status ?? 'loading' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<span>延迟</span>
|
||||
<strong>{{ network?.latency_ms ?? '--' }} ms</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span>抖动</span>
|
||||
<strong>{{ network?.jitter_ms ?? '--' }} ms</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span>丢包率</span>
|
||||
<strong>{{ network?.packet_loss_pct ?? '--' }} %</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span>信号强度</span>
|
||||
<strong>{{ network?.signal_dbm ?? '--' }} dBm</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span>发送速率</span>
|
||||
<strong>{{ network?.tx_kbps ?? '--' }} kbps</strong>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span>接收速率</span>
|
||||
<strong>{{ network?.rx_kbps ?? '--' }} kbps</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary">
|
||||
<p><strong>来源:</strong>{{ network?.transport ?? '暂无' }} / {{ network?.source_mode ?? '暂无' }}</p>
|
||||
<p><strong>刷新:</strong>{{ updatedAt }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.network-panel {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 4px;
|
||||
color: #4dd4ac;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
padding: 8px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(40, 199, 111, 0.16);
|
||||
color: #63e6a9;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
background: rgba(7, 14, 26, 0.78);
|
||||
border: 1px solid rgba(133, 147, 169, 0.2);
|
||||
}
|
||||
|
||||
.stat-card span {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #8d99b3;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.stat-card strong {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
background: rgba(7, 14, 26, 0.78);
|
||||
border: 1px solid rgba(133, 147, 169, 0.2);
|
||||
color: #d5dbee;
|
||||
}
|
||||
|
||||
.summary p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.summary p + p {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.stats {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user