husq
2023-10-30 faca63a304d7677d6576c8604894dc40ed0aebc9
历史航线功能添加
5 files modified
1 files added
203 ■■■■■ changed files
src/api/wayline.ts 24 ●●●● patch | view | raw | blame | history
src/components/common/sidebar.vue 3 ●●●● patch | view | raw | blame | history
src/hooks/use-cesium-tsa.ts 4 ●●●● patch | view | raw | blame | history
src/pages/page-web/projects/routeLine.vue 166 ●●●●● patch | view | raw | blame | history
src/router/index.ts 5 ●●●●● patch | view | raw | blame | history
src/types/enums.ts 1 ●●●● patch | view | raw | blame | history
src/api/wayline.ts
@@ -76,17 +76,16 @@
  rth_altitude: number // 相对机场返航高度 20 - 500
  out_of_control_action: OutOfControlAction // 失控动作
  //重复频率类型
  // 重复频率类型
  rep_fre_type?:number
  //重复频率值
  // 重复频率值
  rep_fre_val?:number
  // 重复规则值
  rep_rule_val?:[]
  rep_rule_type?:number
  min_battery_capacity?:number
  //执行开始时间
  // 执行开始时间
  execute_start_time_arr:number[][]
}
// 新增计划
@@ -96,13 +95,12 @@
  return result.data
}
//新增计划,重复定时和连续执行走这个逻辑
// 新增计划,重复定时和连续执行走这个逻辑
export const createPlanCondition = async function (workspaceId: string, plan: CreatePlan): Promise<IWorkspaceResponse<any>> {
  const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/flight-tasks-condition`
  const result = await request.post(url, plan)
  return result.data
}
export interface Task {
  job_id: string,
@@ -193,3 +191,17 @@
  const result = await request.post(url)
  return result.data
}
// 历史轨迹记录
export const getHistoryTrack = async function (workspaceId: string, page: number, page_size :number): Promise<IWorkspaceResponse<any>> {
  const url = `/log/droneFlightLog/page?page=${page}&page_sie=${page_size}&workspaceId=${workspaceId}`
  const result = await request.get(url)
  return result.data
}
// 历史轨迹详情
export const getHistoryDetail = async function (id: string): Promise<IWorkspaceResponse<any>> {
  const url = `/log/droneFlightLog/infoListByFid?flightId=${id}`
  const result = await request.get(url)
  return result.data
}
src/components/common/sidebar.vue
@@ -60,7 +60,8 @@
      { key: 3, label: '媒体库', path: '/' + ERouterName.MEDIA, icon: 'PictureOutlined' },
      { key: 4, label: '航线库', path: '/' + ERouterName.WAYLINE, icon: 'NodeIndexOutlined' },
      { key: 5, label: '计划库', path: '/' + ERouterName.TASK, icon: 'CalendarOutlined' },
      { key: 6, label: '设备', path: '/' + ERouterName.IMPLEMENT, icon: 'ClusterOutlined' }
      { key: 6, label: '设备', path: '/' + ERouterName.IMPLEMENT, icon: 'ClusterOutlined' },
      { key: 7, label: '历史航线', path: '/' + ERouterName.ROUTE_HISTORY, icon: 'NodeIndexOutlined' }
    ]
    const store = useMyStore()
    function selectedRoute (item: IOptions) {
src/hooks/use-cesium-tsa.ts
@@ -191,9 +191,9 @@
    }
  }
  // 飞行 flyto
  const flyTo = (pointOption: pointOption, time: number = 4) => {
  const flyTo = (pointOption: pointOption, time: number = 4, height:number = 3000) => {
    if (!pointOption.longitude && !pointOption.latitude) return
    const destination = Cesium.Cartesian3.fromDegrees(pointOption.longitude, pointOption.latitude, 3000)
    const destination = Cesium.Cartesian3.fromDegrees(pointOption.longitude, pointOption.latitude, height)
    const duration = time
    viewer?.camera.flyTo({
      destination,
src/pages/page-web/projects/routeLine.vue
New file
@@ -0,0 +1,166 @@
<template>
    <div class="project-wayline-wrapper height-100">
      <a-spin :spinning="loading" :delay="300" tip="加载中" size="large">
      <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;">
        <a-row>
          <a-col :span="1"></a-col>
          <a-col :span="15">历史航线</a-col>
        </a-row>
      </div>
      <div :style="{ height : height + 'px'}" class="scrollbar">
        <div id="data" class="height-100 uranus-scrollbar" v-if="routeLine.length !== 0" @scroll="onScroll">
          <div v-for="wayline in routeLine" :key="wayline.id">
            <div class="wayline-panel" style="padding-top: 5px;" @click="selectRoute(wayline)">
              <div class="title">
                <a-tooltip :title="wayline.title">
                  <div class="pr10">{{ wayline.title }}</div>
                </a-tooltip>
                <div class="ml10"></div>
                <a-tooltip :title="wayline.device_name">
                  <div class="ml5 pr10">{{ wayline.device_name }}</div>
                </a-tooltip>
                <div class="fz20"></div>
              </div>
              <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
              </div>
              <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);">
                <span class="mr10">开始时间: {{ convertTimestampToDate(wayline.start_time) }}</span>
              </div>
              <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);">
                <span class="mr10">结束时间: {{ convertTimestampToDate(wayline.end_time) }}</span>
              </div>
            </div>
          </div>
        </div>
        <div v-else>
          <a-empty :image-style="{ height: '60px', marginTop: '60px' }" />
        </div>
      </div>
      </a-spin>
    </div>
  </template>
<script lang="ts" setup>
import { reactive } from '@vue/reactivity'
import { message } from 'ant-design-vue'
import { onMounted, ref } from 'vue'
import { getHistoryTrack, getHistoryDetail } from '/@/api/wayline'
import { ELocalStorageKey } from '/@/types'
import { useMyStore } from '/@/store'
import { IPage } from '/@/api/http/type'
import * as Cesium from 'cesium'
import { convertTimestampToDate } from '/@/utils/time'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
const loading = ref(false)
const { appContext } = getCurrentInstance()
const store = useMyStore()
const pagination :IPage = {
  page: 1,
  total: -1,
  page_size: 10
}
const waylinesData = reactive({
  data: []
})
const routeLine = ref([])
const workspaceId = computed(() => store.state.common.projectId || localStorage.getItem(ELocalStorageKey.WorkspaceId))
const canRefresh = ref(true)
const height = ref()
const { removeById, addPolyline, getEntityById, flyTo } = cesiumOperation()
onMounted(() => {
  const parent = document.getElementsByClassName('scrollbar').item(0)?.parentNode as HTMLDivElement
  height.value = document.body.clientHeight - parent.firstElementChild!.clientHeight
  getHistoryWay()
  //   const key = setInterval(() => {
  //     const data = document.getElementById('data')?.lastElementChild as HTMLDivElement
  //     if (pagination.total === 0 || Math.ceil(pagination.total / pagination.page_size) <= pagination.page || height.value <= data?.clientHeight + data?.offsetTop) {
  //       clearInterval(key)
  //       return
  //     }
  //     pagination.page++
  //     getWaylines()
  //   }, 1000)
  console.log(workspaceId.value)
})
async function getHistoryWay () {
  const res = await getHistoryTrack(workspaceId.value, pagination.page, pagination.page_size)
  if (res.code !== 0) return
  routeLine.value = [...routeLine.value, ...res.data.list]
  pagination.total = res.data.pagination.total
  pagination.page = res.data.pagination.page
}
async function selectRoute (wayline) {
  // 判断是否有历史航线的id实体
  const entity = getEntityById('drone_route_history')
  if (entity) {
    removeById('drone_route_history')
  }
  // 航线经纬度存储数组
  let routeLine = []
  const res = await getHistoryDetail(wayline.id)
  if (res.code !== 0) return
  res.data.forEach(v => {
    routeLine.push(v.longitude)
    routeLine.push(v.latitude)
  })
  const pointOption = {
    longitude: routeLine[0],
    latitude: routeLine[1]
  }
  routeLine = Cesium.Cartesian3.fromDegreesArray(routeLine)
  // 无人机历史路线轨迹
  const routeTrajectory = {
    longitude: 115.85666327144976,
    latitude: 28.62452712442823,
    id: 'drone_route_history',
    polyline: {
      width: 5,
      positions: routeLine,
      material: Cesium.Color.BLUE
    },
  }
  addPolyline(routeTrajectory)
  // 飞向第一个坐标点
  flyTo(pointOption, 4, 1000)
}
function onScroll (e: any) {
  const element = e.srcElement
  if (element.scrollTop + element.clientHeight >= element.scrollHeight - 5 && Math.ceil(pagination.total / pagination.page_size) > pagination.page && canRefresh.value) {
    pagination.page++
    getHistoryWay()
  }
}
</script>
  <style lang="scss" scoped>
  .wayline-panel {
    background: #3c3c3c;
    margin-left: auto;
    margin-right: auto;
    margin-top: 10px;
    height: 90px;
    width: 95%;
    font-size: 13px;
    border-radius: 2px;
    cursor: pointer;
    .title {
      display: flex;
      flex-direction: row;
      align-items: center;
      height: 30px;
      font-weight: bold;
      margin: 0px 10px 0 10px;
    }
  }
  .uranus-scrollbar {
    overflow: auto;
    scrollbar-width: thin;
    scrollbar-color: #c5c8cc transparent;
  }
  </style>
src/router/index.ts
@@ -123,6 +123,11 @@
                name: ERouterName.IMPLEMENT,
                component: () => import('/@/pages/page-web/projects/implement.vue')
              },
              {
                path: '/' + ERouterName.ROUTE_HISTORY,
                name: ERouterName.ROUTE_HISTORY,
                component: () => import('/@/pages/page-web/projects/routeLine.vue')
              },
            ],
            meta: {
              header: false
src/types/enums.ts
@@ -25,6 +25,7 @@
    PILOT_LIVESHARE = 'pilot-liveshare',
    PILOT_BIND = 'pilot-bind',
    IMPLEMENT = 'implement',
    ROUTE_HISTORY = 'route-history',
}
export enum EStorageKey {