feat: introduce Vue Bootstrap interface and scoped router network status
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import {
|
||||
deviceView,
|
||||
snapshot,
|
||||
bridge,
|
||||
accessLabel,
|
||||
} from "../composables/bridge.js";
|
||||
import AppIcon from "./AppIcon.vue";
|
||||
import NetworkStatus from "./NetworkStatus.vue";
|
||||
const home = computed(() =>
|
||||
(snapshot.value.state.households || []).find(
|
||||
(h) => h.id === snapshot.value.state.familyId,
|
||||
),
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<div id="device-topology" hidden>
|
||||
<section class="panel network-map">
|
||||
<div class="network-platform">
|
||||
<AppIcon name="network" />
|
||||
<div>
|
||||
<h3>{{ home?.name || "当前场所" }}</h3>
|
||||
<p>{{ deviceView.devices.length }} 台设备 · 随设备档案自动更新</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="description">
|
||||
连线来自已确认的上级设备关系。上级未填写时单独列出;不代表已自动发现所有交换机或布线。
|
||||
</p>
|
||||
<div class="topology-nodes">
|
||||
<article
|
||||
v-for="row in deviceView.rows"
|
||||
:key="row.device.id"
|
||||
class="network-node card"
|
||||
:class="{ nested: row.depth > 0 }"
|
||||
:style="{ '--depth': Math.min(row.depth, 5) }"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="device-card-heading">
|
||||
<AppIcon
|
||||
:name="row.device.source === 'camera' ? 'camera' : 'router'"
|
||||
/>
|
||||
<div class="flex-grow-1">
|
||||
<span class="small text-secondary"
|
||||
>{{ row.device.deviceType }} ·
|
||||
{{ accessLabel(row.device.networkAccess) }}</span
|
||||
>
|
||||
<h3>
|
||||
<button
|
||||
class="device-title"
|
||||
@click="
|
||||
bridge().enterDevice(row.device.source, row.device.id)
|
||||
"
|
||||
>
|
||||
{{ row.device.name }}
|
||||
</button>
|
||||
</h3>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
@click="
|
||||
bridge().enterDevice(
|
||||
row.device.source,
|
||||
row.device.id,
|
||||
'device',
|
||||
)
|
||||
"
|
||||
>
|
||||
详情 →
|
||||
</button>
|
||||
</div>
|
||||
<p class="device-location">
|
||||
{{ bridge().location?.(row.device.siteId) || "未指定区域" }}
|
||||
<template v-if="row.device.point">
|
||||
· {{ row.device.point }}</template
|
||||
>
|
||||
</p>
|
||||
<div class="network-facts">
|
||||
<span
|
||||
>IP
|
||||
<b>{{
|
||||
row.device.networkHosts.join(" / ") || "待填写"
|
||||
}}</b></span
|
||||
><span v-if="row.device.tailscaleHost"
|
||||
>Tailscale <b>{{ row.device.tailscaleHost }}</b></span
|
||||
><span v-if="row.device.networkCidr"
|
||||
>网段 <b>{{ row.device.networkCidr }}</b></span
|
||||
><span
|
||||
>上级 <b>{{ row.parentName || "待确认 / 直接接入" }}</b></span
|
||||
><span
|
||||
>连接
|
||||
<b>{{
|
||||
{ wired: "网线", wifi: "Wi-Fi" }[row.device.connectionType] ||
|
||||
"待确认"
|
||||
}}</b></span
|
||||
><span v-if="row.via.length"
|
||||
>取流经录像机 <b>{{ row.via.join("、") }}</b></span
|
||||
><span v-if="row.archiveVia.length"
|
||||
>录像归档 <b>{{ row.archiveVia.join("、") }}</b></span
|
||||
>
|
||||
</div>
|
||||
<NetworkStatus
|
||||
v-if="/路由|网关|服务器/.test(row.device.deviceType)"
|
||||
:device="row.device"
|
||||
:active="
|
||||
snapshot.page === 'objects' && deviceView.mode === 'topology'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</article>
|
||||
<p v-if="!deviceView.rows.length" class="empty">
|
||||
当前范围尚未登记设备。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user