| New file |
| | |
| | | <template> |
| | | <div class="drone-card"> |
| | | <div class="header"> |
| | | <div class="title"> |
| | | <span class="name">{{ data.droneName }}</span> |
| | | <span class="status"> |
| | | <span :class="getStatusType(data)"> |
| | | |
| | | </span> |
| | | |
| | | <span> |
| | | {{ getStatusText(data) }} |
| | | </span> |
| | | </span> |
| | | </div> |
| | | |
| | | <div class="actions"> |
| | | <span class="star" @click="emit('favorite')"> |
| | | {{ data.isFavorite ? '★' : '☆' }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="content"> |
| | | <div> |
| | | <span class="label">序列号</span> |
| | | {{ data.droneSerialNo }} |
| | | </div> |
| | | <div> |
| | | <span class="label">数据源</span> |
| | | {{ getDataSource(data) }} |
| | | </div> |
| | | <div> |
| | | <span class="label">经纬度</span> |
| | | {{ data.longitude }}, {{ data.latitude }} |
| | | </div> |
| | | <div class="row"> |
| | | <div class="col"> |
| | | <span class="label">信号频段</span> |
| | | {{ formatFrequency(data.signalFreqMhz) }} |
| | | </div> |
| | | <div class="col"> |
| | | <span class="label">发现时间</span> |
| | | {{ getAlarmTime(data.alarmTime) }} |
| | | </div> |
| | | </div> |
| | | <div class="row"> |
| | | <div class="col"> |
| | | <span class="label">飞行高度</span> |
| | | {{ formatHeight(data.flightHeightM) }} |
| | | </div> |
| | | <div class="col"> |
| | | <span class="label">飞行速度</span> |
| | | {{ formatSpeed(data.flightSpeedMs) }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="footer"> |
| | | <el-button class="general" color="#2B2B4C" @click="emit('signal')">信号干扰</el-button> |
| | | <el-button color="#284FE3" type="primary" @click="emit('counter')">诱导驱离</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | const props = defineProps({ |
| | | data: { |
| | | type: Object, |
| | | required: true, |
| | | default: () => ({}) |
| | | } |
| | | }) |
| | | |
| | | const emit = defineEmits(['signal', 'counter', 'favorite']) |
| | | |
| | | const getStatusText = (item) => { |
| | | const status = item?.flightStatus |
| | | if (status === 1 || status === '1') return '侦测中' |
| | | if (status === 2 || status === '2') return '反制中' |
| | | return status || '侦测中' |
| | | } |
| | | |
| | | const getStatusType = (item) => { |
| | | const statusText = getStatusText(item) |
| | | const counterWay = item?.counterWay |
| | | if (statusText.includes('反制') || counterWay === 2 || counterWay === '2' || counterWay === '诱导驱离') { |
| | | return 'countering' |
| | | } |
| | | return 'detecting' |
| | | } |
| | | |
| | | const getDataSource = (item) => { |
| | | return item?.deviceName || item?.areaName || '-' |
| | | } |
| | | |
| | | const formatFrequency = (value) => { |
| | | if (value == null || value === '') return '-' |
| | | return `${value}MHz` |
| | | } |
| | | |
| | | const getAlarmTime = (value) => { |
| | | if (!value) return '-' |
| | | const parts = value.replace('T', ' ').split(' ') |
| | | return parts[1] || value |
| | | } |
| | | |
| | | const formatHeight = (value) => { |
| | | if (value == null || value === '') return '-' |
| | | return `${value}m` |
| | | } |
| | | |
| | | const formatSpeed = (value) => { |
| | | if (value == null || value === '') return '-' |
| | | return `${value}m/s` |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .drone-card { |
| | | margin-top: 10px; |
| | | padding: 10px; |
| | | color: #fff; |
| | | background: #191933; |
| | | border-radius: 6px 6px 6px 6px; |
| | | |
| | | &:hover { |
| | | background: #29294D; |
| | | ; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | |
| | | .name { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #FFFFFF; |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | |
| | | .status { |
| | | padding: 0 10px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | height: 21px; |
| | | |
| | | background: #303041; |
| | | border-radius: 10px; |
| | | gap: 6px; |
| | | |
| | | span { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 10px; |
| | | color: #FFFFFF; |
| | | text-align: center; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | |
| | | |
| | | span.detecting { |
| | | width: 4px; |
| | | height: 4px; |
| | | background: #18FF4A; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | span.countering { |
| | | width: 4px; |
| | | height: 4px; |
| | | background: #FF4444; |
| | | border-radius: 50%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | font-size: 16px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | .content { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #9E9EBA; |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | |
| | | &>div { |
| | | margin-top: 10px; |
| | | line-height: 22px; |
| | | |
| | | span.label { |
| | | margin-right: 10px; |
| | | color: #D4D5D7; |
| | | } |
| | | } |
| | | |
| | | .row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | |
| | | .footer { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | margin-top: 10px; |
| | | |
| | | ::v-deep(.el-button) { |
| | | width: 96px; |
| | | height: 36px; |
| | | |
| | | &.general.el-button { |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid rgba(255, 255, 255, 0.5); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |