You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.4 KiB
107 lines
3.4 KiB
<template>
|
|
<aside class="device-panel">
|
|
<div class="panel-heading">
|
|
<div><h1>设备列表</h1><span>{{ dockCount }} 巢 · {{ droneCount }} 机</span></div>
|
|
<button class="icon-button" title="收起面板" @click="emit('clear-selection')"><svg><use href="#i-x" /></svg></button>
|
|
</div>
|
|
|
|
<div class="device-search">
|
|
<t-input v-model="searchModel" clearable placeholder="搜索机巢或无人机">
|
|
<template #prefix-icon><t-icon name="search" /></template>
|
|
</t-input>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<button class="filter" :class="{ active: filter === 'all' }" @click="emit('update:filter', 'all')">全部 <b>{{ filterCounts.all }}</b></button>
|
|
<button class="filter" :class="{ active: filter === 'online' }" @click="emit('update:filter', 'online')">在线 <b>{{ filterCounts.online }}</b></button>
|
|
<button class="filter" :class="{ active: filter === 'alarm' }" @click="emit('update:filter', 'alarm')">告警 <b>{{ filterCounts.alarm }}</b></button>
|
|
</div>
|
|
<div v-if="docks.length" class="multi-select-bar" :class="{ 'has-selection': selectedSize }">
|
|
<span>已选择 {{ selectedSize }} 个机巢</span>
|
|
<button type="button" @click="emit('select-all')">全选</button>
|
|
<button type="button" @click="emit('clear-dock-selection')">取消选择</button>
|
|
</div>
|
|
|
|
<div class="device-list">
|
|
<DockDeviceCard
|
|
v-for="dock in docks"
|
|
:key="dock.id"
|
|
:dock="dock"
|
|
:active="isDockActive(dock)"
|
|
:multi-selected="selectedDockIds.has(dock.id)"
|
|
:selected-drone-id="selectedId"
|
|
:altitude-of="altitudeOf"
|
|
@select="emit('select', $event)"
|
|
@toggle-select="(id, checked) => emit('toggle-select', id, checked)"
|
|
/>
|
|
<div v-if="!docks.length" class="table-empty" style="height:120px;display:grid;place-items:center;color:var(--muted);font-size:10px">暂无匹配设备</div>
|
|
</div>
|
|
</aside>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
import DockDeviceCard from '@/components/DockDeviceCard.vue'
|
|
|
|
const props = defineProps({
|
|
dockCount: { type: Number, default: 0 },
|
|
droneCount: { type: Number, default: 0 },
|
|
search: { type: String, default: '' },
|
|
filter: { type: String, default: 'all' },
|
|
filterCounts: {
|
|
type: Object,
|
|
default: () => ({ all: 0, online: 0, alarm: 0 }),
|
|
},
|
|
docks: { type: Array, default: () => [] },
|
|
selectedDockIds: {
|
|
type: Object,
|
|
default: () => new Set(),
|
|
},
|
|
selectedId: { type: String, default: null },
|
|
isDockActive: { type: Function, required: true },
|
|
altitudeOf: { type: Function, default: null },
|
|
})
|
|
|
|
const emit = defineEmits([
|
|
'clear-selection',
|
|
'select-all',
|
|
'clear-dock-selection',
|
|
'select',
|
|
'toggle-select',
|
|
'update:search',
|
|
'update:filter',
|
|
])
|
|
|
|
const selectedSize = computed(() => props.selectedDockIds?.size ?? 0)
|
|
|
|
const searchModel = computed({
|
|
get: () => props.search,
|
|
set: (value) => emit('update:search', value ?? ''),
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.device-search {
|
|
height: auto;
|
|
margin-top: 16px;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
}
|
|
.device-search :deep(.t-input) {
|
|
width: 100%;
|
|
}
|
|
.device-select-checkbox {
|
|
width: auto;
|
|
height: auto;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.device-select-checkbox :deep(.t-checkbox) {
|
|
margin: 0;
|
|
}
|
|
.device-select-checkbox :deep(.t-checkbox__input) {
|
|
margin: 0;
|
|
}
|
|
</style>
|
|
|