<template>
|
<div class="g-map-wrapper">
|
<!-- 地图区域 -->
|
<!-- <div id="g-container" :style="{ width: '100%', height: '100%' }" /> -->
|
<Cesium />
|
<!-- 绘制面板 -->
|
<!-- <div class="g-action-panel" :style="{ right: drawVisible ? '316px' : '16px' }">
|
<div :class="state.currentType === 'pin' ? 'g-action-item selection' : 'g-action-item'" @click="draw('pin', true)">
|
<a><a-image :src="pin" :preview="false" /></a>
|
</div>
|
<div :class="state.currentType === 'polyline' ? 'g-action-item selection' : 'g-action-item'"
|
@click="draw('polyline', true)">
|
<a>
|
<LineOutlined :rotate="135" class="fz20" />
|
</a>
|
</div>
|
<div :class="state.currentType === 'polygon' ? 'g-action-item selection' : 'g-action-item'"
|
@click="draw('polygon', true)">
|
<a>
|
<BorderOutlined class="fz18" />
|
</a>
|
</div>
|
<div v-if="mouseMode" class="g-action-item" @click="draw('off', false)">
|
<a style="color: red;">
|
<CloseOutlined />
|
</a>
|
</div>
|
</div> -->
|
<!-- 飞机OSD -->
|
<div v-if="osdVisible.visible && !osdVisible.is_dock" class="osd-panel fz12">
|
<div class="pl5 pr5 flex-align-center flex-row flex-justify-between"
|
style="border-bottom: 1px solid #515151; height: 18%;">
|
<span>{{ osdVisible.callsign }}</span>
|
<span><a class="fz16" style="color: white;" @click="() => osdVisible.visible = false">
|
<CloseOutlined />
|
</a></span>
|
</div>
|
<div style="height: 82%;">
|
<div class="flex-column flex-align-center flex-justify-center"
|
style="margin-top: -5px; padding-top: 25px; float: left; width: 60px; background: #2d2d2d;">
|
<a-tooltip :title="osdVisible.model">
|
<div style="width: 90%;" class="flex-column flex-align-center flex-justify-center">
|
<span><a-image :src="M30" :preview="false" /></span>
|
<span>{{ osdVisible.model }}</span>
|
</div>
|
</a-tooltip>
|
</div>
|
<div class="osd">
|
<a-row>
|
<a-col span="16"
|
:style="deviceInfo.device.mode_code === EModeCode.Disconnected ? 'color: red; font-weight: 700;' : 'color: rgb(25,190,107)'">{{
|
EModeText[deviceInfo.device.mode_code] }}</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="Signal strength">
|
<span>HD</span>
|
<span class="ml5">{{ deviceInfo.gateway?.transmission_signal_quality }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="RC Battery Level">
|
<span>
|
<ThunderboltOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.gateway && deviceInfo.gateway.capacity_percent !== str ?
|
deviceInfo.gateway.capacity_percent + ' %' : deviceInfo.gateway.capacity_percent }}</span>
|
</a-tooltip>
|
</a-col>
|
|
<a-col span="6">
|
<a-tooltip title="无人机电池电量">
|
<span>
|
<ThunderboltOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device.battery.capacity_percent !== str ?
|
deviceInfo.device.battery.capacity_percent + ' %' : deviceInfo.device.battery.capacity_percent }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-tooltip title="RTK固定">
|
<a-col span="6" class="flex-row flex-align-center flex-justify-start">
|
<span>Fixed</span>
|
<span class="ml5 circle"
|
:style="deviceInfo.device.position_state.is_fixed === 1 ? 'backgroud: rgb(25,190,107);' : ' background: red;'"></span>
|
</a-col>
|
</a-tooltip>
|
<a-col span="6">
|
<a-tooltip title="GPS">
|
<span>GPS</span>
|
<span class="ml5">{{ deviceInfo.device.position_state.gps_number }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="RTK">
|
<span>
|
<TrademarkOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device.position_state.rtk_number }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="飞行模式">
|
<span>
|
<ControlOutlined class="fz16" />
|
</span>
|
<span class="ml5">{{ EGear[deviceInfo.device.gear] }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="海拔高度">
|
<span>ASL</span>
|
<span class="ml5">{{ deviceInfo.device.height === str ? str : deviceInfo.device.height.toFixed(2) +
|
'm' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="高于起飞高度">
|
<span>ALT</span>
|
<span class="ml5">{{ deviceInfo.device.elevation === str ? str : deviceInfo.device.elevation.toFixed(2) +
|
'm' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="到起点距离">
|
<span>H</span>
|
<span class="ml5">{{ deviceInfo.device.home_distance === str ? str :
|
deviceInfo.device.home_distance.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="水平速度">
|
<span>H.S</span>
|
<span class="ml5">{{ deviceInfo.device.horizontal_speed === str ? str :
|
deviceInfo.device.horizontal_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="垂直速度">
|
<span>V.S</span>
|
<span class="ml5">{{ deviceInfo.device.vertical_speed === str ? str :
|
deviceInfo.device.vertical_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="风速">
|
<span>W.S</span>
|
<span class="ml5">{{ deviceInfo.device.wind_speed === str ? str : (deviceInfo.device.wind_speed / 10).toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
</div>
|
</div>
|
<div class="battery-slide" v-if="deviceInfo.device.battery.remain_flight_time !== 0">
|
<div style="background: #535759;" class="width-100"></div>
|
<div class="capacity-percent" :style="{ width: deviceInfo.device.battery.capacity_percent + '%' }"></div>
|
<div class="return-home" :style="{ width: deviceInfo.device.battery.return_home_power + '%' }"></div>
|
<div class="landing" :style="{ width: deviceInfo.device.battery.landing_power + '%' }"></div>
|
<div class="white-point" :style="{ left: deviceInfo.device.battery.landing_power + '%' }"></div>
|
<div class="battery" :style="{ left: deviceInfo.device.battery.capacity_percent + '%' }">
|
{{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}:
|
{{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' :
|
'' }}{{ deviceInfo.device.battery.remain_flight_time % 60 }}
|
</div>
|
</div>
|
</div>
|
<!-- 机场OSD -->
|
<!-- && osdVisible.is_dock -->
|
<div class="osd-panel fz12" v-if="osdVisible.visible">
|
<div class="fz16 pr5 flex-align-center flex-row flex-justify-between"
|
style="border-bottom: 1px solid #515151; height: 10%;">
|
<div class="flex-align-center flex-justify-center" style="display: flex;">
|
<div v-if="osdVisible.latest_wayline_job" class="flex-column flex-align-center flex-justify-center">
|
<div class="task_wrapper">
|
<div class="task_content task_content_way" v-if="deviceInfo.device && deviceInfo.device?.mode_code === 5">
|
<div class="task_status">
|
<ContainerOutlined />
|
<span>执行任务中</span>
|
</div>
|
</div>
|
<div class="task_content" v-else>
|
<div class="task_status">
|
<ContainerOutlined />
|
<span>待执行</span>
|
</div>
|
<div class="task_info">{{osdVisible.latest_wayline_job.is_later ? '今天': '明天'}}{{convertTimestampToDate(osdVisible.latest_wayline_job.begin_time, 'hh:mm')}}</div>
|
</div>
|
<div class="task_title">{{osdVisible.latest_wayline_job.name}}</div>
|
</div>
|
</div>
|
<span :style="[osdVisible.latest_wayline_job?'margin-left:20px':'']">{{ osdVisible.gateway_callsign }}</span>
|
</div>
|
<div>
|
<a style="color: white;" @click="closeOsdWindow">
|
<CloseOutlined />
|
</a>
|
</div>
|
</div>
|
<!-- 机场 -->
|
<div class="flex-display" style="border-bottom: 1px solid #515151;">
|
<div class="flex-column flex-align-stretch flex-justify-center" style="width: 60px; background: #2d2d2d;">
|
<a-tooltip :title="osdVisible.gateway_callsign">
|
<div class="flex-column flex-align-center flex-justify-center" style="width: 90%;">
|
<span>
|
<RobotFilled style="font-size: 48px;" />
|
</span>
|
<span class="mt10">Dock</span>
|
</div>
|
</a-tooltip>
|
</div>
|
<div class="osd flex-1" style="flex: 1">
|
<a-row justify="space-between" class="mr-20">
|
<a-col span="9"
|
:style="deviceInfo.dock.basic_osd?.mode_code === EDockModeCode.Disconnected ? 'color: red; font-weight: 700;' : 'color: rgb(25,190,107)'">
|
{{ EDockModeText[deviceInfo.dock.basic_osd?.mode_code] }}</a-col>
|
<!-- <a-col span="1">{{ hmsInfo[sn]?.length || 1 }}</a-col> -->
|
<a-col span="1" class="num" v-if="hmsInfo[sn]">{{ hmsInfo[sn]?.length }}</a-col>
|
<a-col span="14" v-if="hmsInfo[sn] && hmsInfo[sn].length > 0" style="width: 100%;padding-left:5px ;">
|
<a-tooltip :title="hmsInfo[sn][0].message_zh">
|
<div class="overflow">{{ hmsInfo[sn][0].message_zh }}</div>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<!-- <a-col span="12">
|
<a-tooltip title="累计运行时间">
|
<span><HistoryOutlined /></span>
|
<span class="ml5">
|
<span v-if="deviceInfo.dock.work_osd?.acc_time >= 2592000"> {{ Math.floor(deviceInfo.dock.work_osd?.acc_time / 2592000) }}m </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000) >= 86400"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000) / 86400) }}d </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) >= 3600"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) / 3600) }}h </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) >= 60"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) / 60) }}min </span>
|
<span>{{ Math.floor(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600 % 60) }} s</span>
|
</span>
|
</a-tooltip>
|
</a-col> -->
|
<a-col span="9">
|
<a-tooltip title="降雨量">
|
<span>🌧</span>
|
<span class="ml5">{{ RainfallEnum[deviceInfo.dock.basic_osd?.rainfall] }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="15" style="width: 100%;">
|
<div class="env-box span5">
|
<div class="span-box mr-20">
|
<a-tooltip title="环境温度">
|
<span>°C</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.environment_temperature }}</span>
|
</a-tooltip>
|
</div>
|
<div class="span-box mr-20">
|
<a-tooltip title="网络状态">
|
<span
|
:style="deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.ETHERNET || deviceInfo.dock.basic_osd?.network_state?.quality === NetworkStateQualityEnum.GOOD ?
|
'color: #00ee8b' : deviceInfo.dock.basic_osd?.network_state?.quality === NetworkStateQualityEnum.MEDIUM ? 'color: yellow' : 'color: red'">
|
<span v-if="deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.FOUR_G">
|
<SignalFilled />
|
</span>
|
<span v-else>
|
<GlobalOutlined />
|
</span>
|
</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.network_state?.rate }} kb/s</span>
|
</a-tooltip>
|
</div>
|
<div class="span-box mr-20">
|
<a-tooltip title="媒体文件剩余上传">
|
<span>
|
<CloudUploadOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.dock.link_osd?.media_file_detail?.remain_upload }}</span>
|
</a-tooltip>
|
</div>
|
</div>
|
</a-col>
|
<!-- <a-col span="12">
|
<a-tooltip title="激活时间">
|
<span><FieldTimeOutlined /></span>
|
<span class="ml5">{{ new Date((deviceInfo.dock.work_osd?.activation_time ?? 0) * 1000).toLocaleString() }}
|
</span>
|
</a-tooltip>
|
</a-col> -->
|
</a-row>
|
<a-row>
|
<!-- <a-col span="12">
|
<a-tooltip title="累计运行时间">
|
<span><HistoryOutlined /></span>
|
<span class="ml5">
|
<span v-if="deviceInfo.dock.work_osd?.acc_time >= 2592000"> {{ Math.floor(deviceInfo.dock.work_osd?.acc_time / 2592000) }}m </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000) >= 86400"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000) / 86400) }}d </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) >= 3600"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400) / 3600) }}h </span>
|
<span v-if="(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) >= 60"> {{ Math.floor((deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600) / 60) }}min </span>
|
<span>{{ Math.floor(deviceInfo.dock.work_osd?.acc_time % 2592000 % 86400 % 3600 % 60) }} s</span>
|
</span>
|
</a-tooltip>
|
</a-col> -->
|
<a-col span="9">
|
<a-tooltip title="设备上的无人机">
|
<span>
|
<RocketOutlined />
|
</span>
|
<span class="ml5">{{ DroneInDockEnum[deviceInfo.dock.basic_osd?.drone_in_dock] }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="15" style="width: 100%;">
|
<div class="env-box span5 op_btn">
|
<a-col span="6">
|
<a-tooltip title="设备湿度">
|
<span>💦</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.humidity }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="8">
|
<a-button :class="[showMonitor ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openMonitor">
|
监控
|
</a-button>
|
</a-col>
|
<a-col span="2"></a-col>
|
<a-col span="8">
|
<a-button :class="[airPortOption ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openFlySetting">
|
操作
|
</a-button>
|
</a-col>
|
</div>
|
</a-col>
|
<!-- <a-col span="12">
|
<a-tooltip title="激活时间">
|
<span><FieldTimeOutlined /></span>
|
<span class="ml5">{{ new Date((deviceInfo.dock.work_osd?.activation_time ?? 0) * 1000).toLocaleString() }}
|
</span>
|
</a-tooltip>
|
</a-col> -->
|
</a-row>
|
<!-- 注释 -->
|
<!-- <a-row>
|
<a-col span="6">
|
<a-tooltip title="网络状态">
|
<span :style="deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.ETHERNET || deviceInfo.dock.basic_osd?.network_state?.quality === NetworkStateQualityEnum.GOOD ?
|
'color: #00ee8b' : deviceInfo.dock.basic_osd?.network_state?.quality === NetworkStateQualityEnum.MEDIUM ? 'color: yellow' : 'color: red'">
|
<span v-if="deviceInfo.dock.basic_osd?.network_state?.type === NetworkStateTypeEnum.FOUR_G"><SignalFilled /></span>
|
<span v-else><GlobalOutlined /></span>
|
</span>
|
<span class="ml5" >{{ deviceInfo.dock.basic_osd?.network_state?.rate }} kb/s</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="设备执行任务总次数">
|
<span><CarryOutOutlined /></span>
|
<span class="ml5" >{{ deviceInfo.dock.work_osd?.job_number }} </span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="媒体文件剩余上传">
|
<span><CloudUploadOutlined class="fz14"/></span>
|
<span class="ml5">{{ deviceInfo.dock.link_osd?.media_file_detail?.remain_upload }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip>
|
<template #title>
|
<p>总共: {{ deviceInfo.dock.basic_osd?.storage?.total }}</p>
|
<p>已使用: {{ deviceInfo.dock.basic_osd?.storage?.used }}</p>
|
</template>
|
<span><FolderOpenOutlined /></span>
|
<span class="ml5" v-if="deviceInfo.dock.basic_osd?.storage?.total > 0">
|
<a-progress type="circle" :width="20" :percent="deviceInfo.dock.basic_osd?.storage?.used * 100/ deviceInfo.dock.basic_osd?.storage?.total"
|
:strokeWidth="20" :showInfo="false" :strokeColor="deviceInfo.dock.basic_osd?.storage?.used * 100 / deviceInfo.dock.basic_osd?.storage?.total > 80 ? 'red' : '#00ee8b' "/>
|
</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="风速">
|
<span>W.S</span>
|
<span class="ml5">{{ (deviceInfo.dock.basic_osd?.wind_speed ?? str) + ' m/s'}}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="降雨量">
|
<span>🌧</span>
|
<span class="ml5">{{ RainfallEnum[deviceInfo.dock.basic_osd?.rainfall] }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="环境温度">
|
<span>°C</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.environment_temperature }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="设备温度">
|
<span>°C</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.temperature }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="设备湿度">
|
<span>💦</span>
|
<span class="ml5">{{ deviceInfo.dock.basic_osd?.humidity }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="工作电压">
|
<span style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 16px; text-align: center; float: left;">V</span>
|
<span class="ml5">{{ (deviceInfo.dock.work_osd?.working_voltage ?? str) + ' mV' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="工作电流">
|
<span style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 15px; text-align: center; float: left;" >A</span>
|
<span class="ml5">{{ (deviceInfo.dock.work_osd?.working_current ?? str) + ' mA' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="设备上的无人机">
|
<span><RocketOutlined /></span>
|
<span class="ml5">{{ DroneInDockEnum[deviceInfo.dock.basic_osd?.drone_in_dock] }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row> -->
|
<!-- <a-row class="p5" justify="space-between">
|
<a-col span="11">
|
<a-button :class="[showMonitor ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openMonitor">
|
监控
|
</a-button>
|
</a-col>
|
<a-col span="11">
|
<a-button :class="[showOption ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
:disabled="dockControlPanelVisible" size="small" @click="openFlySetting">
|
操作
|
</a-button>
|
</a-col>
|
</a-row> -->
|
<!-- 机场控制面板 -->
|
<DockControlPanel v-if="dockControlPanelVisible" :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo"
|
@close-control-panel="closeOperate">
|
</DockControlPanel>
|
</div>
|
</div>
|
<a-row class="p5" v-if="showMonitor" justify="center" align="middle">
|
<!-- <a-spin :spinning="spinning"> -->
|
<Jessibuca v-if="airPortUrl" @timeout="airTimeout" :videoUrl="airPortUrl" width="100%" height="300px" />
|
<!-- </a-spin> -->
|
</a-row>
|
<!-- 飞机-->
|
<div class="flex-display">
|
<div class="flex-column flex-align-stretch flex-justify-center" style="width: 60px; background: #2d2d2d;">
|
<a-tooltip :title="osdVisible.model">
|
<div style="width: 90%;" class="flex-column flex-align-center flex-justify-center">
|
<span><a-image :src="M30" :preview="false" /></span>
|
<span>{{ DEVICE_NAME[`${osdVisible.device_domain}-${osdVisible.device_type}-${osdVisible.device_sub_type}`]
|
}}</span>
|
</div>
|
</a-tooltip>
|
</div>
|
<div class="osd flex-1">
|
<a-row class="mr-20" align="middle">
|
<a-col span="9"
|
:style="deviceInfo.device && deviceInfo.device?.mode_code !== EModeCode.Disconnected ? 'color: rgb(25,190,107)' : deviceInfo.dock.basic_osd?.drone_in_dock === 1 ? 'color: rgb(25,190,107)' : 'color: red; font-weight: 700;'">
|
<!-- DroneInDockEnum[deviceInfo.dock.basic_osd?.drone_in_dock] -->
|
{{ deviceInfo.device ? EModeText[deviceInfo.device?.mode_code] : (deviceInfo.dock.basic_osd?.drone_in_dock
|
=== 1) ? '舱内关机' : EModeText[EModeCode.Disconnected]
|
}}</a-col>
|
<a-col span="15">
|
<div style="width:100%;padding:0 5px;background-color: #5d5f61;color: #fff;font-size: 10px;">
|
{{ deviceInfo.device?.mode_code == 14 || !deviceInfo.device ? 'N/A' : '当前正常' }}</div>
|
</a-col>
|
</a-row>
|
<a-row align="middle" justify="center">
|
<a-col span="24">
|
<div v-if="deviceInfo.device?.mode_code == 14 || !deviceInfo.device" style="color:#494949;"
|
class="flex-display flex-justify-center mt5 mb5">当前设备已关机,无法进行直播</div>
|
</a-col>
|
</a-row>
|
<a-row class="p5" v-if="deviceInfo.device?.mode_code != 14 && deviceInfo.device" align="middle"
|
justify="space-between">
|
<a-col span="11">
|
<a-button :class="[aircrafIndex === 0 ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openAircra(0)">
|
飞行相机
|
</a-button>
|
</a-col>
|
<a-col span="11">
|
<a-button :class="[aircrafIndex === 1 ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openAircra(1)">
|
M30T相机
|
</a-button>
|
</a-col>
|
</a-row>
|
<a-row class="p5" align="middle" justify="space-between">
|
<a-col span="24">
|
<!-- <a-button v-if="controlStatus != ''" :class="[openDroneControl ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openDeviceSetting">
|
飞行控制(<DesktopOutlined v-if="controlStatus === 'A'" /> <RobotFilled v-else />{{ controlStatus === 'A' ? 'A控' : 'B控'}})
|
</a-button>
|
<a-button v-else :class="[openDroneControl ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openDeviceSetting">
|
飞行控制
|
</a-button> -->
|
<a-button :class="[openDroneControl ? 'active-color' : 'unactive-color']" class="width-100" type="primary"
|
size="small" @click="openDeviceSetting">
|
飞行控制
|
</a-button>
|
</a-col>
|
</a-row>
|
</div>
|
</div>
|
<!-- 飞机直播 -->
|
<a-row class="p5" v-if="showAircraft">
|
<!-- <a-spin :spinning="spinning"> -->
|
<Jessibuca v-if="aircraftUrl" @timeout="flyTimeout" :videoUrl="aircraftUrl" width="100%" height="300px" />
|
<!-- </a-spin> -->
|
</a-row>
|
<!-- 飞机图标信息 -->
|
<div class="osd-info flex-1">
|
<!-- <a-row align="middle">
|
<a-col span="6">
|
<a-tooltip title="向上质量">
|
<span>
|
<SignalFilled />
|
<ArrowUpOutlined style="font-size: 9px; vertical-align: top;" />
|
</span>
|
<span class="ml5">{{ deviceInfo.dock.link_osd?.sdr?.up_quality }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="向下质量">
|
<span>
|
<SignalFilled />
|
<ArrowDownOutlined style="font-size: 9px; vertical-align: top;" />
|
</span>
|
<span class="ml5">{{ deviceInfo.dock.link_osd?.sdr?.down_quality }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="无人机电池电量">
|
<span>
|
<ThunderboltOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device && deviceInfo.device.battery.capacity_percent !== str ?
|
deviceInfo.device?.battery.capacity_percent + ' %' : str }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip>
|
<template #title>
|
<p>总供: {{ deviceInfo.device?.storage?.total }}</p>
|
<p>已使用: {{ deviceInfo.device?.storage?.used }}</p>
|
</template>
|
<span>
|
<FolderOpenOutlined />
|
</span>
|
<span class="ml5" v-if="deviceInfo.device?.storage?.total > 0">
|
<a-progress type="circle" :width="20"
|
:percent="deviceInfo.device?.storage?.used * 100 / deviceInfo.device?.storage?.total" :strokeWidth="20"
|
:showInfo="false"
|
:strokeColor="deviceInfo.device?.storage?.used * 100 / deviceInfo.device?.storage?.total > 80 ? 'red' : '#00ee8b'" />
|
</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-tooltip title="RTK固定">
|
<a-col span="6" class="flex-row flex-align-center flex-justify-start">
|
<span>Fixed</span>
|
<span class="ml5 circle"
|
:style="deviceInfo.device?.position_state.is_fixed === 1 ? 'backgroud: rgb(25,190,107);' : 'background: red;'"></span>
|
</a-col>
|
</a-tooltip>
|
<a-col span="6">
|
<a-tooltip title="GPS">
|
<span>GPS</span>
|
<span class="ml5">{{ deviceInfo.device ? deviceInfo.device.position_state.gps_number : str }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="RTK">
|
<span>
|
<TrademarkOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device ? deviceInfo.device.position_state.rtk_number : str }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="飞行模式">
|
<span>
|
<ControlOutlined class="fz16" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device ? EGear[deviceInfo.device?.gear] : str }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="海拔高度">
|
<span>ASL</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.height === str ? str :
|
deviceInfo.device?.height.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="高于起飞高度">
|
<span>ALT</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.elevation === str ? str :
|
deviceInfo.device?.elevation.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="到起点距离">
|
<span
|
style="border: 1px solid; border-radius: 50%; width: 18px; height: 18px; line-height: 15px; text-align: center; display: block; float: left;">H</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.home_distance === str ? str :
|
deviceInfo.device?.home_distance.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row>
|
<a-col span="6">
|
<a-tooltip title="水平速度">
|
<span>H.S</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device?.horizontal_speed === str ? str :
|
deviceInfo.device?.horizontal_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="垂直速度">
|
<span>V.S</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.vertical_speed === str ? str :
|
deviceInfo.device?.vertical_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="风速">
|
<span>W.S</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.wind_speed === str ? str :
|
(deviceInfo.device?.wind_speed / 10).toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row> -->
|
<a-row align="middle">
|
<a-col span="6" class="flex-row flex-align-center flex-justify-start">
|
<a-tooltip title="飞行模式">
|
<span>
|
<ControlOutlined class="fz16" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device ? EGear[deviceInfo.device?.gear] : str }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="RTK">
|
<span>
|
<TrademarkOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device ? deviceInfo.device.position_state.rtk_number : str }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="无人机电池电量">
|
<span>
|
<ThunderboltOutlined class="fz14" />
|
</span>
|
<span class="ml5">{{ deviceInfo.device && deviceInfo.device.battery.capacity_percent !== str ?
|
deviceInfo.device?.battery.capacity_percent + ' %' : str }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
<a-row align="middle" class="mt10">
|
<a-col span="6">
|
<a-tooltip title="海拔高度">
|
<span>ASL</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.height === str ? str :
|
deviceInfo.device?.height.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="高于起飞高度">
|
<span>ALT</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.elevation === str ? str :
|
deviceInfo.device?.elevation.toFixed(2) + ' m' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="水平速度">
|
<span>H.S</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device?.horizontal_speed === str ? str :
|
deviceInfo.device?.horizontal_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
<a-col span="6">
|
<a-tooltip title="垂直速度">
|
<span>V.S</span>
|
<span class="ml5">{{ !deviceInfo.device || deviceInfo.device.vertical_speed === str ? str :
|
deviceInfo.device?.vertical_speed.toFixed(2) + ' m/s' }}</span>
|
</a-tooltip>
|
</a-col>
|
</a-row>
|
</div>
|
<!-- 飞行控制 -->
|
<!-- <div class="fly-control flex-display">
|
<div class="flex-column flex-align-stretch flex-justify-center" style="width: 100px; background: #2d2d2d;">
|
<div style="cursor: pointer;" class="p10 flex-column flex-align-center flex-justify-center">
|
<span><a-image :src="M30" :preview="false" /></span>
|
<span>一键起飞</span>
|
</div>
|
</div>
|
</div> -->
|
<div class="battery-slide" v-if="deviceInfo.device && deviceInfo.device.battery.remain_flight_time !== 0"
|
style="border: 1px solid red">
|
<div style="background: #535759;" class="width-100"></div>
|
<div class="capacity-percent" :style="{ width: deviceInfo.device.battery.capacity_percent + '%' }"></div>
|
<div class="return-home" :style="{ width: deviceInfo.device.battery.return_home_power + '%' }"></div>
|
<div class="landing" :style="{ width: deviceInfo.device.battery.landing_power + '%' }"></div>
|
<div class="white-point" :style="{ left: deviceInfo.device.battery.landing_power + '%' }"></div>
|
<div class="battery" :style="{ left: deviceInfo.device.battery.capacity_percent + '%' }">
|
{{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}:
|
{{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' :
|
'' }}{{ deviceInfo.device.battery.remain_flight_time % 60 }}
|
</div>
|
</div>
|
<!-- 飞行指令 -->
|
<DroneControlPanel v-model="openDroneControl" :sn="osdVisible.gateway_sn" :deviceInfo="deviceInfo"
|
:payloads="osdVisible.payloads">
|
</DroneControlPanel>
|
</div>
|
</div>
|
</template>
|
|
<script lang="ts">
|
import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue'
|
import {
|
generateLineContent,
|
generatePointContent,
|
generatePolyContent
|
} from '../utils/map-layer-utils'
|
import { message } from 'ant-design-vue'
|
import { postElementsReq } from '/@/api/layer'
|
import { MapDoodleType, MapElementEnum } from '/@/constants/map'
|
import { useGMapManage } from '/@/hooks/use-g-map'
|
import { useGMapCover } from '/@/hooks/use-g-map-cover'
|
import { useMouseTool } from '/@/hooks/use-mouse-tool'
|
import { getApp, getRoot } from '/@/root'
|
import { useMyStore } from '/@/store'
|
import { GeojsonCoordinate } from '/@/types/map'
|
import { MapDoodleEnum } from '/@/types/map-enum'
|
import { PostElementsBody } from '/@/types/mapLayer'
|
import { uuidv4 } from '/@/utils/uuid'
|
import { gcj02towgs84, wgs84togcj02 } from '/@/vendors/coordtransform'
|
import { deviceTsaUpdate } from '/@/hooks/use-g-map-tsa'
|
import Jessibuca from '/@/components/Jessibuca/Jessibuca.vue'
|
import { CURRENT_CONFIG as config } from '/@/api/http/config'
|
import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage'
|
import {
|
DeviceOsd, DeviceStatus, DockOsd, EGear, EModeCode, GatewayOsd, EDockModeCode, EDockModeText, EModeText,
|
NetworkStateQualityEnum, NetworkStateTypeEnum, RainfallEnum, DroneInDockEnum, DEVICE_NAME
|
} from '/@/types/device'
|
import pin from '/@/assets/icons/pin-2d8cf0.svg'
|
import M30 from '/@/assets/icons/m30.png'
|
import {
|
BorderOutlined, LineOutlined, ControlOutlined, TrademarkOutlined, ArrowDownOutlined,
|
ThunderboltOutlined, SignalFilled, GlobalOutlined, HistoryOutlined, CloudUploadOutlined, RocketOutlined,
|
FieldTimeOutlined, CloudOutlined, CloudFilled, FolderOpenOutlined, RobotFilled, ArrowUpOutlined, CarryOutOutlined,
|
DesktopOutlined, CloseOutlined, ContainerOutlined
|
} from '@ant-design/icons-vue'
|
import { EDeviceTypeName } from '../types'
|
import DockControlPanel from './g-map/DockControlPanel.vue'
|
import { useDockControl } from './g-map/use-dock-control'
|
import DroneControlPanel from './g-map/DroneControlPanel.vue'
|
import { useConnectMqtt } from './g-map/use-connect-mqtt'
|
import Cesium from './cesiumMap/cesium.vue'
|
import { convertTimestampToDate } from '/@/utils/time'
|
export default defineComponent({
|
components: {
|
BorderOutlined,
|
LineOutlined,
|
CloseOutlined,
|
ContainerOutlined,
|
ControlOutlined,
|
TrademarkOutlined,
|
ThunderboltOutlined,
|
SignalFilled,
|
GlobalOutlined,
|
HistoryOutlined,
|
CloudUploadOutlined,
|
FieldTimeOutlined,
|
CloudOutlined,
|
CloudFilled,
|
FolderOpenOutlined,
|
RobotFilled,
|
ArrowUpOutlined,
|
ArrowDownOutlined,
|
DockControlPanel,
|
DroneControlPanel,
|
CarryOutOutlined,
|
RocketOutlined,
|
DesktopOutlined,
|
},
|
name: 'GMap',
|
props: {},
|
setup () {
|
const useMouseToolHook = useMouseTool()
|
const useGMapManageHook = useGMapManage()
|
const deviceTsaUpdateHook = deviceTsaUpdate()
|
interface SelectOption {
|
value: any,
|
label: string,
|
more?: any
|
}
|
// 打开飞行控制
|
const openDroneControl = ref(false)
|
const root = getRoot()
|
// 监控显示
|
const showMonitor = ref(false)
|
const mouseMode = ref(false)
|
const store = useMyStore()
|
// 机场直播地址
|
const airPortUrl = ref('')
|
const airPortOption = ref(false)
|
// 设备列表
|
const droneList = ref()
|
// 设备相机
|
const cameraList = ref()
|
// 相机设备选择值
|
const cameraIndex = ref(0)
|
// 设备列表选择值
|
const droneIndex = ref(0)
|
// 视频列表选择值
|
const videoList = ref()
|
const videoIndex = ref(0)
|
|
// 飞机视频播放地址
|
const aircraftUrl = ref('')
|
const showAircraft = ref(false)
|
// 飞机视频列表
|
const aircraftList = ref([])
|
const aircraSelected = ref(undefined)
|
const aircrafIndex = ref(-1)
|
const state = reactive({
|
currentType: '',
|
coverIndex: 0
|
})
|
const str: string = '--'
|
const deviceInfo = reactive({
|
gateway: {
|
capacity_percent: str,
|
transmission_signal_quality: str,
|
} as GatewayOsd,
|
dock: {
|
|
} as DockOsd,
|
device: {
|
gear: -1,
|
mode_code: EModeCode.Disconnected,
|
height: str,
|
home_distance: str,
|
horizontal_speed: str,
|
vertical_speed: str,
|
wind_speed: str,
|
wind_direction: str,
|
elevation: str,
|
position_state: {
|
gps_number: str,
|
is_fixed: 0,
|
rtk_number: str
|
},
|
battery: {
|
capacity_percent: str,
|
landing_power: str,
|
remain_flight_time: 0,
|
return_home_power: str,
|
},
|
latitude: 0,
|
longitude: 0,
|
} as DeviceOsd
|
})
|
const shareId = computed(() => {
|
return store.state.layerBaseInfo.share
|
})
|
const defaultId = computed(() => {
|
return store.state.layerBaseInfo.default
|
})
|
const drawVisible = computed(() => {
|
return store.state.drawVisible
|
})
|
const osdVisible = computed(() => JSON.parse(JSON.stringify(store.state.osdVisible)))
|
const sn = computed(() => {
|
return store.state.hmsInfoDetailSn
|
})
|
const hmsInfo = computed({
|
get: () => store.state.hmsInfo,
|
set: (val) => {
|
return val
|
}
|
})
|
|
// 关闭窗口
|
const closeOsdWindow = () => {
|
store.commit('SET_OSD_VISIBLE_INFO', false)
|
showAircraft.value = false
|
aircrafIndex.value = -1
|
aircraftUrl.value = ''
|
showMonitor.value = false
|
airPortUrl.value = ''
|
airPortOption.value = false
|
showMonitor.value = false
|
}
|
|
// 打开监控权限
|
const openMonitor = () => {
|
showMonitor.value = !showMonitor.value
|
if (showMonitor.value) {
|
loadVideo()
|
} else {
|
airPortUrl.value = ''
|
// onClose()
|
}
|
}
|
// 打开飞机监控
|
const openAircra = (type: number) => {
|
showAircraft.value = !showAircraft.value
|
if (type === aircrafIndex.value) {
|
showAircraft.value = false
|
aircrafIndex.value = -1
|
} else {
|
showAircraft.value = true
|
aircrafIndex.value = type
|
}
|
if (showAircraft.value) {
|
loadDroneVideo(type)
|
} else {
|
aircraftUrl.value = ''
|
// closeFly()
|
}
|
}
|
// 加载该设备的视频信息
|
const loadVideo = async () => {
|
droneList.value = []
|
cameraList.value = []
|
videoList.value = []
|
droneIndex.value = 0
|
cameraIndex.value = 0
|
await getLiveCapacity({ id: store.state.common.projectId })
|
.then(res => {
|
if (res.code === 0) {
|
if (res.data === null) {
|
console.warn('warning: get live capacity is null!!!')
|
return
|
}
|
// 机场数据
|
const airport = res.data.find(v => v.sn === sn.value)
|
const temp: Array<SelectOption> = []
|
if (airport) {
|
temp.push({ label: airport.name, value: airport.sn, more: airport.cameras_list })
|
// 设备列表
|
droneList.value = temp.filter(v => v.value === sn.value)
|
// 设备直播处理
|
if (droneList.value[0].more && droneList.value[0].more.length > 0) {
|
cameraList.value = droneList.value[droneIndex.value].more.map((v: { name: any; index: any; videos_list: any }) => {
|
return {
|
label: v.name,
|
value: v.index,
|
more: v.videos_list
|
}
|
})
|
videoList.value = cameraList.value[cameraIndex.value].more.map((v) => {
|
return {
|
label: v.type,
|
value: v.index,
|
}
|
})
|
onStart()
|
} else {
|
showMonitor.value = false
|
message.error('该设备暂无直播设备开启')
|
}
|
}
|
}
|
})
|
.catch(error => {
|
showMonitor.value = false
|
airPortUrl.value = ''
|
message.error(error)
|
})
|
}
|
// 加载无人机的视频信息
|
const loadDroneVideo = async (index: number) => {
|
aircraftList.value = []
|
await getLiveCapacity({ id: store.state.common.projectId })
|
.then(res => {
|
if (res.code === 0) {
|
if (res.data === null) {
|
console.warn('warning: get live capacity is null!!!')
|
return
|
}
|
const drone = res.data.find(v => v.sn === deviceInfo.dock.basic_osd.sub_device?.device_sn)
|
const temp: Array<SelectOption> = []
|
if (drone) {
|
temp.push({ label: drone.name, value: drone.sn, more: drone.cameras_list })
|
} // 无人机列表
|
const airList = temp.filter(v => v.value === deviceInfo.dock.basic_osd?.sub_device?.device_sn)
|
// 无人机设备处理
|
if (airList[0].more && airList[0].more.length > 0) {
|
aircraftList.value = airList[0].more.map(v => {
|
return {
|
label: v.name,
|
value: v.index,
|
vadeosList: v.videos_list
|
}
|
})
|
aircraSelected.value = aircraftList.value[index].value
|
flyOnStart()
|
} else {
|
showAircraft.value = false
|
message.error('该无人机暂无直播设备开启')
|
}
|
}
|
})
|
.catch(error => {
|
showAircraft.value = false
|
aircrafIndex.value = -1
|
message.error(error)
|
})
|
}
|
// 机场视频超时说明可能直播被关闭需要重新开启直播
|
const airTimeout = () => {
|
try {
|
onStart()
|
} catch (e) {
|
airPortUrl.value = ''
|
// onClose()
|
}
|
}
|
const flyTimeout = () => {
|
try {
|
flyOnStart()
|
} catch (e) {
|
aircraftUrl.value = ''
|
// closeFly()
|
}
|
}
|
// 设备开始播放
|
const onStart = async () => {
|
airPortUrl.value = ''
|
const videoId = droneList.value[droneIndex.value].value + '/' + cameraList.value[cameraIndex.value].value + '/' + videoList.value[videoIndex.value].value
|
const streamId = droneList.value[droneIndex.value].value + '-' + cameraList.value[cameraIndex.value].value + '-' + videoList.value[videoIndex.value].value
|
const liveURL = config.rtmpURL + streamId
|
await startLivestream({
|
url: liveURL,
|
video_id: videoId,
|
url_type: 1,
|
video_quality: 0
|
})
|
.then(res => {
|
if (res.code !== 0) return
|
airPortUrl.value = res.data.url
|
})
|
}
|
// 关闭设备直播
|
const onClose = async () => {
|
const videoId = droneList.value[droneIndex.value].value + '/' + cameraList.value[cameraIndex.value].value + '/' + videoList.value[videoIndex.value].value
|
|
stopLivestream({
|
video_id: videoId
|
}).then(res => {
|
if (res.code === 0) {
|
airPortUrl.value = ''
|
}
|
})
|
}
|
// 飞机设备播放
|
const flyOnStart = async () => {
|
aircraftUrl.value = ''
|
const videoId = deviceInfo.dock.basic_osd?.sub_device?.device_sn + '/' + aircraSelected.value + '/' + 'normal-0'
|
const streamId = deviceInfo.dock.basic_osd?.sub_device?.device_sn + '-' + aircraSelected.value + '-' + 'normal-0'
|
const liveURL = config.rtmpURL + streamId
|
await startLivestream({
|
url: liveURL,
|
video_id: videoId,
|
url_type: 1,
|
video_quality: 0
|
})
|
.then(res => {
|
if (res.code !== 0) return
|
aircraftUrl.value = res.data.url
|
})
|
}
|
// 飞行设备关闭
|
const closeFly = async () => {
|
aircraftList.value.forEach(item => {
|
const videoId = deviceInfo.dock.basic_osd?.sub_device?.device_sn + '/' + item.value + '/' + 'normal-0'
|
stopLivestream({
|
video_id: videoId
|
}).then(res => {
|
if (res.code === 0) {
|
aircraftUrl.value = ''
|
}
|
}).catch(e => {
|
console.log(e, 'errrrrrrrrrrrrrr')
|
})
|
})
|
// const videoId = deviceInfo.dock.basic_osd?.sub_device?.device_sn + '/' + aircraSelected.value + '/' + 'normal-0'
|
aircraftList.value = []
|
aircraSelected.value = ''
|
}
|
// 打开机场操作
|
const openFlySetting = () => {
|
openDroneControl.value = false
|
airPortOption.value = !airPortOption.value
|
if (airPortOption.value) {
|
setDockControlPanelVisible(true)
|
} else {
|
setDockControlPanelVisible(false)
|
}
|
}
|
// 打开无人机操作
|
const openDeviceSetting = () => {
|
setDockControlPanelVisible(false)
|
airPortOption.value = false
|
openDroneControl.value = !openDroneControl.value
|
}
|
// 飞行控制状态
|
const controlStatus = computed(() => store.state.common.droneControlSource)
|
watch(() => store.state.deviceStatusEvent,
|
data => {
|
if (Object.keys(data.deviceOnline).length !== 0) {
|
// deviceTsaUpdateHook.initMarker(data.deviceOnline.domain, data.deviceOnline.device_callsign, data.deviceOnline.sn)
|
store.state.deviceStatusEvent.deviceOnline = {} as DeviceStatus
|
}
|
if (Object.keys(data.deviceOffline).length !== 0) {
|
store.state.deviceStatusEvent.deviceOffline = {}
|
}
|
},
|
{
|
deep: true
|
}
|
)
|
watch(() => store.state.deviceState, data => {
|
if (data.currentType === EDeviceTypeName.Gateway && data.gatewayInfo[data.currentSn]) {
|
if (osdVisible.value.visible && osdVisible.value.gateway_sn !== '') {
|
deviceInfo.gateway = data.gatewayInfo[osdVisible.value.gateway_sn]
|
}
|
}
|
if (data.currentType === EDeviceTypeName.Aircraft && data.deviceInfo[data.currentSn]) {
|
if (osdVisible.value.visible && osdVisible.value.sn !== '') {
|
deviceInfo.device = data.deviceInfo[osdVisible.value.sn]
|
}
|
}
|
if (data.currentType === EDeviceTypeName.Dock && data.dockInfo[data.currentSn]) {
|
if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') {
|
deviceInfo.dock = data.dockInfo[osdVisible.value.gateway_sn]
|
deviceInfo.device = data.deviceInfo[deviceInfo.dock.basic_osd.sub_device?.device_sn ?? osdVisible.value.sn]
|
}
|
}
|
}, {
|
deep: true,
|
})
|
watch(() => osdVisible.value, (data, oldData) => {
|
showMonitor.value = false
|
aircraftUrl.value = ''
|
showAircraft.value = false
|
aircraftList.value = []
|
aircraSelected.value = undefined
|
airPortUrl.value = ''
|
droneList.value = []
|
if (deviceInfo.dock.basic_osd?.mode_code === 2) {
|
onCloseControlPanel(oldData.gateway_sn)
|
} else {
|
setDockControlPanelVisible(false)
|
}
|
}, {
|
deep: true,
|
})
|
watch(
|
() => store.state.wsEvent,
|
newData => {
|
const useGMapCoverHook = useGMapCover()
|
const event = newData
|
let exist = false
|
if (Object.keys(event.mapElementCreat).length !== 0) {
|
console.log(event.mapElementCreat)
|
const ele = event.mapElementCreat
|
store.state.Layers.forEach(layer => {
|
layer.elements.forEach(e => {
|
if (e.id === ele.id) {
|
exist = true
|
console.log('true')
|
}
|
})
|
})
|
if (exist === false) {
|
setLayers({
|
id: ele.id,
|
name: ele.name,
|
resource: ele.resource
|
})
|
|
updateCoordinates('wgs84-gcj02', ele)
|
useGMapCoverHook.init2DPin(
|
ele.name,
|
ele.resource.content.geometry.coordinates,
|
ele.resource.content.properties.color,
|
{
|
id: ele.id,
|
name: ele.name
|
}
|
)
|
}
|
|
store.state.wsEvent.mapElementCreat = {}
|
}
|
if (Object.keys(event.mapElementUpdate).length !== 0) {
|
console.log(event.mapElementUpdate)
|
console.log('该功能还未实现,请开发商自己增加')
|
store.state.wsEvent.mapElementUpdate = {}
|
}
|
if (Object.keys(event.mapElementDelete).length !== 0) {
|
console.log(event.mapElementDelete)
|
console.log('该功能还未实现,请开发商自己增加')
|
store.state.wsEvent.mapElementDelete = {}
|
}
|
},
|
{
|
deep: true
|
}
|
)
|
|
function draw (type: MapDoodleType, bool: boolean) {
|
state.currentType = type
|
useMouseToolHook.mouseTool(type, getDrawCallback)
|
mouseMode.value = bool
|
}
|
|
// dock 控制面板
|
const {
|
dockControlPanelVisible,
|
setDockControlPanelVisible,
|
onCloseControlPanel,
|
} = useDockControl()
|
// 关闭设备控制方法
|
const closeOperate = (sn: string) => {
|
airPortOption.value = false
|
if (deviceInfo.dock.basic_osd?.mode_code === 2) {
|
onCloseControlPanel(sn)
|
} else {
|
setDockControlPanelVisible(false)
|
}
|
}
|
// 连接或断开drc
|
useConnectMqtt()
|
|
onMounted(() => {
|
// const app = getApp()
|
// useGMapManageHook.globalPropertiesConfig(app)
|
})
|
|
function getDrawCallback ({ obj }) {
|
switch (state.currentType) {
|
case MapDoodleEnum.PIN:
|
postPinPositionResource(obj)
|
break
|
case MapDoodleEnum.POLYLINE:
|
postPolylineResource(obj)
|
break
|
case MapDoodleEnum.POLYGON:
|
postPolygonResource(obj)
|
break
|
default:
|
break
|
}
|
}
|
async function postPinPositionResource (obj: { setExtData: (arg0: { id: string; name: any }) => void }) {
|
const req = getPinPositionResource(obj)
|
setLayers(req)
|
const coordinates = req.resource.content.geometry.coordinates
|
updateCoordinates('gcj02-wgs84', req);
|
(req.resource.content.geometry.coordinates as GeojsonCoordinate).push((coordinates as GeojsonCoordinate)[2])
|
const result = await postElementsReq(shareId.value, req)
|
obj.setExtData({ id: req.id, name: req.name })
|
store.state.coverList.push(obj)
|
// console.log(store.state.coverList)
|
}
|
async function postPolylineResource (obj: { setExtData: (arg0: { id: string; name: any }) => void }) {
|
const req = getPolylineResource(obj)
|
setLayers(req)
|
updateCoordinates('gcj02-wgs84', req)
|
const result = await postElementsReq(shareId.value, req)
|
obj.setExtData({ id: req.id, name: req.name })
|
store.state.coverList.push(obj)
|
// console.log(store.state.coverList)
|
}
|
async function postPolygonResource (obj: { setExtData: (arg0: { id: string; name: any }) => void }) {
|
const req = getPoygonResource(obj)
|
setLayers(req)
|
updateCoordinates('gcj02-wgs84', req)
|
const result = await postElementsReq(shareId.value, req)
|
obj.setExtData({ id: req.id, name: req.name })
|
store.state.coverList.push(obj)
|
// console.log(store.state.coverList)
|
}
|
|
function getPinPositionResource (obj: { getPosition: () => any; _originOpts: { title: any } }) {
|
const position = obj.getPosition()
|
const resource = generatePointContent(position)
|
const name = obj._originOpts.title
|
const id = uuidv4()
|
return {
|
id,
|
name,
|
resource
|
}
|
}
|
function getPolylineResource (obj: { getPath: () => any; _opts: any }) {
|
const path = obj.getPath()
|
const resource = generateLineContent(path)
|
const { name, id } = getBaseInfo(obj._opts)
|
return {
|
id,
|
name,
|
resource
|
}
|
}
|
function getPoygonResource (obj: { getPath: () => any; _opts: any }) {
|
const path = obj.getPath()
|
const resource = generatePolyContent(path)
|
const { name, id } = getBaseInfo(obj._opts)
|
return {
|
id,
|
name,
|
resource
|
}
|
}
|
function getBaseInfo (obj: { title: any }) {
|
const name = obj.title
|
const id = uuidv4()
|
return { name, id }
|
}
|
function setLayers (resource: PostElementsBody) {
|
const layers = store.state.Layers
|
const layer = layers.find(item => item.id.includes(shareId.value))
|
// layer.id = 'private_layer' + uuidv4()
|
// layer?.elements.push(resource)
|
if (layer?.elements) {
|
; (layer?.elements as any[]).push(resource)
|
}
|
console.log('layers', layers)
|
store.commit('SET_LAYER_INFO', layers)
|
}
|
function updateCoordinates (transformType: string, element: any) {
|
const geoType = element.resource?.content.geometry.type
|
const type = element.resource?.type as number
|
if (element.resource) {
|
if (MapElementEnum.PIN === type) {
|
const coordinates = element.resource?.content.geometry
|
.coordinates as GeojsonCoordinate
|
if (transformType === 'wgs84-gcj02') {
|
const transResult = wgs84togcj02(
|
coordinates[0],
|
coordinates[1]
|
) as GeojsonCoordinate
|
element.resource.content.geometry.coordinates = transResult
|
} else if (transformType === 'gcj02-wgs84') {
|
const transResult = gcj02towgs84(
|
coordinates[0],
|
coordinates[1]
|
) as GeojsonCoordinate
|
element.resource.content.geometry.coordinates = transResult
|
}
|
} else if (MapElementEnum.LINE === type && geoType === 'LineString') {
|
const coordinates = element.resource?.content.geometry
|
.coordinates as GeojsonCoordinate[]
|
if (transformType === 'wgs84-gcj02') {
|
coordinates.forEach(coordinate => {
|
coordinate = wgs84togcj02(
|
coordinate[0],
|
coordinate[1]
|
) as GeojsonCoordinate
|
})
|
} else if (transformType === 'gcj02-wgs84') {
|
coordinates.forEach(coordinate => {
|
coordinate = gcj02towgs84(
|
coordinate[0],
|
coordinate[1]
|
) as GeojsonCoordinate
|
})
|
}
|
element.resource.content.geometry.coordinates = coordinates
|
} else if (MapElementEnum.LINE === type && geoType === 'Polygon') {
|
const coordinates = element.resource?.content.geometry
|
.coordinates[0] as GeojsonCoordinate[]
|
|
if (transformType === 'wgs84-gcj02') {
|
coordinates.forEach(coordinate => {
|
coordinate = wgs84togcj02(
|
coordinate[0],
|
coordinate[1]
|
) as GeojsonCoordinate
|
})
|
} else if (transformType === 'gcj02-wgs84') {
|
coordinates.forEach(coordinate => {
|
coordinate = gcj02towgs84(
|
coordinate[0],
|
coordinate[1]
|
) as GeojsonCoordinate
|
})
|
}
|
element.resource.content.geometry.coordinates = [coordinates]
|
}
|
}
|
}
|
return {
|
draw,
|
mouseMode,
|
drawVisible,
|
osdVisible,
|
pin,
|
state,
|
M30,
|
deviceInfo,
|
EGear,
|
EModeCode,
|
str,
|
EDockModeCode,
|
EDockModeText,
|
DEVICE_NAME,
|
EModeText,
|
dockControlPanelVisible,
|
setDockControlPanelVisible,
|
onCloseControlPanel,
|
NetworkStateTypeEnum,
|
NetworkStateQualityEnum,
|
RainfallEnum,
|
DroneInDockEnum,
|
hmsInfo,
|
sn,
|
showMonitor,
|
airPortUrl,
|
openMonitor,
|
droneIndex,
|
openAircra,
|
showAircraft,
|
aircraftUrl,
|
aircraftList,
|
aircraSelected,
|
closeOperate,
|
closeOsdWindow,
|
openDroneControl,
|
openFlySetting,
|
openDeviceSetting,
|
airTimeout,
|
flyTimeout,
|
aircrafIndex,
|
airPortOption,
|
controlStatus,
|
convertTimestampToDate
|
}
|
}
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.g-map-wrapper {
|
height: 100%;
|
width: 100%;
|
|
.g-action-panel {
|
position: absolute;
|
top: 16px;
|
right: 16px;
|
|
.g-action-item {
|
width: 28px;
|
height: 28px;
|
background: white;
|
color: $primary;
|
border-radius: 2px;
|
line-height: 28px;
|
text-align: center;
|
margin-bottom: 2px;
|
}
|
|
.g-action-item:hover {
|
border: 1px solid $primary;
|
border-radius: 2px;
|
}
|
}
|
|
.selection {
|
border: 1px solid $primary;
|
border-radius: 2px;
|
}
|
|
// antd button 光晕
|
&:deep(.ant-btn) {
|
&::after {
|
display: none;
|
}
|
}
|
|
&:deep(.ant-btn > .anticon + span, .ant-btn > span + .anticon, .ant-btn > .anticon + span, .ant-btn > span + .anticon) {
|
margin-left: 5px !important;
|
}
|
}
|
|
.osd-panel {
|
position: absolute;
|
left: 10px;
|
top: 10px;
|
width: 480px;
|
background-color: #232323;
|
color: #fff;
|
border-radius: 2px;
|
// opacity: 0.8;
|
}
|
|
.overflow {
|
width: 100%;
|
overflow: hidden;
|
background-color: #ff9900;
|
// padding: 2px 5px;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
}
|
|
.osd-info {
|
margin: 15px 10px;
|
}
|
|
.num {
|
padding: 0 5px;
|
background-color: #ff9900;
|
color: #fff;
|
}
|
|
.span5 {
|
display: flex;
|
align-items: center;
|
padding-right: 20px;
|
}
|
|
.op_btn {
|
justify-content: space-between;
|
}
|
|
.osd>div:not(.dock-control-panel) {
|
margin-top: 5px;
|
padding-left: 5px;
|
margin-bottom: 5px;
|
}
|
|
.circle {
|
border-radius: 50%;
|
width: 10px;
|
height: 10px;
|
}
|
|
.battery-slide {
|
.capacity-percent {
|
background: #00ee8b;
|
}
|
|
.return-home {
|
background: #ff9f0a;
|
}
|
|
.landing {
|
background: #f5222d;
|
}
|
|
.white-point {
|
width: 4px;
|
height: 4px;
|
border-radius: 50%;
|
background: white;
|
bottom: -0.5px;
|
}
|
|
.battery {
|
background: #141414;
|
color: #00ee8b;
|
margin-top: -10px;
|
height: 20px;
|
width: auto;
|
border-left: 1px solid #00ee8b;
|
padding: 0 5px;
|
}
|
}
|
|
.battery-slide>div {
|
position: absolute;
|
min-height: 2px;
|
border-radius: 2px;
|
}
|
.task_wrapper {
|
display: flex;
|
align-items: center;
|
font-size: 12px;
|
.task_content {
|
background-color: #41bbfa;
|
padding: 2px 4px;
|
}
|
|
.task_content_way {
|
background-color: #19be6b;
|
}
|
.task_title {
|
margin-left: 5px;
|
font-size: 14px;
|
}
|
}
|
</style>
|