Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard
25 files modified
3 files renamed
1 files added
1 files deleted
| | |
| | | #开发、测试、生产环境共用环境配置 |
| | | |
| | | VITE_APP_API = /api |
| | | #调试参数 |
| | | VITE_APP_DEBUG_KEY = saber |
| | |
| | | # 航线文件地址 |
| | | VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket |
| | | |
| | | #系统运维 |
| | | VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage' |
| | | #管理后台地址 |
| | | VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage/wel/index' |
| | |
| | | # ws地址 |
| | | VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws |
| | | # 管理后台地址 |
| | | VITE_APP_ADMIN_URL = 'https://aisky.org.cn/manage' |
| | | VITE_APP_ADMIN_URL = 'https://aisky.org.cn/manage/wel/index' |
| | |
| | | # 航线文件地址 |
| | | VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket |
| | | |
| | | #系统运维 |
| | | VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage' |
| | | #管理后台地址 |
| | | VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage/wel/index' |
| | |
| | | }) |
| | | } |
| | | |
| | | export function getLiveCapacityApi(workspace_id,params) { |
| | | export function getLiveCapacityApi(params) { |
| | | return request({ |
| | | url:`/drone-device-core/manage/api/v1/live/capacity${workspace_id}`, |
| | | url:`/drone-device-core/manage/api/v1/live/capacity`, |
| | | method:'get', |
| | | params |
| | | }) |
| | |
| | | import EventBus from '@/event-bus' |
| | | |
| | | const isAutoControl = inject('isAutoControl') |
| | | const isBackDock = inject('isBackDock') |
| | | |
| | | const list3 = computed(() => [ |
| | | { name: '自动控制', svg: 'autoControl', style: { top: '-70%' }, active: isAutoControl.value, handle: autoControl }, |
| | | { name: '自动控制', svg: 'autoControl', style: { top: '-70%' }, active: isAutoControl.value && !isBackDock.value, handle: autoControl }, |
| | | //如果是返航, 继续任务 就是自动任务 |
| | | //如果是取消返航, 继续任务 就是自动任务 |
| | | { name: '继续任务', svg: 'continueTask', style: { left: '70%' }, active: false, handle: autoControl }, |
| | | { |
| | | name: '手动控制', |
| | | svg: 'manualControl', |
| | | style: { top: '70%' }, |
| | | active: !isAutoControl.value, |
| | | active: !isAutoControl.value && !isBackDock.value, |
| | | handle: manualControl, |
| | | }, |
| | | { name: '返航/取消返航', svg: 'turnBack', style: { left: '-70%' }, active: false, handle: turnBack }, |
| | | { name: '返航/取消返航', svg: 'turnBack', style: { left: '-70%' }, active: isBackDock.value, handle: turnBack }, |
| | | ]) |
| | | |
| | | function autoControl() { |
| | | isAutoControl.value = true |
| | | EventBus.emit('controlPanel-cancelControl') |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | function turnBack() { |
| | | isAutoControl.value = true |
| | | EventBus.emit('controlPanel-returnOrCancelReturn') |
| | | } |
| | | </script> |
| | |
| | | const droneSn = inject('droneSn') |
| | | const trueAltitude = inject('trueAltitude') |
| | | const client_id = inject('client_id') |
| | | const isBackDock = inject('isBackDock') |
| | | |
| | | const deviceTopicInfo = ref({ |
| | | pubTopic: '', |
| | |
| | | function cancelControl() { |
| | | exitController({ client_id: client_id.value, dock_sn: dockSn.value }) |
| | | .then(res => { |
| | | flightController.value = false |
| | | deviceTopicInfo.value.subTopic = '' |
| | | deviceTopicInfo.value.pubTopic = '' |
| | | flightController.value = false |
| | | isAutoControl.value = true |
| | | ElMessage.success('退出飞行控制成功') |
| | | }) |
| | | .catch(e => {}) |
| | |
| | | }) |
| | | } |
| | | |
| | | const isBackDock = ref(false) |
| | | |
| | | |
| | | // 返航 |
| | | async function onBackDock() { |
| | | await returnHome(dockSn?.value) |
| | | ElMessage.success('返航操作成功') |
| | | isBackDock.value = true |
| | | isAutoControl.value = true |
| | | } |
| | | |
| | | // 取消返航 |
| | |
| | | await returnHomeCancel({ dock_sn: dockSn?.value, client_id: client_id.value }) |
| | | ElMessage.success('取消返航成功') |
| | | isBackDock.value = false |
| | | isAutoControl.value = false |
| | | } |
| | | |
| | | // 创建mqtt连接 |
| | |
| | | import { pxToRem } from '@/utils/rem' |
| | | import LiveVideo from '@/components/LiveVideo.vue' |
| | | import { liveStart } from '@/api/home/machineNest' |
| | | import { getJobDetails } from '@/api/home/task' |
| | | |
| | | import RealTimeMap from '@/components/CurrentTaskDetails/RealTimeMap.vue' |
| | | import ControlPanel from '@/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue' |
| | | import TaskDetailsHead from '@/components/CurrentTaskDetails/TaskDetailsHead.vue' |
| | |
| | | const isAutoControl = ref(true) //是否自动控制 |
| | | const lineQuality = ref(1) //1流畅,2标清 |
| | | const taskDetailsViewer = ref(null) //地图实例 |
| | | const deviceOsdInfo = computed(() => wsInfo.value?.device_osd) |
| | | const dockSn = computed(() => taskDetails?.value?.device_sns?.[0]) |
| | | const droneSn = computed(() => deviceOsdInfo?.value?.data?.sn) |
| | | const dockSn = computed(() => taskDetails?.value?.device_sns?.[0]) //机巢sn |
| | | const droneSn = computed(() => wsInfo.value?.device_osd?.data?.sn) //无人机sn |
| | | const trueAltitude = ref('') // 真实高度 |
| | | const isAiLive = ref(false) // 是ai直播 |
| | | const video_id = ref('') // 直播视频id |
| | |
| | | const currentLiveUrl = ref('') // 当前直播地址 |
| | | const isTakeOff = ref(false) // 是在飞行中 |
| | | const isMaxMap = ref(false) //是大地图 |
| | | const client_id = ref('') //是大地图 |
| | | |
| | | // 获取机巢直播 |
| | | const getDeviceLiveUrl = async () => { |
| | | const res = await liveStart(dockSn.value, 2) |
| | | currentLiveUrl.value = res.data.data.rtcs_url |
| | | } |
| | | |
| | | //获取相机能力 |
| | | async function getLiveCapacity() { |
| | | const res = await getLiveCapacityApi(workspace_id.value,{ sn: dockSn.value}) |
| | | } |
| | | const useTaskDetailsCallBack = () => { |
| | | console.log(workspace_id.value,66666666) |
| | | getDeviceLiveUrl() |
| | | } |
| | | |
| | | let { taskDetails, workspace_id, getTaskDetails } = useTaskDetails(useTaskDetailsCallBack) |
| | | let { wsInfo, removeWS } = useDroneWS(workspace_id) //ws信息,是一个ref对象 |
| | | const client_id = ref('') //mqtt id |
| | | const hasIr = ref(false) //有红外能力 |
| | | let once = true //第一次触发 |
| | | const isBackDock = ref(false) |
| | | let { taskDetails, workspace_id, getTaskDetails:initTaskDetails } = useTaskDetails(()=> getDeviceLiveUrl()) |
| | | let { wsInfo } = useDroneWS(workspace_id) //ws信息,是一个ref对象 |
| | | |
| | | provide('wsInfo', wsInfo) |
| | | provide('isBackDock', isBackDock) |
| | | provide('workspace_id', workspace_id) |
| | | provide('deviceOsdInfo', deviceOsdInfo) |
| | | provide('dockOsdInfo', wsInfo?.value?.dock_osd) |
| | | provide('dockSn', dockSn) |
| | | provide('droneSn', droneSn) |
| | |
| | | provide('isAiLive', isAiLive) |
| | | provide('video_id', video_id) |
| | | provide('client_id', client_id) |
| | | provide('hasIr', hasIr) |
| | | |
| | | let once = true |
| | | watch(deviceOsdInfo,()=>{ |
| | | if (once){ |
| | | // getLiveCapacity() |
| | | once =false |
| | | } |
| | | }) |
| | | // 获取机巢直播 |
| | | const getDeviceLiveUrl = async () => { |
| | | const res = await liveStart(dockSn.value, 2) |
| | | currentLiveUrl.value = res.data.data.rtcs_url |
| | | } |
| | | |
| | | watch( |
| | | wsInfo, |
| | | () => { |
| | | // wsInfo 变化触发 |
| | | setCurrentLiveUrl() |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | //获取是否有红外功能 |
| | | async function getLiveCapacity() { |
| | | if (!once) return |
| | | once = false |
| | | const res = await getLiveCapacityApi({ sn: droneSn.value }) |
| | | res?.data?.data?.forEach(item => { |
| | | item?.cameras_list?.forEach(item1 => { |
| | | item1?.videos_list?.forEach(item2 => { |
| | | item2?.switch_video_types?.forEach(item3 => { |
| | | if (item3 === 'ir') { |
| | | hasIr.value = true |
| | | } |
| | | }) |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // set Ai直播 |
| | | const getAiLiveUrl = async () => { |
| | | const res = await getLiveAiLinkApi({ |
| | | original_stream_url: `${CURRENT_CONFIG.rtmpURL}${video_id.value.replace(/\//g, '-')}`, |
| | |
| | | |
| | | // 无人机直播画质切换 |
| | | const changeLineQuality = async () => { |
| | | const res = await updateDroneQualityApi({ video_id: video_id.value, video_quality: lineQuality.value }) |
| | | await updateDroneQualityApi({ video_id: video_id.value, video_quality: lineQuality.value }) |
| | | ElMessage.success('切换画质成功') |
| | | } |
| | | |
| | | // 设置当前直播地址 |
| | | const setCurrentLiveUrl = async () => { |
| | | const deviceInfo = deviceOsdInfo.value?.data?.host |
| | | const deviceInfo = wsInfo.value?.device_osd?.data?.host |
| | | if (!deviceInfo) return |
| | | const currentIsTakeOff = ![14, 0].includes(deviceInfo?.mode_code) |
| | | // 如果还是之前的状态,不切换 |
| | |
| | | isTakeOff.value ? await getDroneLiveUrl() : await getDeviceLiveUrl() |
| | | } |
| | | |
| | | watch(() => wsInfo.value?.device_osd, getLiveCapacity) |
| | | watch(wsInfo, setCurrentLiveUrl, { deep: true }) |
| | | |
| | | onMounted(() => { |
| | | getTaskDetails(props?.id) |
| | | initTaskDetails(props?.id) |
| | | EventBus.on('CurrentTaskDetails-timeStop', changeLineQuality) |
| | | EventBus.on('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl) |
| | | EventBus.on('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl) |
| | |
| | | import AmapMercatorTilingScheme from '@/utils/cesium/AmapMercatorTilingScheme' |
| | | import { Cartesian3, Terrain, Viewer } from 'cesium' |
| | | import { addBlueFilter } from '@/utils/cesium/common' |
| | | import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum' |
| | | import aircraftGltf from '@/assets/gltf/aircraft.gltf' |
| | | import { useTaskWayline } from '@/hooks/useTaskWayline/useTaskWayline' |
| | | |
| | | const { init: initTaskWayline } = useTaskWayline() |
| | | |
| | | const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({ |
| | | url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', |
| | |
| | | const taskDetailsViewer = inject('taskDetailsViewer') |
| | | |
| | | const taskDetails = inject('taskDetails') |
| | | const deviceOsdInfo = inject('deviceOsdInfo') |
| | | const wsInfo = inject('wsInfo') |
| | | |
| | | const initMap = () => { |
| | | taskDetailsViewer.value = new Viewer('currentTaskMap', { |
| | |
| | | taskDetailsViewer?.value.camera.setView({ |
| | | destination: Cartesian3.fromDegrees(115.763819, 28.787374, 5000), |
| | | }) |
| | | |
| | | initTaskWayline(taskDetailsViewer.value, wsInfo, taskDetails) |
| | | } |
| | | |
| | | let viewInfoFrustum |
| | | // 设置视椎 |
| | | const setCreateFrustum = () => { |
| | | const host = deviceOsdInfo.value?.data?.host |
| | | if (!host) return |
| | | viewInfoFrustum?.clear() |
| | | if ([14, 0].includes(host.mode_code)) return |
| | | const attitude_head = 180 + host.attitude_head |
| | | const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0 |
| | | viewInfoFrustum = new CreateFrustum(taskDetailsViewer?.value, { |
| | | position: { |
| | | longitude: host.longitude, |
| | | latitude: host.latitude, |
| | | altitude: host.height, |
| | | }, |
| | | width: 30, |
| | | height: 30, |
| | | fov: 20.0, |
| | | near: 3.0, |
| | | far: 250.0, |
| | | roll: gimbal_pitch, |
| | | pitch: 0, |
| | | heading: attitude_head, |
| | | }) |
| | | } |
| | | |
| | | function setAircraftGltf() { |
| | | const host = deviceOsdInfo.value?.data?.host |
| | | const aircraftEntity = taskDetailsViewer.value.entities.getById('aircraftGltf') |
| | | const position = Cesium.Cartesian3.fromDegrees(host.longitude, host.latitude, host.height) |
| | | if (aircraftEntity) { |
| | | aircraftEntity.position = new Cesium.ConstantPositionProperty(position) |
| | | return |
| | | } |
| | | taskDetailsViewer.value.entities.add({ |
| | | id: 'aircraftGltf', |
| | | position, |
| | | model: { |
| | | uri: aircraftGltf, // 或 .glb |
| | | scale: 1.0, // 缩放比例 |
| | | minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见) |
| | | maximumScale: 128, // 最大缩放(可选) |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | watch(deviceOsdInfo, () => { |
| | | setCreateFrustum() |
| | | setAircraftGltf() |
| | | }) |
| | | |
| | | useTaskWayline(taskDetailsViewer, taskDetails) |
| | | |
| | | const removeMap = () => { |
| | | taskDetailsViewer?.value.entities.removeAll() |
| | |
| | | <div class="title">负载控制</div> |
| | | <div |
| | | class="singleCol" |
| | | v-for="item in list1" |
| | | v-for="item in list1.filter(i => i.show)" |
| | | @click="cameraType(item)" |
| | | :key="item.key" |
| | | :class="{ active: item.key === cameraParams.camera_type }" |
| | |
| | | // 初始化喊话 |
| | | let globalShout = null |
| | | const isRecording = ref(false) |
| | | |
| | | const list1 = ref([ |
| | | { name: '广角', key: 'wide' }, |
| | | { name: '变焦', key: 'zoom' }, |
| | | { name: '红外', key: 'ir' }, |
| | | ]) |
| | | const hasIr = inject('hasIr') |
| | | const list1 = computed(() => { |
| | | return [ |
| | | { name: '广角', key: 'wide',show:true }, |
| | | { name: '变焦', key: 'zoom', show: true }, |
| | | { name: '红外', key: 'ir',show: hasIr.value }, |
| | | ] |
| | | }) |
| | | const cameraParams = ref({ |
| | | zoom_factor: 0, |
| | | camera_type: 'wide', |
| | |
| | | <div class="taskInfo"> |
| | | <div v-for="item in list" class="itemBox"> |
| | | <div class="itemName">{{ item.name }}:</div> |
| | | <div class="itemValue">{{ item.value }}</div> |
| | | <div class="itemValue" v-if="item.name !== '飞行事件'">{{ item.value }}</div> |
| | | <div class="flightEvents" v-else> |
| | | <img v-for="item in flightEvents" alt="" :src="item.img" :title="item.name"></img> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <script setup> |
| | | import droneImg from '@/assets/images/taskManagement/taskIntermediateContent/droneImg.png' |
| | | import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue' |
| | | import { droneEventList } from '@/const/drc' |
| | | |
| | | const taskDetails = inject('taskDetails') |
| | | const workspace_id = inject('workspace_id') |
| | |
| | | { name: '关联算法', value: '', field: 'ai_type_str' }, |
| | | { name: '任务描述', value: '', field: 'remark' }, |
| | | ]) |
| | | const flightEvents = ref([]) |
| | | |
| | | watch( |
| | | taskDetails, |
| | |
| | | if (item.name === '任务频次') { |
| | | const { rep_rule_type = '', rep_rule_val = '' } = taskDetails?.value || {} |
| | | item.value = rep_rule_type + ' -- ' + rep_rule_val |
| | | } |
| | | if (item.name === '飞行事件') { |
| | | const { action_modes = [] } = taskDetails?.value || {} |
| | | flightEvents.value = action_modes.flatMap(({ actionActuatorFunc }) => |
| | | droneEventList.filter(({ value }) => actionActuatorFunc === value) |
| | | ) |
| | | } |
| | | }) |
| | | }, |
| | |
| | | } |
| | | |
| | | .taskInfo { |
| | | width: 220px; |
| | | width: 230px; |
| | | height: 520px; |
| | | display: flex; |
| | | overflow: auto; |
| | |
| | | .itemValue { |
| | | font-weight: bold; |
| | | color: #ffffff; |
| | | word-break: break-all; /* 强制在任意字符断行 */ |
| | | white-space: normal; /* 允许正常换行 */ |
| | | word-break: break-all; /* 强制在任意字符断行 */ |
| | | white-space: normal; /* 允许正常换行 */ |
| | | } |
| | | |
| | | .flightEvents{ |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px 10px; |
| | | img { |
| | | width: 30px; |
| | | height: 30px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | import DeviceJobDetailsMap from './DeviceJobDetailsMap.vue' |
| | | const isShow = defineModel('show') |
| | | const infoList = ref([ |
| | | { name: '任务编号', value: '', field: 'job info num' }, |
| | | { name: '任务编号', value: '', field: 'job_info_num' }, |
| | | { name: '任务所属机巢', value: '', field: 'device_names' }, |
| | | { name: '任务名称', value: '', field: 'name' }, |
| | | { name: '所属单位', value: '', field: 'dept_name' }, |
| | | { name: '任务类型', value: '', field: 'industry_type_str' }, |
| | | { name: '任务时间', value: '', field: 'begin_time' + ' - ' + 'end_time' }, |
| | | { name: '飞行事件', value: '', field: 'event_number' }, |
| | | { name: '任务频次', value: '', field: 'rep_rule_type' + ' - ' + 'rep_rule_val' }, |
| | | { name: '任务频次', value: '', field: 'rep_rule_type rep_rule_val' }, |
| | | { name: '任务描述', value: '', field: 'remark' }, |
| | | ]) |
| | | // 机巢状态 |
| | |
| | | if (item.name === '任务时间') { |
| | | item.value = detailsData.value.begin_time.slice(0, 10) + '-' + detailsData.value.end_time.slice(0, 10) |
| | | } else if (item.name === '任务频次') { |
| | | item.value ===undefined ? '' : detailsData.value.rep_rule_type + ' -- ' + detailsData.value.rep_rule_val |
| | | const { rep_rule_type = '', rep_rule_val = '' } = detailsData?.value || {} |
| | | item.value = rep_rule_type + ' -- ' + rep_rule_val |
| | | } else { |
| | | item.value = detailsData.value?.[item.field] || '' |
| | | } |
| | |
| | | <div class="machineTableDetailsTitle"><span>关联事件</span></div> |
| | | <div class="ztzf-table"> |
| | | <el-table |
| | | :row-class-name="tableRowClassName" |
| | | :row-class-name="tableRowClassName" |
| | | :data="list" |
| | | style="width: 100%" |
| | | :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }" |
| | |
| | | <div class="processing" v-if="scope.row.status === 3">处理中</div> |
| | | <div class="done" v-if="scope.row.status === 4">已完成</div> |
| | | <div class="ended" v-if="scope.row.status === 5">已完结</div> |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="80"> |
| | |
| | | </el-table> |
| | | </div> |
| | | <el-pagination |
| | | class="ztzf-pagination" |
| | | class="ztzf-pagination" |
| | | background |
| | | :page-sizes="[10, 20, 30, 50]" |
| | | v-model:current-page="sizeParams.current" |
| | |
| | | |
| | | const list = ref() |
| | | const params = ref({ |
| | | wayLineJodInfoId: null, |
| | | way_line_jod_info_id: null, |
| | | }) |
| | | const sizeParams = ref({ |
| | | current: 1, |
| | |
| | | const store = useStore() |
| | | const child_sn = computed(() => store.state.home.singleUavHome.child_sn) |
| | | const total = ref(10) |
| | | |
| | | const distribution = row => { |
| | | ElMessage.warning('正在加急开发中...') |
| | | } |
| | | const examine = row => { |
| | | ElMessage.warning('正在加急开发中...') |
| | | const orderNumber = row.event_num |
| | | const adminUrl = import.meta.env.VITE_APP_ADMIN_URL |
| | | const targetPath = `/tickets/ticket?orderNumber=${orderNumber}`; |
| | | window.open(`${adminUrl}?redirect=${encodeURIComponent(targetPath)}`, '_blank'); |
| | | } |
| | | const wayLineJodInfoId = inject('wayLineJodInfoId') |
| | | |
| | | |
| | | const getList = () => { |
| | | params.value.wayLineJodInfoId = wayLineJodInfoId.value |
| | | params.value.way_line_jod_info_id = wayLineJodInfoId.value |
| | | |
| | | getDeviceEventList(params.value, sizeParams.value).then(res => { |
| | | const resData = res?.data?.data || {} |
| | | list.value = resData.records |
| | |
| | | } |
| | | |
| | | // 待处理 |
| | | .pending{ |
| | | color: #FF7411; |
| | | .pending { |
| | | color: #ff7411; |
| | | } |
| | | // 待审核 |
| | | .reviewed{ |
| | | color: #8CFEA7; |
| | | .reviewed { |
| | | color: #8cfea7; |
| | | } |
| | | // 处理中 |
| | | .processing{ |
| | | color: #FFC398; |
| | | .processing { |
| | | color: #ffc398; |
| | | } |
| | | // 已完成 |
| | | .done{ |
| | | color: #AFD9FB; |
| | | .done { |
| | | color: #afd9fb; |
| | | } |
| | | // 已完结 |
| | | .ended{ |
| | | color: #11C4FF; |
| | | .ended { |
| | | color: #11c4ff; |
| | | } |
| | | </style> |
| | |
| | | <script setup> |
| | | import { fullscreenToggel } from '@/utils/util'; |
| | | import { useStore } from 'vuex'; |
| | | import { ElMessage } from 'element-plus' |
| | | const router = useRouter(); |
| | | const store = useStore(); |
| | | const dropdownClick = val => { |
| | |
| | | } |
| | | |
| | | const info = () =>{ |
| | | ElMessage.warning('加急开发中...') |
| | | console.log('点击了个人信息'); |
| | | } |
| | | </script> |
| | |
| | | { min: 315, max: 360, value: '北偏西' }, |
| | | { min: 360, max: 360, value: '正北' } |
| | | ]; |
| | | |
| | | import hoverImg from '@/assets/images/aiNowFly/event/hover.png' |
| | | import startRecordImg from '@/assets/images/aiNowFly/event/startRecord.png' |
| | | import takePhotoImg from '@/assets/images/aiNowFly/event/takePhoto.png' |
| | | export const droneEventList = [ |
| | | {name:'开始录像',value:'startRecord',img:startRecordImg}, |
| | | {name:'悬停',value:'hover',img:hoverImg}, |
| | | {name:'拍照',value:'takePhoto',img:takePhotoImg}, |
| | | ] |
| | |
| | | * @Author: shuishen 1109946754@qq.com |
| | | * @Date: 2025-04-19 14:24:34 |
| | | * @LastEditors: shuishen 1109946754@qq.com |
| | | * @LastEditTime: 2025-04-19 15:23:57 |
| | | * @LastEditTime: 2025-04-20 17:53:08 |
| | | * @FilePath: \command-center-dashboard\src\hooks\useTaskWayline\useTaskWayline.js |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2025 by shuishen, All Rights Reserved. |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2025 by shuishen, All Rights Reserved. |
| | | */ |
| | | import lineImg from '@/assets/images/arrow-right-blue.png' |
| | | import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png' |
| | |
| | | |
| | | import * as Cesium from 'cesium' |
| | | import { Cartesian3 } from 'cesium' |
| | | import aircraftGltf from '@/assets/gltf/aircraft.gltf' |
| | | import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum' |
| | | |
| | | export function useTaskWayline (viewer, taskDetails) { |
| | | const newViewer = unref(viewer) |
| | | export function useTaskWayline () { |
| | | let viewer = null |
| | | let deviceOsdInfo = null |
| | | let flighttaskProgressInfo = null |
| | | |
| | | // watch |
| | | let taskWatch = null |
| | | let flighttaskWatch = null |
| | | let deviceWatch = null |
| | | |
| | | // 航线位置 |
| | | let currentWaylinePostions = [] |
| | | // 当前航点 下标 |
| | | let currentWaypointIndex = null |
| | | let droneSpeedArr = [] |
| | | |
| | | // 解析kmz文件 |
| | | const parsingFiles = async url => { |
| | |
| | | const waylinesXMLJSON = XMLToJSON(waylinesXML)?.['Document'] |
| | | const waylinesXMLObj = removeTextKey(waylinesXMLJSON.Folder) |
| | | if (!waylinesXMLObj.Placemark.length) return |
| | | const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(',')) |
| | | flyVisual(allPoint, newViewer) |
| | | // const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(',')) |
| | | // flyVisual(allPoint, viewer) |
| | | drawWayline(waylinesXMLObj) |
| | | } |
| | | |
| | | const drawWayline = lineObj => { |
| | | const positions = lineObj.Placemark.map(item => { |
| | | currentWaylinePostions = lineObj.Placemark.map(item => { |
| | | const [lon, lat] = item.Point.coordinates.split(',') |
| | | return Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | }) |
| | | |
| | | removeEntitys() |
| | | |
| | | // 起点 |
| | | newViewer.entities.add({ |
| | | viewer.entities.add({ |
| | | id: 'drone-job-wayline-start', |
| | | position: positions[0], |
| | | position: currentWaylinePostions[0], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(rwqfdImg), |
| | | width: 70, |
| | |
| | | }) |
| | | |
| | | // 终点 |
| | | newViewer.entities.add({ |
| | | viewer.entities.add({ |
| | | id: 'drone-job-wayline-end', |
| | | position: positions[positions.length - 1], |
| | | position: currentWaylinePostions[currentWaylinePostions.length - 1], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(endPointImg), |
| | | width: 30, |
| | |
| | | }) |
| | | |
| | | // 路径线 |
| | | newViewer.entities.add({ |
| | | let polylineEntity = viewer.entities.add({ |
| | | id: 'drone-job-wayline-polyline', |
| | | polyline: { |
| | | width: 4, |
| | | positions: positions, |
| | | positions: currentWaylinePostions, |
| | | material: new ImageTrailMaterial({ |
| | | color: { alpha: 1, blue: 1, green: 1, red: 1 }, |
| | | speed: 20, |
| | |
| | | clampToGround: false, |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | watch(taskDetails, () => { |
| | | if (taskDetails.value?.way_lines?.length) { |
| | | parsingFiles(taskDetails.value.way_lines[0].url) |
| | | } |
| | | }, { immediate: true }) |
| | | |
| | | const removeEntitys = () => { |
| | | const entitiesIDs = newViewer?.entities.values.map(i => i.id) |
| | | |
| | | entitiesIDs.forEach(item => { |
| | | item.includes('drone-job-wayline-') && newViewer?.entities.removeById(item) |
| | | viewer.flyTo(polylineEntity, { |
| | | offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0), |
| | | duration: 0.5, |
| | | }) |
| | | } |
| | | |
| | | let viewInfoFrustum |
| | | // 设置视椎 |
| | | const setCreateFrustum = (host) => { |
| | | if (!host) return |
| | | viewInfoFrustum?.clear() |
| | | |
| | | const attitude_head = 180 + host?.attitude_head |
| | | const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0 |
| | | |
| | | viewInfoFrustum = new CreateFrustum(viewer, { |
| | | position: { |
| | | longitude: host?.longitude, |
| | | latitude: host?.latitude, |
| | | altitude: host?.height, |
| | | }, |
| | | width: 30, |
| | | height: 30, |
| | | fov: 20.0, |
| | | near: 3.0, |
| | | far: 250.0, |
| | | roll: gimbal_pitch, |
| | | pitch: 0, |
| | | heading: attitude_head, |
| | | }) |
| | | } |
| | | |
| | | function setAircraftGltf () { |
| | | const host = deviceOsdInfo.value?.data?.host |
| | | |
| | | const aircraftEntity = viewer?.entities.getById('aircraftGltf') |
| | | const position = Cesium.Cartesian3.fromDegrees(host?.longitude, host?.latitude, host?.height) |
| | | |
| | | if (aircraftEntity) { |
| | | aircraftEntity.position = new Cesium.ConstantPositionProperty(position) |
| | | |
| | | const homeDistance = Math.floor(host?.home_distance) || 0 |
| | | |
| | | // 距离下一个航点 |
| | | const nextPoint = currentWaylinePostions[currentWaypointIndex] |
| | | |
| | | if (!nextPoint) { |
| | | aircraftEntity.label = {} |
| | | return |
| | | } |
| | | |
| | | const devicePosition = Cesium.Cartesian3.fromDegrees( |
| | | Number(host.longitude), |
| | | Number(host.latitude), |
| | | 0, |
| | | ) |
| | | |
| | | // 距离下个点位的距离 |
| | | let distance = Cesium.Cartesian3.distance( |
| | | devicePosition, |
| | | nextPoint, |
| | | ) |
| | | |
| | | // 本次航线平面里程 |
| | | let totalDistance = 0 |
| | | currentWaylinePostions.map((cartesian3, index) => { |
| | | // 两点之间的距离 |
| | | let deviceCurPosition = null |
| | | if (index === 0) { |
| | | deviceCurPosition = devicePosition |
| | | } else { |
| | | deviceCurPosition = currentWaylinePostions[index - 1] |
| | | } |
| | | |
| | | let distance = Cesium.Cartesian3.distance( |
| | | deviceCurPosition, |
| | | cartesian3, |
| | | ) |
| | | totalDistance += distance |
| | | return Math.round(distance) |
| | | }) |
| | | |
| | | // 速度 |
| | | let horizontalSpeed = host.horizontal_speed || 0 |
| | | if ( |
| | | !droneSpeedArr.includes(horizontalSpeed) && |
| | | horizontalSpeed > 1 |
| | | ) { |
| | | droneSpeedArr.push(horizontalSpeed) |
| | | } |
| | | if (horizontalSpeed < 5) { |
| | | horizontalSpeed = 10 |
| | | } |
| | | |
| | | // 预计到达下一个航点时间 |
| | | let arrivalTime = distance / horizontalSpeed |
| | | if (arrivalTime === Infinity || isNaN(arrivalTime)) { |
| | | arrivalTime = 0 |
| | | } |
| | | if (arrivalTime > 60) { |
| | | const minute = Math.floor(arrivalTime / 60) |
| | | const second = Math.round(arrivalTime % 60) |
| | | arrivalTime = `${minute}m${second}s` |
| | | } else { |
| | | arrivalTime = Math.round(arrivalTime) + 's' |
| | | } |
| | | |
| | | aircraftEntity.label = new Cesium.LabelGraphics({ |
| | | text: `距离机场水平距离:${homeDistance}m\n距离下一个航点:${Math.round(distance)}m\n预计到达下一航点时间:${arrivalTime}\n本次航线平面里程:${Math.round(totalDistance)}m`, |
| | | font: '13px monospace', |
| | | showBackground: true, |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
| | | disableDepthTestDistance: Number.POSITIVE_INFINITY, |
| | | pixelOffset: new Cesium.Cartesian2(0, -40), |
| | | show: true, |
| | | }) |
| | | |
| | | return |
| | | } |
| | | |
| | | viewer?.entities.add({ |
| | | id: 'aircraftGltf', |
| | | position, |
| | | label: {}, |
| | | model: { |
| | | uri: aircraftGltf, // 或 .glb |
| | | scale: 1.0, // 缩放比例 |
| | | minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见) |
| | | maximumScale: 128, // 最大缩放(可选) |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | const mapEntityRemove = () => { |
| | | viewInfoFrustum?.clear() |
| | | |
| | | viewer?.entities.removeById('aircraftGltf') |
| | | } |
| | | |
| | | const removeEntitys = () => { |
| | | const entitiesIDs = viewer?.entities.values.map(i => i.id) |
| | | |
| | | Array.isArray(entitiesIDs) && entitiesIDs.forEach(item => { |
| | | item.includes('drone-job-wayline-') && viewer?.entities.removeById(item) |
| | | }) |
| | | } |
| | | |
| | | const removeWatchs = () => { |
| | | taskWatch?.() |
| | | flighttaskWatch?.() |
| | | deviceWatch?.() |
| | | } |
| | | |
| | | const init = (v, wsInfo, taskDetails) => { |
| | | viewer = v |
| | | deviceOsdInfo = computed(() => wsInfo.value?.device_osd) |
| | | flighttaskProgressInfo = computed(() => wsInfo.value?.flighttask_progress) |
| | | |
| | | removeWatchs() |
| | | |
| | | taskWatch = watch(taskDetails, |
| | | () => { |
| | | if (taskDetails.value?.way_lines?.length) { |
| | | parsingFiles(taskDetails.value.way_lines[0].url) |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ) |
| | | |
| | | flighttaskWatch = watch(flighttaskProgressInfo, async () => { |
| | | const output = flighttaskProgressInfo.value?.data?.output |
| | | |
| | | currentWaypointIndex = output.ext['current_waypoint_index'] |
| | | }) |
| | | |
| | | deviceWatch = watch(deviceOsdInfo, () => { |
| | | const host = deviceOsdInfo.value?.data?.host |
| | | |
| | | if (!host) return |
| | | |
| | | if ([14, 0].includes(host?.mode_code)) { |
| | | mapEntityRemove() |
| | | return |
| | | } |
| | | |
| | | setCreateFrustum(host) |
| | | setAircraftGltf() |
| | | } |
| | | ) |
| | | } |
| | | |
| | | onBeforeUnmount(() => { |
| | | mapEntityRemove() |
| | | removeEntitys() |
| | | |
| | | removeWatchs() |
| | | }) |
| | | |
| | | return { |
| | | removeEntitys |
| | | init, |
| | | removeEntitys, |
| | | mapEntityRemove, |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | const handleClick = ({ path, name }) => { |
| | | if (['系统运维'].includes(name)) { |
| | | window.open(import.meta.env.VITE_APP_ADMIN_URL + '?token=' + localStorage.getItem(ELocalStorageKey.Token), '_blank'); |
| | | window.open(import.meta.env.VITE_APP_ADMIN_URL, '_blank'); |
| | | return; |
| | | } |
| | | if (!['首页', '任务管理'].includes(name)) return ElMessage.warning('正在加急开发中...'); |
| | |
| | | border: 1px solid !important; |
| | | border-radius: 0px 0px 8px 8px; |
| | | border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1 !important; |
| | | /* 修改箭头样式 */ |
| | | .el-popper__arrow { |
| | | &::before { |
| | | background: #0d3556 !important; |
| | |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | /* 修改头部背景色 */ |
| | | |
| | | .custom-date-picker .el-picker-panel__header { |
| | | background: linear-gradient(180deg, rgba(13, 53, 86, 0.85) 0%, rgba(1, 35, 80, 0.85) 100%) !important; |
| | | color: #fff !important; |
| | | } |
| | | .el-date-table { |
| | | th { |
| | | color: #fff !important; /* 星期标题颜色 */ |
| | | color: #fff !important; |
| | | } |
| | | } |
| | | /* 修改日期单元格悬停/选中状态 */ |
| | | |
| | | .custom-date-picker .el-date-table td:hover, |
| | | .custom-date-picker .el-date-table td.current:not(.disabled) { |
| | | background: rgba(60, 121, 202) !important; |
| | | color: white !important; |
| | | } |
| | | // 头部按钮 |
| | | |
| | | .el-date-table td.start-date span, |
| | | .el-date-table td.start-date span, |
| | | .el-date-table td.end-date span { |
| | |
| | | overflow-x: hidden !important; |
| | | margin-right: 0 !important; |
| | | } |
| | | /* 箭头样式 */ |
| | | |
| | | .el-popper__arrow::before { |
| | | background: #0d3556 !important; |
| | | border: 1px solid #0d3556 !important; |
| | | } |
| | | .el-select { |
| | | --el-select-border-color-hover: rgb(0, 162, 255) !important; |
| | | /* // 修改下拉框hover的默认样式 */ |
| | | |
| | | } |
| | | |
| | | .el-input { |
| | | --el-border-color: rgb(0, 162, 255); |
| | | /* // 修改下拉框的边框 */ |
| | | |
| | | } |
| | | |
| | | .el-select .el-input__wrapper { |
| | | background-color: #012350 !important; |
| | | /* // 外层下拉框背景 */ |
| | | |
| | | } |
| | | |
| | | .el-input__wrapper { |
| | | --el-input-text-color: #012350 !important; /* // 修改外层下拉框的颜色 */ |
| | | --el-input-text-color: #012350 !important; |
| | | } |
| | | |
| | | .el-select__popper.el-popper { |
| | | border: rgba(0, 27, 63) !important; |
| | | /* // 修改内部下拉框的边框颜色 */ |
| | | |
| | | } |
| | | |
| | | .el-select-dropdown__wrap { |
| | |
| | | border-radius: 0px 0px 8px 8px; |
| | | border: 1px solid; |
| | | border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1; |
| | | /* // 下拉框背景色 */ |
| | | |
| | | } |
| | | |
| | | .el-select-dropdown__item { |
| | | background: rgba(0, 27, 63) !important; /* // 下拉框选项的颜色 */ |
| | | background: #012350 !important; |
| | | } |
| | | |
| | | .el-select-dropdown__item { |
| | |
| | | text-transform: none; |
| | | background: linear-gradient(90deg, #fbfdff 0%, #86d4ff 100%); |
| | | margin-left: 16px; |
| | | -webkit-background-clip: text; /* 背景被裁剪成文字的前景色 */ |
| | | -webkit-text-fill-color: transparent; /* 文字填充颜色变透明 */ |
| | | -webkit-background-clip: text; |
| | | -webkit-text-fill-color: transparent; |
| | | } |
| | | .el-dialog .el-dialog__header { |
| | | /* margin: 0px !important; */ |
| | | |
| | | padding: 0px !important; |
| | | padding-left: 0px !important; |
| | | } |
| | |
| | | background: #13c6ff !important; |
| | | } |
| | | } |
| | | /* 时间选择器下拉面板 */ |
| | | .custom-time-picker { |
| | | /* 整体背景和边框 */ |
| | | background: linear-gradient( 180deg, rgba(13,53,86,0.85) 0%, rgba(1,35,80,0.85) 100%) !important; |
| | | border-radius: 0px 0px 8px 8px; |
| | | border: 1px solid !important; |
| | | border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1 !important; |
| | | |
| | | /* 修改箭头样式 */ |
| | | .el-popper__arrow::before { |
| | | background: #0D3556 !important; |
| | | border: 1px solid #479DFF !important; |
| | | } |
| | | |
| | | /* 时间面板头部 */ |
| | | .el-time-panel__header { |
| | | background: #012350 !important; |
| | | color: #FFFFFF !important; |
| | | border-bottom: 1px solid rgba(71, 157, 255, 0.3) !important; |
| | | } |
| | | |
| | | /* 时间选择区域 */ |
| | | .el-time-panel__content { |
| | | background: #012350 !important; |
| | | |
| | | /* 时间数字项 */ |
| | | .el-time-spinner__item { |
| | | color: #E6E6E6 !important; |
| | | |
| | | &:hover { |
| | | background: rgba(71, 157, 255, 0.3) !important; |
| | | } |
| | | |
| | | &.active { |
| | | color: #479DFF !important; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | .el-time-panel__footer { |
| | | background: #012350 !important; |
| | | border-top: 1px solid rgba(71, 157, 255, 0.3) !important; |
| | | |
| | | .el-button { |
| | | color: #fff !important; |
| | | &:hover { |
| | | color: #479DFF !important; |
| | | } |
| | | } |
| | | |
| | | .el-time-panel__btn.cancel { |
| | | color: #fff !important; |
| | | &:hover { |
| | | color: #fff !important; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | <!-- todo--> |
| | | <el-form-item label="飞行事件"> |
| | | <div class="event"> |
| | | <img src="@/assets/images/aiNowFly/picture-recording.png" alt=""> |
| | | <img src="../../assets/images/aiNowFly/event/startRecord.png" alt=""> |
| | | <div class="img-close" v-show="isPhoto"> |
| | | <img @click="isPhoto=false" class="close" src="@/assets/images/aiNowFly/close.png" alt=""> |
| | | <img src="@/assets/images/aiNowFly/photo.png" alt=""> |
| | | <img src="../../assets/images/aiNowFly/event/takePhoto.png" alt=""> |
| | | </div> |
| | | <div class="img-close" v-show="isStop"> |
| | | <img @click="isStop=false" class="close" src="@/assets/images/aiNowFly/close.png" alt=""> |
| | | <img src="@/assets/images/aiNowFly/stop.png" alt=""> |
| | | <img src="../../assets/images/aiNowFly/event/hover.png" alt=""> |
| | | </div> |
| | | <div class="add-event" @click="isShowEvent = !isShowEvent">+ |
| | | <div class="event-select" v-show="isShowEvent"> |
| | |
| | | label: { |
| | | text: `预计${item.minute}分钟`, |
| | | font: 'bold 16px Source Han Sans CN', // 加粗并增大字号 |
| | | // fillColor: new Cesium.Color(27/255, 179/255, 255/255, 1.0), |
| | | // fillColor: new Cesium.Color(27/255, 179/255, 255/255, 1.0), |
| | | // fillColor: Cesium.Color.WHITE, |
| | | // style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | // verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | |
| | | :deep(.el-select__wrapper) { |
| | | background-color: #021740; |
| | | box-shadow: 0 0 0 1px #026AD6; |
| | | |
| | | |
| | | &.is-focus { |
| | | box-shadow: 0 0 0 1px #026AD6; |
| | | } |
| | | } |
| | | |
| | | |
| | | :deep(.el-input__wrapper.is-disabled) { |
| | | background-color: #021740; |
| | | box-shadow: 0 0 0 1px #026AD6; |
| | |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | |
| | | .btn-submit { |
| | | cursor: pointer; |
| | | margin-left: 88px; |
| | |
| | | <img class="completion-left-img" :src="completionLeft" alt="" /> |
| | | <div class="completion-text">事件类型完成率情况</div> |
| | | <div class="completion-separator"></div> |
| | | <img class="completion-left-img" :src="completionLeft" alt="" /> |
| | | <img class="completion-left-img" :src="leftTriangle" alt="" /> |
| | | </div> |
| | | |
| | | <div class="chart" ref="echartsRef"></div> |
| | |
| | | import overviewImg5 from '@/assets/images/home/homeRight/overview5.png' |
| | | import overviewImg6 from '@/assets/images/home/homeRight/overview6.png' |
| | | import completionLeft from '@/assets/images/home/homeRight/completionLeft.png' |
| | | import leftTriangle from '@/assets/images/home/homeRight/leftTriangle.png' |
| | | import * as echarts from 'echarts' |
| | | import CommonDateTime from '@/components/CommonDateTime.vue' |
| | | import VSelectLoad from '@/directive/selectLoad' |
| | |
| | | width: 2, // 线条宽度 |
| | | type: 'solid', // 线条类型 |
| | | }, |
| | | tooltip: { |
| | | valueFormatter: (value) => value + '%' |
| | | }, |
| | | symbol: 'circle', // 数据点符号 |
| | | symbolSize: 6, // 数据点符号大小 |
| | | emphasis: { |
| | |
| | | import tc from '@/assets/images/rSide/tc.png' |
| | | import tc1 from '@/assets/images/rSide/tc1.png' |
| | | import cesiumOperation from '@/utils/cesium-tsa' |
| | | import { ElMessage } from 'element-plus' |
| | | |
| | | let logIndex = ref(3) |
| | | const enterHover = value => { |
| | |
| | | activeIndex.value = activeIndex.value === 1 ? null : value |
| | | } |
| | | if (value === 2) { |
| | | ElMessage.warning('加急开发中...') |
| | | activeIndex.value = activeIndex.value === 2 ? null : value |
| | | } |
| | | } |
| | |
| | | }, |
| | | ], |
| | | } |
| | | |
| | | import _ from 'lodash' |
| | | // chart.setOption(option); |
| | | |
| | | const pieOption = { |
| | |
| | | tarValue = data[i].value |
| | | } |
| | | } |
| | | let percentage = ((tarValue / total) * 100).toFixed(1) |
| | | let percentage = total ? _.round(((tarValue / total) * 100),1) : 0 |
| | | return `${name} ${percentage}%` |
| | | }, |
| | | }, |
| | |
| | | { value: 0, name: '处理中', itemStyle: { color: '#FFC398' } }, |
| | | { value: 0, name: '已完成', itemStyle: { color: '#AFD9FB' } }, |
| | | // { value: 0, name: '待分拨', itemStyle: { color: '#E9C81A' } }, |
| | | |
| | | |
| | | { value: 0, name: '已完结', itemStyle: { color: '#11C4FF' } }, |
| | | ], |
| | | }, |
| | |
| | | :infinite-scroll-disabled="busy" |
| | | infinite-scroll-immediate="true" |
| | | > |
| | | > |
| | | <div class="item" v-for="(item, index) in tableList"> |
| | | <div class="left" @click="taskClick(item)"> |
| | | <div class="left-t"> |
| | |
| | | import { useStore } from 'vuex' |
| | | import { useTaskWayline } from '@/hooks/useTaskWayline/useTaskWayline' |
| | | import { useTaskDetails } from '@/hooks/useTaskDetails/useTaskDetails' |
| | | import { useTaskViewInfo } from '@/hooks/useTaskViewInfo/useTaskViewInfo' |
| | | import { useDroneWS } from '@/hooks/useDroneWS' |
| | | let viewer = null |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | watch([() => tabIndex.value, () => tableList.value], async ([newTabIndex, newTableList]) => { |
| | | if (newTabIndex == 1 && newTableList.length > 0) { |
| | | await getTaskDetails(newTableList[0].wayline_job_info_id) |
| | | } |
| | | }) |
| | | |
| | | const { init: initTaskWayline, removeEntitys } = useTaskWayline() |
| | | |
| | | onMounted(async () => { |
| | | viewer = window.$viewer |
| | | |
| | | await getJobList() |
| | | |
| | | // tableList.value = [ |
| | | // { |
| | | // id: 11563, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 05:46:25', |
| | | // end_time: '2025/04/19 05:46:25', |
| | | // create_time: '2025-04-19T05:46:36.032+00:00', |
| | | // name: '智引即飞202504191252', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 340, |
| | | // job_id: '484a7846-60e0-4ec3-b9fb-272a055c6938', |
| | | // }, |
| | | // { |
| | | // id: 11559, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 05:39:42', |
| | | // end_time: '2025/04/19 05:39:42', |
| | | // create_time: '2025-04-19T05:39:52.022+00:00', |
| | | // name: '智引即飞202504191252', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 340, |
| | | // job_id: 'b8c58bfb-4352-47c5-ba33-242eec8df188', |
| | | // }, |
| | | // { |
| | | // id: 11558, |
| | | // status: 3, |
| | | // begin_time: '2025/04/19 05:39:17', |
| | | // end_time: '2025/04/19 05:39:17', |
| | | // create_time: '2025-04-19T05:39:27.407+00:00', |
| | | // name: '智引即飞202504191252', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 340, |
| | | // job_id: '839773ce-bd46-4947-a2ef-d859eaea82f6', |
| | | // }, |
| | | // { |
| | | // id: 11557, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 04:52:04', |
| | | // end_time: '2025/04/19 04:52:04', |
| | | // create_time: '2025-04-19T04:52:14.503+00:00', |
| | | // name: '智引即飞202504191252', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 340, |
| | | // job_id: '58366fd4-8361-456f-8ad9-3b881f933620', |
| | | // }, |
| | | // { |
| | | // id: 11556, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 03:45:06', |
| | | // end_time: '2025/04/19 03:45:06', |
| | | // create_time: '2025-04-19T03:45:16.522+00:00', |
| | | // name: '智引即飞202504191145', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 338, |
| | | // job_id: '39c60fb8-e5c4-4474-912a-c3af3f1b9054', |
| | | // }, |
| | | // { |
| | | // id: 11555, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 03:27:55', |
| | | // end_time: '2025/04/19 03:27:55', |
| | | // create_time: '2025-04-19T03:28:05.196+00:00', |
| | | // name: '智引即飞202504191127', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 336, |
| | | // job_id: '78c42532-45e4-4a01-b698-69bca19286ff', |
| | | // }, |
| | | // { |
| | | // id: 11554, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 02:58:53', |
| | | // end_time: '2025/04/19 02:58:53', |
| | | // create_time: '2025-04-19T02:59:03.602+00:00', |
| | | // name: '智引即飞202504191058', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 335, |
| | | // job_id: 'd3b25edc-ec23-4ad6-800a-0f659a72bff3', |
| | | // }, |
| | | // { |
| | | // id: 11553, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 02:52:21', |
| | | // end_time: '2025/04/19 02:52:21', |
| | | // create_time: '2025-04-19T02:52:31.415+00:00', |
| | | // name: '智引即飞202504191052', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 334, |
| | | // job_id: 'e27090f1-e740-4ae4-8d4d-301354eb0bbc', |
| | | // }, |
| | | // { |
| | | // id: 11548, |
| | | // status: 5, |
| | | // begin_time: '2025/04/19 02:23:06', |
| | | // end_time: '2025/04/19 02:23:06', |
| | | // create_time: '2025-04-19T02:23:16.151+00:00', |
| | | // name: '智引即飞202504191023', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 332, |
| | | // job_id: '9e1f7283-fe34-4cfd-b468-cd2b34a96d34', |
| | | // }, |
| | | // { |
| | | // id: 11547, |
| | | // status: 3, |
| | | // begin_time: '2025/04/19 02:18:24', |
| | | // end_time: '2025/04/19 02:18:24', |
| | | // create_time: '2025-04-19T02:18:34.590+00:00', |
| | | // name: '智引即飞202504191018', |
| | | // event_number: 0, |
| | | // dock_sn: '7CTDLCR00BQBM2', |
| | | // wayline_job_info_id: 331, |
| | | // job_id: '7aa5222c-2f8b-401e-b6ba-d6a550398829', |
| | | // }, |
| | | // ] |
| | | |
| | | if (tableList.value.length > 0) { |
| | | await getTaskDetails(tableList.value[0].wayline_job_info_id) |
| | | } |
| | | initTaskWayline(viewer, wsInfo, taskDetails) |
| | | }) |
| | | |
| | | const { removeEntitys } = useTaskWayline(viewer || window.$viewer, taskDetails) |
| | | |
| | | useTaskViewInfo(viewer || window.$viewer, wsInfo, removeEntitys) |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | <!-- 机巢状态 --> |
| | | <template> |
| | | <CommonTitle title="机巢状态" @details="detailsFun" /> |
| | | <div :style="{ marginLeft: pxToRem(14) }"> |
| | | <div class="machine-status"> |
| | | <div class="info"> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/wrj.png" alt=""> |
| | | <div class="info-right"> |
| | | <!-- <div class="name">{{ osdVisible?.callsign || '--' }}</div> --> |
| | | <div class="name">{{ osdVisible?.nickname || '--' }}</div> |
| | | <div class="wz"> |
| | | <span class="left">当前位置:</span> |
| | | <span class="right">{{ detailInfo.longitude }},{{ detailInfo.latitude }}</span> |
| | | </div> |
| | | <div class="close-wb"> |
| | | <div class="close" :class="AircraftStatus == undefined ? '' : 'other'"> |
| | | {{ AircraftStatus == undefined ? '舱内关机' : AircraftStatus }} |
| | | </div> |
| | | <!-- <div class="wb">需要维保</div> --> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="status"> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/height.png" alt=""> |
| | | <span class="text">实时真高</span> |
| | | </div> |
| | | <div class="text-data">{{ detailInfo.height || '--' }}<span class="text">米</span></div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/speed.png" alt=""> |
| | | <span class="text">飞行速度</span> |
| | | </div> |
| | | <div class="text-data">{{ detailInfo.horizontal_speed }}<span class="text">米/秒</span></div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/signal.png" alt=""> |
| | | <span class="text">信号强度</span> |
| | | </div> |
| | | <div class="text-data">{{ detailInfo.quality }}</div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/electricity.png" alt=""> |
| | | <span class="text">电池电量</span> |
| | | </div> |
| | | <div v-if="drone_charge_state.capacity_percent != 0" class="text-data"> |
| | | {{ drone_charge_state.capacity_percent }}<span class="text">%</span> |
| | | </div> |
| | | <div v-else class="text-data">{{ detailInfo.capacity_percent }}<span class="text">%</span></div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/distance.png" alt=""> |
| | | <span class="text">飞行距离</span> |
| | | </div> |
| | | <div class="text-data">{{ singleTotal.flight_mileage }}<span class="text">km</span></div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/duration.png" alt=""> |
| | | <span class="text">飞行时长</span> |
| | | </div> |
| | | <div class="text-data">{{ singleTotal.hour_count }}<span class="text">h</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <MachineTableDetails v-model:show="isShowDetails"/> |
| | | <CommonTitle title="机巢状态" @details="detailsFun" /> |
| | | <div :style="{ marginLeft: pxToRem(14) }"> |
| | | <div class="machine-status"> |
| | | <div class="info"> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/wrj.png" alt="" /> |
| | | <div class="info-right"> |
| | | <!-- <div class="name">{{ osdVisible?.callsign || '--' }}</div> --> |
| | | <div class="name">{{ osdVisible?.nickname || '--' }}</div> |
| | | <div class="wz"> |
| | | <span class="left">当前位置:</span> |
| | | <span class="right">{{ detailInfo.longitude }},{{ detailInfo.latitude }}</span> |
| | | </div> |
| | | <div class="close-wb"> |
| | | <div class="close" :class="AircraftStatus == undefined ? '' : 'other'"> |
| | | {{ AircraftStatus == undefined ? '舱内关机' : AircraftStatus }} |
| | | </div> |
| | | <!-- <div class="wb">需要维保</div> --> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="status"> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/height.png" alt="" /> |
| | | <span class="text">实时真高</span> |
| | | </div> |
| | | <div class="text-data"> |
| | | {{ detailInfo.height || '--' }} |
| | | <span class="text">米</span> |
| | | </div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/speed.png" alt="" /> |
| | | <span class="text">飞行速度</span> |
| | | </div> |
| | | <div class="text-data"> |
| | | {{ detailInfo.horizontal_speed }} |
| | | <span class="text">米/秒</span> |
| | | </div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/signal.png" alt="" /> |
| | | <span class="text">信号强度</span> |
| | | </div> |
| | | <div class="text-data">{{ detailInfo.quality }}</div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/electricity.png" alt="" /> |
| | | <span class="text">电池电量</span> |
| | | </div> |
| | | <div v-if="drone_charge_state.capacity_percent != 0" class="text-data"> |
| | | {{ drone_charge_state.capacity_percent }} |
| | | <span class="text">%</span> |
| | | </div> |
| | | <div v-else class="text-data"> |
| | | {{ detailInfo.capacity_percent }} |
| | | <span class="text">%</span> |
| | | </div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/distance.png" alt="" /> |
| | | <span class="text">飞行距离</span> |
| | | </div> |
| | | <div class="text-data"> |
| | | {{ singleTotal.flight_mileage }} |
| | | <span class="text">km</span> |
| | | </div> |
| | | </div> |
| | | <div class="card"> |
| | | <div> |
| | | <img src="../../../../assets/images/signMachineNest/machineRight/duration.png" alt="" /> |
| | | <span class="text">飞行时长</span> |
| | | </div> |
| | | <div class="text-data"> |
| | | {{ singleTotal.hour_count }} |
| | | <span class="text">h</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <MachineTableDetails v-model:show="isShowDetails" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import CommonTitle from '@/components/CommonTitle.vue'; |
| | | import { EDeviceTypeName } from '@/utils/staticData/enums.js'; |
| | | import { EModeCode, EDockModeText, EModeText } from '@/utils/staticData/device'; |
| | | import { getLnglatAltitude } from '@/utils/cesium/mapUtil.js'; |
| | | import { useStore } from 'vuex'; |
| | | import MachineTableDetails from '@/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue'; |
| | | import CommonTitle from '@/components/CommonTitle.vue' |
| | | import { EDeviceTypeName } from '@/utils/staticData/enums.js' |
| | | import { EModeCode, EDockModeText, EModeText } from '@/utils/staticData/device' |
| | | import { getLnglatAltitude } from '@/utils/cesium/mapUtil.js' |
| | | import { useStore } from 'vuex' |
| | | import MachineTableDetails from '@/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue' |
| | | |
| | | const store = useStore(); |
| | | const store = useStore() |
| | | // 获取机巢信息 |
| | | let osdVisible = ref({});//computed(() => store.state.home.osdVisible); |
| | | const singleUavHome = computed(() => store.state.home.singleUavHome); |
| | | let osdVisible = ref({}) //computed(() => store.state.home.osdVisible); |
| | | const singleUavHome = computed(() => store.state.home.singleUavHome) |
| | | // 单个机巢统计数据 |
| | | const singleTotal = computed(() => store.state.home.singleTotal); |
| | | const singleTotal = computed(() => store.state.home.singleTotal) |
| | | // 是否展示机机巢状态详情 |
| | | let isShowDetails = ref(false); |
| | | let isShowDetails = ref(false) |
| | | |
| | | let str = '--'; |
| | | let str = '--' |
| | | let drone_charge_state = ref({ |
| | | capacity_percent: '--', |
| | | state: 0 |
| | | capacity_percent: '--', |
| | | state: 0, |
| | | }) |
| | | let AircraftStatus = ref(null); |
| | | let AircraftStatus = ref(null) |
| | | let detailInfo = ref({ |
| | | longitude: '--', |
| | | latitude: '--', |
| | | home_distance: '--', |
| | | quality: '--', |
| | | horizontal_speed: '--', |
| | | height: '--', |
| | | remain_flight_time: '--', |
| | | capacity_percent: '--', |
| | | }); |
| | | let quality = ref(['弱', '较弱', '中等', '较强', '强']); |
| | | longitude: '--', |
| | | latitude: '--', |
| | | home_distance: '--', |
| | | quality: '--', |
| | | horizontal_speed: '--', |
| | | height: '--', |
| | | remain_flight_time: '--', |
| | | capacity_percent: '--', |
| | | }) |
| | | let quality = ref(['弱', '较弱', '中等', '较强', '强']) |
| | | let deviceInfo = ref({ |
| | | gateway: { |
| | | capacity_percent: str, |
| | | transmission_signal_quality: str, |
| | | }, |
| | | dock: {}, |
| | | 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, |
| | | }, |
| | | }); |
| | | let mode_code = ref('已断开连接'); |
| | | gateway: { |
| | | capacity_percent: str, |
| | | transmission_signal_quality: str, |
| | | }, |
| | | dock: {}, |
| | | 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, |
| | | }, |
| | | }) |
| | | let mode_code = ref('已断开连接') |
| | | |
| | | watch(() => store.state.home.osdVisible, (newValue) => { |
| | | osdVisible.value = newValue; |
| | | }); |
| | | watch( |
| | | () => store.state.home.osdVisible, |
| | | newValue => { |
| | | osdVisible.value = newValue |
| | | } |
| | | ) |
| | | |
| | | // 监听实时信息 |
| | | watch( |
| | | () => store.state.home.wsMessage, |
| | | (newValue) => { |
| | | if (newValue.mode_code === 14) return |
| | | if (Object.keys(newValue).length === 0) return |
| | | detailInfo.value.longitude = newValue?.longitude.toFixed(6) || '--'; |
| | | detailInfo.value.latitude = newValue?.latitude.toFixed(6) || '--'; |
| | | // console.log(window.$viewer) |
| | | getLnglatAltitude(Number(detailInfo.value.longitude), Number(detailInfo.value.latitude),window.$viewer).then((res) => { |
| | | const height = newValue?.height - res?.height; |
| | | //针对西安实时高度进行降低 |
| | | const wId = localStorage.getItem('bs_workspace_id'); |
| | | if (wId === 'f47ac10b-58cc-4372-a567-0e02b2c3d479') { |
| | | detailInfo.value.height = reduceHeight(height); |
| | | } else { |
| | | detailInfo.value.height = height.toFixed(1) || '--'; |
| | | } |
| | | () => store.state.home.wsMessage, |
| | | newValue => { |
| | | if (newValue.mode_code === 14) return |
| | | if (Object.keys(newValue).length === 0) return |
| | | detailInfo.value.longitude = newValue?.longitude.toFixed(6) || '--' |
| | | detailInfo.value.latitude = newValue?.latitude.toFixed(6) || '--' |
| | | // console.log(window.$viewer) |
| | | getLnglatAltitude(Number(detailInfo.value.longitude), Number(detailInfo.value.latitude), window.$viewer).then( |
| | | res => { |
| | | const height = newValue?.height - res?.height |
| | | //针对西安实时高度进行降低 |
| | | const wId = localStorage.getItem('bs_workspace_id') |
| | | if (wId === 'f47ac10b-58cc-4372-a567-0e02b2c3d479') { |
| | | detailInfo.value.height = reduceHeight(height) |
| | | } else { |
| | | detailInfo.value.height = height.toFixed(1) || '--' |
| | | } |
| | | |
| | | detailInfo.value.quality = quality.value[newValue?.position_state.quality - 1] || '--'; |
| | | detailInfo.value.horizontal_speed = newValue?.horizontal_speed.toFixed(1) || '--'; |
| | | detailInfo.value.remain_flight_time = (newValue?.battery.remain_flight_time / 60).toFixed(0) || '--'; |
| | | detailInfo.value.capacity_percent = (newValue?.battery.capacity_percent).toFixed(0) || '--'; |
| | | }); |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ); |
| | | detailInfo.value.quality = quality.value[newValue?.position_state.quality - 1] || '--' |
| | | detailInfo.value.horizontal_speed = newValue?.horizontal_speed.toFixed(1) || '--' |
| | | detailInfo.value.remain_flight_time = (newValue?.battery.remain_flight_time / 60).toFixed(0) || '--' |
| | | detailInfo.value.capacity_percent = (newValue?.battery.capacity_percent).toFixed(0) || '--' |
| | | } |
| | | ) |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ) |
| | | // 获取最新机场状态 |
| | | watch(store.state.home.deviceState, (newValue) => { |
| | | // console.log('newValue', newValue); |
| | | if (newValue.currentType === EDeviceTypeName.Dock && newValue?.dockInfo[newValue.currentSn]) { |
| | | // 机场状态 |
| | | mode_code.value = EDockModeText[newValue?.dockInfo[newValue.currentSn]?.basic_osd?.mode_code]; |
| | | // this.$emit('updateModeCode', mode_code.value); |
| | | // 舱内状态 |
| | | AircraftStatus.value = |
| | | EModeText[newValue.deviceInfo[ |
| | | deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? |
| | | osdVisible.sn |
| | | ]?.mode_code |
| | | ]; |
| | | // 舱内关机时显示的电量 |
| | | let child_sn = newValue?.dockInfo[newValue.currentSn].basic_osd.sub_device?.device_sn; |
| | | // 飞机在线时取飞机中的电量 |
| | | if(newValue.deviceInfo[child_sn]) { |
| | | drone_charge_state.value = { |
| | | capacity_percent: newValue.deviceInfo[child_sn].battery.capacity_percent, |
| | | state: newValue.deviceInfo[child_sn].battery.landing_power |
| | | } |
| | | } else{ |
| | | // 遥控器这里拿不到值data.drone_charge_state_new == undefined 会一直报错 |
| | | if (newValue.drone_charge_state_new) { |
| | | drone_charge_state.value = newValue.drone_charge_state_new; |
| | | } |
| | | } |
| | | if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') { |
| | | deviceInfo.value.dock = newValue.dockInfo[osdVisible.value.gateway_sn]; |
| | | deviceInfo.value.device = |
| | | newValue.deviceInfo[deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? |
| | | osdVisible.value.sn |
| | | ]; |
| | | // 设备关机即不显示信息 |
| | | // 兼容遥控器 关闭无人机 mode_code返回的是14 不是undefined |
| | | if ( |
| | | newValue.deviceInfo[ |
| | | deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? |
| | | osdVisible.value.sn |
| | | ]?.mode_code === undefined || newValue.deviceInfo[ |
| | | deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? |
| | | osdVisible.value .sn |
| | | ]?.mode_code == 14 |
| | | ) { |
| | | detailInfo.value = { |
| | | longitude: '--', |
| | | latitude: '--', |
| | | home_distance: '--', |
| | | quality: '--', |
| | | horizontal_speed: '--', |
| | | remain_flight_time: '--', |
| | | height: '--', |
| | | capacity_percent: '--', |
| | | }; |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ); |
| | | watch( |
| | | store.state.home.deviceState, |
| | | newValue => { |
| | | // console.log('newValue', newValue); |
| | | if (newValue.currentType === EDeviceTypeName.Dock && newValue?.dockInfo[newValue.currentSn]) { |
| | | // 机场状态 |
| | | mode_code.value = EDockModeText[newValue?.dockInfo[newValue.currentSn]?.basic_osd?.mode_code] |
| | | // this.$emit('updateModeCode', mode_code.value); |
| | | // 舱内状态 |
| | | AircraftStatus.value = |
| | | EModeText[ |
| | | newValue.deviceInfo[deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? osdVisible.sn]?.mode_code |
| | | ] |
| | | // 舱内关机时显示的电量 |
| | | let child_sn = newValue?.dockInfo[newValue.currentSn].basic_osd?.sub_device?.device_sn |
| | | // 飞机在线时取飞机中的电量 |
| | | if (newValue.deviceInfo[child_sn]) { |
| | | drone_charge_state.value = { |
| | | capacity_percent: newValue.deviceInfo[child_sn].battery.capacity_percent, |
| | | state: newValue.deviceInfo[child_sn].battery.landing_power, |
| | | } |
| | | } else { |
| | | // 遥控器这里拿不到值data.drone_charge_state_new == undefined 会一直报错 |
| | | if (newValue.drone_charge_state_new) { |
| | | drone_charge_state.value = newValue.drone_charge_state_new |
| | | } |
| | | } |
| | | if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') { |
| | | deviceInfo.value.dock = newValue.dockInfo[osdVisible.value.gateway_sn] |
| | | deviceInfo.value.device = |
| | | newValue.deviceInfo[deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? osdVisible.value.sn] |
| | | // 设备关机即不显示信息 |
| | | // 兼容遥控器 关闭无人机 mode_code返回的是14 不是undefined |
| | | if ( |
| | | newValue.deviceInfo[deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? osdVisible.value.sn] |
| | | ?.mode_code === undefined || |
| | | newValue.deviceInfo[deviceInfo.value.dock.basic_osd?.sub_device?.device_sn ?? osdVisible.value.sn] |
| | | ?.mode_code == 14 |
| | | ) { |
| | | detailInfo.value = { |
| | | longitude: '--', |
| | | latitude: '--', |
| | | home_distance: '--', |
| | | quality: '--', |
| | | horizontal_speed: '--', |
| | | remain_flight_time: '--', |
| | | height: '--', |
| | | capacity_percent: '--', |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ) |
| | | |
| | | const reduceHeight = (height) => { |
| | | if (!Number(height)) return '--'; |
| | | let theFinheight = 0; |
| | | if (height < 120) { |
| | | theFinheight = height; |
| | | } else if (height > 220) { |
| | | theFinheight = height - 110; |
| | | } else if (height > 210) { |
| | | theFinheight = height - 100; |
| | | } else if (height > 200) { |
| | | theFinheight = height - 90; |
| | | } else if (height > 190) { |
| | | theFinheight = height - 80; |
| | | } else if (height > 180) { |
| | | theFinheight = height - 70; |
| | | } else if (height > 170) { |
| | | theFinheight = height - 60; |
| | | } else if (height > 160) { |
| | | theFinheight = height - 50; |
| | | } else if (height > 150) { |
| | | theFinheight = height - 40; |
| | | } else if (height > 140) { |
| | | theFinheight = height - 30; |
| | | } else if (height > 130) { |
| | | theFinheight = height - 20; |
| | | } else if (height > 120) { |
| | | theFinheight = height - 10; |
| | | } |
| | | return theFinheight.toFixed(1); |
| | | }; |
| | | const reduceHeight = height => { |
| | | if (!Number(height)) return '--' |
| | | let theFinheight = 0 |
| | | if (height < 120) { |
| | | theFinheight = height |
| | | } else if (height > 220) { |
| | | theFinheight = height - 110 |
| | | } else if (height > 210) { |
| | | theFinheight = height - 100 |
| | | } else if (height > 200) { |
| | | theFinheight = height - 90 |
| | | } else if (height > 190) { |
| | | theFinheight = height - 80 |
| | | } else if (height > 180) { |
| | | theFinheight = height - 70 |
| | | } else if (height > 170) { |
| | | theFinheight = height - 60 |
| | | } else if (height > 160) { |
| | | theFinheight = height - 50 |
| | | } else if (height > 150) { |
| | | theFinheight = height - 40 |
| | | } else if (height > 140) { |
| | | theFinheight = height - 30 |
| | | } else if (height > 130) { |
| | | theFinheight = height - 20 |
| | | } else if (height > 120) { |
| | | theFinheight = height - 10 |
| | | } |
| | | return theFinheight.toFixed(1) |
| | | } |
| | | |
| | | // 详情 |
| | | const detailsFun = () => { |
| | | isShowDetails.value = true; |
| | | }; |
| | | isShowDetails.value = true |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .machine-status { |
| | | width: 390px; |
| | | height: 230px; |
| | | background: linear-gradient( |
| | | 270deg, |
| | | #1f3e7a 0%, |
| | | rgba(31, 62, 122, 0.35) 79%, |
| | | rgba(31, 62, 122, 0) 100% |
| | | ); |
| | | opacity: 0.85; |
| | | margin: 2px 0 13 0; |
| | | .machine-status { |
| | | width: 390px; |
| | | height: 230px; |
| | | background: linear-gradient(270deg, #1f3e7a 0%, rgba(31, 62, 122, 0.35) 79%, rgba(31, 62, 122, 0) 100%); |
| | | opacity: 0.85; |
| | | margin: 2px 0 13 0; |
| | | |
| | | padding: 8px 0px 20px 18px; |
| | | .info { |
| | | display: flex; |
| | | // justify-content: ce; |
| | | height: 88px; |
| | | display: flex; |
| | | align-items: center; |
| | | img { |
| | | width: 94px; |
| | | height: 88px; |
| | | margin-right: 22px; |
| | | } |
| | | .info-right { |
| | | .name { |
| | | width: 184px; |
| | | height: 31px; |
| | | font-family: YouSheBiaoTiHei, YouSheBiaoTiHei; |
| | | font-weight: 400; |
| | | font-size: 24px; |
| | | color: #0BE5F5; |
| | | line-height: 28px; |
| | | overflow: hidden; // 添加溢出隐藏 |
| | | text-overflow: ellipsis; // 显示省略号 |
| | | white-space: nowrap; // 不换行 |
| | | } |
| | | .wz { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-size: 14px; |
| | | color: #FFFFFF; |
| | | line-height: 16px; |
| | | .left { |
| | | width: 70px; |
| | | height: 21px; |
| | | font-weight: 400; |
| | | opacity: 0.6; |
| | | } |
| | | .right { |
| | | width: 100px; |
| | | height: 21px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | .close-wb { |
| | | display: flex; |
| | | margin-top: 10px; |
| | | text-align: center; |
| | | line-height: 16px; |
| | | .close { |
| | | width: 60px; |
| | | height: 20px; |
| | | line-height: 20px; |
| | | background: rgba(255,178,106,0.2); |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid #FFB26A; |
| | | color: #FFB26A; |
| | | margin-right: 10px; |
| | | } |
| | | .other { |
| | | border: 1px solid #8EFFAC; |
| | | color: #8EFFAC; |
| | | } |
| | | .wb { |
| | | width: 60px; |
| | | height: 20px; |
| | | background: rgba(255,106,106,0.2); |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid #FF6A6A; |
| | | color: #FF6A6A; |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | .status { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px 20px; |
| | | margin-top: 18px; |
| | | .card { |
| | | width: calc(33.33% - 14px); |
| | | } |
| | | img { |
| | | width: 16px; |
| | | height: 16px; |
| | | // margin-right: 0px; |
| | | // margin-top: 2px; |
| | | } |
| | | .text { |
| | | width: 56px; |
| | | height: 21px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #FFFFFF; |
| | | line-height: 16px; |
| | | } |
| | | .text-data { |
| | | // width: 40px; |
| | | margin-left: 20px; |
| | | height: 23px; |
| | | font-family: YouSheBiaoTiHei, YouSheBiaoTiHei; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #0BE5F5; |
| | | line-height: 21px; |
| | | } |
| | | } |
| | | } |
| | | padding: 8px 0px 20px 18px; |
| | | .info { |
| | | display: flex; |
| | | // justify-content: ce; |
| | | height: 88px; |
| | | display: flex; |
| | | align-items: center; |
| | | img { |
| | | width: 94px; |
| | | height: 88px; |
| | | margin-right: 22px; |
| | | } |
| | | .info-right { |
| | | .name { |
| | | width: 184px; |
| | | height: 31px; |
| | | font-family: YouSheBiaoTiHei, YouSheBiaoTiHei; |
| | | font-weight: 400; |
| | | font-size: 24px; |
| | | color: #0be5f5; |
| | | line-height: 28px; |
| | | overflow: hidden; // 添加溢出隐藏 |
| | | text-overflow: ellipsis; // 显示省略号 |
| | | white-space: nowrap; // 不换行 |
| | | } |
| | | .wz { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | .left { |
| | | width: 70px; |
| | | height: 21px; |
| | | font-weight: 400; |
| | | opacity: 0.6; |
| | | } |
| | | .right { |
| | | width: 100px; |
| | | height: 21px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | .close-wb { |
| | | display: flex; |
| | | margin-top: 10px; |
| | | text-align: center; |
| | | line-height: 16px; |
| | | .close { |
| | | width: 60px; |
| | | height: 20px; |
| | | line-height: 20px; |
| | | background: rgba(255, 178, 106, 0.2); |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid #ffb26a; |
| | | color: #ffb26a; |
| | | margin-right: 10px; |
| | | } |
| | | .other { |
| | | border: 1px solid #8effac; |
| | | color: #8effac; |
| | | } |
| | | .wb { |
| | | width: 60px; |
| | | height: 20px; |
| | | background: rgba(255, 106, 106, 0.2); |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid #ff6a6a; |
| | | color: #ff6a6a; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .status { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px 20px; |
| | | margin-top: 18px; |
| | | .card { |
| | | width: calc(33.33% - 14px); |
| | | } |
| | | img { |
| | | width: 16px; |
| | | height: 16px; |
| | | // margin-right: 0px; |
| | | // margin-top: 2px; |
| | | } |
| | | .text { |
| | | width: 56px; |
| | | height: 21px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | } |
| | | .text-data { |
| | | // width: 40px; |
| | | margin-left: 20px; |
| | | height: 23px; |
| | | font-family: YouSheBiaoTiHei, YouSheBiaoTiHei; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #0be5f5; |
| | | line-height: 21px; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | const total = ref(0) |
| | | |
| | | const distribution = row => { |
| | | ElMessage.warning('正在加急开发中...') |
| | | const orderNumber = row.event_num |
| | | const adminUrl = import.meta.env.VITE_APP_ADMIN_URL |
| | | const targetPath = `/tickets/ticket?orderNumber=${orderNumber}`; |
| | | window.open(`${adminUrl}?redirect=${encodeURIComponent(targetPath)}`, '_blank'); |
| | | } |
| | | const examine = row => { |
| | | ElMessage.warning('正在加急开发中...') |