118 lines
4.0 KiB
Vue
118 lines
4.0 KiB
Vue
<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>
|