154 lines
4.9 KiB
Vue
154 lines
4.9 KiB
Vue
<script setup>
|
||
import {
|
||
deviceView,
|
||
snapshot,
|
||
bridge,
|
||
accessLabel,
|
||
} from "../composables/bridge.js";
|
||
import AppIcon from "./AppIcon.vue";
|
||
import NetworkStatus from "./NetworkStatus.vue";
|
||
const channels = (d) =>
|
||
(snapshot.value.state.cameras || []).filter((c) =>
|
||
d.source === "camera"
|
||
? c.assetId === d.id
|
||
: c.recorderId === d.id || c.archiveRecorderId === d.id,
|
||
);
|
||
const editAttrs = (d) => ({
|
||
["data-" +
|
||
(d.source === "camera"
|
||
? "edit-asset"
|
||
: d.source === "recorder"
|
||
? "edit-recorder"
|
||
: "edit-device")]: d.id,
|
||
});
|
||
const monitored = (d) =>
|
||
/路由|网关|服务器/.test(d.deviceType) || /gl\.inet/i.test(d.brand || "");
|
||
</script>
|
||
<template>
|
||
<div id="asset-list">
|
||
<section
|
||
v-for="group in deviceView.groups"
|
||
:key="group.key"
|
||
class="device-group"
|
||
>
|
||
<h3 class="group-title">
|
||
{{ group.labels.join(" / ") || "全部设备" }}
|
||
<span class="count-pill">{{ group.items.length }}</span>
|
||
</h3>
|
||
<div class="device-card-grid">
|
||
<article
|
||
v-for="d in group.items"
|
||
:key="d.source + d.id"
|
||
class="card device-card"
|
||
>
|
||
<div class="card-body">
|
||
<div class="device-card-heading">
|
||
<div class="device-symbol">
|
||
<AppIcon
|
||
:name="
|
||
d.source === 'camera'
|
||
? 'camera'
|
||
: monitored(d)
|
||
? 'router'
|
||
: 'devices'
|
||
"
|
||
/>
|
||
</div>
|
||
<div class="flex-grow-1">
|
||
<span class="small text-secondary">{{ d.deviceType }}</span>
|
||
<h3>
|
||
<button
|
||
class="device-title"
|
||
@click="bridge().enterDevice(d.source, d.id)"
|
||
>
|
||
{{ d.name }}
|
||
</button>
|
||
</h3>
|
||
</div>
|
||
<button
|
||
v-if="snapshot.admin"
|
||
class="btn btn-sm btn-outline-secondary"
|
||
v-bind="editAttrs(d)"
|
||
>
|
||
编辑
|
||
</button>
|
||
</div>
|
||
<p class="device-location">
|
||
{{ bridge().location?.(d.siteId) || "区域待填写"
|
||
}}<template v-if="d.point"> · {{ d.point }}</template>
|
||
</p>
|
||
<dl class="compact-details">
|
||
<div>
|
||
<dt>品牌型号</dt>
|
||
<dd>
|
||
{{
|
||
[d.brand, d.model].filter(Boolean).join(" / ") || "未填写"
|
||
}}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>设备地址</dt>
|
||
<dd class="font-monospace">
|
||
{{ d.networkHosts.join(" / ") || "未填写" }}
|
||
</dd>
|
||
</div>
|
||
<div>
|
||
<dt>网络</dt>
|
||
<dd>{{ accessLabel(d.networkAccess) }}</dd>
|
||
</div>
|
||
<div>
|
||
<dt>所有人 / 负责人</dt>
|
||
<dd>
|
||
{{ d.ownerName || "待指定" }} /
|
||
{{ d.managerName || "待指定" }}
|
||
</dd>
|
||
</div>
|
||
<div v-if="d.source !== 'device'">
|
||
<dt>镜头通道</dt>
|
||
<dd>{{ channels(d).length }} 个已配置</dd>
|
||
</div>
|
||
</dl>
|
||
<div v-if="d.tags?.length" class="device-tags">
|
||
<span v-for="tag in d.tags" :key="tag">{{ tag }}</span>
|
||
</div>
|
||
<NetworkStatus
|
||
v-if="monitored(d)"
|
||
:device="d"
|
||
:active="
|
||
snapshot.page === 'objects' && deviceView.mode === 'cards'
|
||
"
|
||
/>
|
||
</div>
|
||
<div class="card-footer device-card-actions">
|
||
<button
|
||
class="btn btn-sm btn-outline-secondary"
|
||
@click="bridge().enterDevice(d.source, d.id, 'device')"
|
||
>
|
||
设备详情</button
|
||
><template v-if="d.source !== 'device'"
|
||
><button
|
||
v-if="snapshot.admin"
|
||
class="btn btn-sm btn-outline-secondary"
|
||
@click="bridge().enterDevice(d.source, d.id, 'cameras')"
|
||
>
|
||
配置镜头</button
|
||
><button
|
||
v-if="channels(d).length"
|
||
class="btn btn-sm btn-primary"
|
||
@click="bridge().enterDevice(d.source, d.id, 'live')"
|
||
>
|
||
实时画面
|
||
</button></template
|
||
>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
<div v-if="!deviceView.devices.length" class="empty">
|
||
<AppIcon name="devices" />
|
||
<h3>当前范围没有设备</h3>
|
||
<p>调整筛选条件,或添加摄像机、路由器、灯等设备。</p>
|
||
</div>
|
||
</div>
|
||
</template>
|