<template>
|
<div v-if="visible" class="device-popup" :style="popupStyle" @click.stop>
|
<div class="device-popup__header">
|
<el-tooltip
|
class="device-popup__title-tooltip"
|
:content="popupTitle"
|
placement="top"
|
effect="dark"
|
:show-after="200"
|
>
|
<span class="device-popup__title">{{ popupTitleDisplay }}</span>
|
</el-tooltip>
|
|
<img class="device-popup__close" :src="popupClose" alt="" @click.stop="emit('close')" />
|
</div>
|
<div class="device-popup__type">
|
<span class="value">{{ popupTypeText }}</span>
|
</div>
|
|
<div class="device-popup__subtitle">
|
<span class="device-popup__dot" :class="popupActionClass"></span>
|
<span class="device-popup__action">{{ popupActionText }}</span>
|
</div>
|
|
<div class="device-popup__rows">
|
<div class="device-popup__row">
|
<div class="device-popup__col">
|
<span class="label">状态</span>
|
<span class="value" :class="popupStatusClass">{{ popupStatusText }}</span>
|
</div>
|
|
<span class="divider">|</span>
|
|
<div class="device-popup__col">
|
<span class="label">电量</span>
|
<span class="value">{{ popupBatteryText }}</span>
|
</div>
|
</div>
|
<div class="device-popup__row">
|
<div class="device-popup__col">
|
<span class="label">方位角</span>
|
<span class="value">{{ popupAzimuthText }}</span>
|
</div>
|
|
<span class="divider">|</span>
|
|
<div class="device-popup__col">
|
<span class="label">俯仰角</span>
|
<span class="value">{{ popupElevationText }}</span>
|
</div>
|
</div>
|
<div class="device-popup__row">
|
<span class="label">侦测目标</span>
|
<span class="value">{{ popupDetectCountText }}</span>
|
</div>
|
<div class="device-popup__row">
|
<span class="label">有效范围</span>
|
<span class="value">{{ popupRangeText }}</span>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed } from 'vue'
|
import popupClose from '@/assets/images/dataCockpit/map/popup-close.png'
|
|
const props = defineProps({
|
visible: {
|
type: Boolean,
|
default: false,
|
},
|
position: {
|
type: Object,
|
default: () => ({ x: 0, y: 0 }),
|
},
|
device: {
|
type: Object,
|
default: () => ({}),
|
},
|
titleMax: {
|
type: Number,
|
default: 12,
|
},
|
})
|
|
const emit = defineEmits(['close'])
|
|
const popupStyle = computed(() => ({
|
left: `${props.position?.x ?? 0}px`,
|
top: `${props.position?.y ?? 0}px`,
|
}))
|
|
const popupTitle = computed(() => props.device?.deviceName || props.device?.deviceModel || '-')
|
const popupTitleOverflow = computed(() => popupTitle.value.length > props.titleMax)
|
const popupTitleDisplay = computed(() => {
|
if (!popupTitleOverflow.value) return popupTitle.value
|
return `${popupTitle.value.slice(0, props.titleMax)}……`
|
})
|
|
const popupStatusText = computed(() => {
|
const status = props.device?.status
|
if (status === 0) return '在线'
|
if (status === 1) return '离线'
|
if (status === 2) return '故障'
|
if (status === 3) return '报废'
|
return '-'
|
})
|
const popupStatusClass = computed(() => (props.device?.status === 0 ? 'online' : ''))
|
const popupActionText = computed(() => {
|
const workMode = props.device?.workMode
|
if (workMode === 1 || workMode === '1') return '侦测中'
|
if (workMode === 2 || workMode === '2') return '信号干扰中'
|
if (workMode === 3 || workMode === '3') return '诱导驱离中'
|
if (workMode === 4 || workMode === '4') return '待机'
|
return workMode || '-'
|
})
|
const popupActionClass = computed(() => {
|
const workMode = props.device?.workMode
|
if (workMode === 1 || workMode === '1') return 'is-detecting'
|
if (workMode === 2 || workMode === '2') return 'is-jamming'
|
if (workMode === 3 || workMode === '3') return 'is-driving'
|
if (workMode === 4 || workMode === '4') return 'is-standby'
|
return 'is-standby'
|
})
|
const popupTypeText = computed(() => {
|
const type = props.device?.deviceType
|
if (type === 1 || type === '1') return '便捷侦测箱'
|
if (type === 2 || type === '2') return '反制枪'
|
if (type === 3 || type === '3') return '察打一体'
|
return type || '-'
|
})
|
const popupBatteryText = computed(() => {
|
const val = props.device?.batteryPct
|
if (val == null) return '-'
|
return `${val}%`
|
})
|
const popupAzimuthText = computed(() => {
|
const val = props.device?.azimuth
|
if (val == null) return '-'
|
return `${val}°`
|
})
|
const popupElevationText = computed(() => {
|
const val = props.device?.elevation
|
if (val == null) return '-'
|
return `${val}°`
|
})
|
const popupDetectCountText = computed(() => {
|
const val = props.device?.detectTargetCnt
|
if (val == null) return '-'
|
return `${val}台`
|
})
|
const popupRangeText = computed(() => {
|
const val = Number(props.device?.effectiveRangeKm).toFixed(0) || 0
|
if (val == null) return '-'
|
return `${val}m`
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.device-popup {
|
position: absolute;
|
transform: translate(-50%, calc(-100% - 72px));
|
width: 202px;
|
padding: 0 16px 20px;
|
border-radius: 16px;
|
background: rgba(5, 5, 15, 0.7);
|
backdrop-filter: blur(16px);
|
color: #C3C3DD;
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-size: 12px;
|
pointer-events: auto;
|
z-index: 11;
|
box-sizing: border-box;
|
|
&::after {
|
content: "";
|
position: absolute;
|
left: 50%;
|
bottom: -8px;
|
transform: translateX(-50%);
|
width: 0;
|
height: 0;
|
border-left: 8px solid transparent;
|
border-right: 8px solid transparent;
|
border-top: 8px solid rgba(5, 5, 15, 0.7);
|
}
|
|
.device-popup__header {
|
height: 40px;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
position: relative;
|
|
font-weight: bold;
|
font-size: 14px;
|
color: #FFFFFF;
|
|
&::after {
|
content: "";
|
position: absolute;
|
left: 0;
|
bottom: 0;
|
width: 50px;
|
height: 2px;
|
background: #284FE3;
|
box-shadow: 0px 3px 2px 0px rgba(15, 89, 255, 0.1), 0px 7px 5px 0px rgba(15, 89, 255, 0.15), 0px 13px 10px 0px rgba(15, 89, 255, 0.18), 0px 22px 18px 0px rgba(15, 89, 255, 0.21), 0px 42px 33px 0px rgba(15, 89, 255, 0.26), 0px 100px 80px 0px rgba(15, 89, 255, 0.36);
|
border-radius: 5px 5px 0px 0px;
|
}
|
|
&::before {
|
content: "";
|
position: absolute;
|
left: 55px;
|
right: 0;
|
bottom: 0;
|
height: 2px;
|
background: #323245;
|
border-radius: 0px 0px 5px 5px;
|
}
|
|
.device-popup__title-tooltip {
|
flex: 1;
|
min-width: 0;
|
display: block;
|
}
|
|
.device-popup__title {
|
display: inline-block;
|
max-width: 100%;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
.device-popup__close {
|
cursor: pointer;
|
}
|
}
|
|
.device-popup__type {
|
display: flex;
|
align-items: center;
|
gap: 6px;
|
font-size: 12px;
|
margin-top: 8px;
|
margin-bottom: 10px;
|
color: #d2d7df;
|
|
.label {
|
color: #9aa4b2;
|
}
|
}
|
|
.device-popup__subtitle {
|
display: inline-flex;
|
align-items: center;
|
gap: 6px;
|
padding: 2px 10px;
|
border-radius: 999px;
|
background: rgba(255, 255, 255, 0.06);
|
font-size: 12px;
|
margin-bottom: 10px;
|
|
.device-popup__dot {
|
width: 6px;
|
height: 6px;
|
border-radius: 50%;
|
background: #6b7685;
|
|
&.is-detecting {
|
background: #35f08c;
|
box-shadow: 0 0 6px rgba(53, 240, 140, 0.8);
|
}
|
|
&.is-jamming {
|
background: #ff4444;
|
box-shadow: 0 0 6px rgba(255, 68, 68, 0.7);
|
}
|
|
&.is-driving {
|
background: #ffb020;
|
box-shadow: 0 0 6px rgba(255, 176, 32, 0.7);
|
}
|
|
&.is-standby {
|
background: #9aa4b2;
|
}
|
}
|
}
|
|
.device-popup__rows {
|
display: flex;
|
flex-direction: column;
|
gap: 6px;
|
font-size: 12px;
|
color: #d2d7df;
|
|
.device-popup__row {
|
display: flex;
|
align-items: center;
|
margin-bottom: 10px;
|
|
.device-popup__col {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
|
&:last-child {
|
justify-content: flex-end;
|
}
|
}
|
}
|
|
.value {
|
margin-left: 10px;
|
}
|
|
.value.online {
|
color: #35f08c;
|
}
|
}
|
}
|
</style>
|