无人机管理后台前端(已迁走)
罗广辉
2025-10-10 8bfd657326eb9d4bd9b63920cfe3bd362cea4445
src/views/monitor/log/flightLog.vue
@@ -4,44 +4,44 @@
    <div class="ztzf-search-mange">
      <el-form :model="params" inline>
        <div class="search-contain">
          <div>
            <el-form-item label="任务名称:">
              <el-input v-model="params.jobName" placeholder="请输入任务名称" clearable />
            </el-form-item>
            <el-form-item label="任务编号:">
              <el-input v-model="params.jobInfoNum" placeholder="请输入任务编号" clearable />
            </el-form-item>
            <el-form-item label="日期:">
              <el-date-picker
                v-model="rangTime"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                clearable
                @change="changeselect"
              />
            </el-form-item>
          </div>
          <div class="btns">
            <el-button type="primary" @click="getList" :icon="Search">搜索</el-button>
            <el-button @click="cancelSearch" :icon="Delete">清空</el-button>
          </div>
          <!--          <div>-->
          <el-form-item label="任务名称:">
            <el-input v-model="params.jobName" placeholder="请输入任务名称" clearable />
          </el-form-item>
          <el-form-item label="任务编号:">
            <el-input v-model="params.jobInfoNum" placeholder="请输入任务编号" clearable />
          </el-form-item>
          <el-form-item label="日期:">
            <el-date-picker
              v-model="rangTime"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              clearable
              @change="changeselect"
            />
          </el-form-item>
          <!--          </div>-->
          <!--          <div class="btns">-->
          <el-button type="primary" @click="getList" :icon="Search">搜索</el-button>
          <el-button @click="cancelSearch" :icon="Delete">清空</el-button>
          <!--          </div>-->
        </div>
      </el-form>
    </div>
    <div class="mange-table">
<!--      <el-tabs v-model="tabType" class="demo-tabs" @tab-click="handleTabClick">-->
<!--        <el-tab-pane label="全部" name="全部"></el-tab-pane>-->
<!--        <el-tab-pane label="我的收藏" name="收藏"></el-tab-pane>-->
<!--        -->
<!--      </el-tabs>-->
      <!--      <el-tabs v-model="tabType" class="demo-tabs" @tab-click="handleTabClick">-->
      <!--        <el-tab-pane label="全部" name="全部"></el-tab-pane>-->
      <!--        <el-tab-pane label="我的收藏" name="收藏"></el-tab-pane>-->
      <!--        -->
      <!--      </el-tabs>-->
      <el-table border :data="tableList" class="custom-header">
        <el-table-column label="序号" type="index" width="60"></el-table-column>
        <el-table-column prop="job_name" label="任务名称" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="job_info_num" label="任务编号" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="title" label="飞行类型" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="device_name" label="无人机" align="center"></el-table-column>
<!--        <el-table-column prop="title" label="飞行类型" align="center" show-overflow-tooltip></el-table-column>-->
        <el-table-column prop="nickname" label="机巢名称" align="center"></el-table-column>
        <el-table-column prop="start_time" label="开始时间" align="center">
          <template #default="scope">
            {{ timeFormatConvert(scope.row.start_time) }}
@@ -52,25 +52,27 @@
            {{ timeFormatConvert(scope.row.end_time) }}
          </template>
        </el-table-column>
<!--        <el-table-column prop="end_time" label="标签" align="center">-->
<!--          <template #default="scope">-->
<!--            <el-select v-model="scope.row.label_id" @change="handleUpdateLabel(scope.row)" clearable>-->
<!--              <el-option-->
<!--                v-for="item in tagList"-->
<!--                :key="item.id"-->
<!--                :label="item.label_name"-->
<!--                :value="item.id"-->
<!--              ></el-option>-->
<!--            </el-select>-->
<!--          </template>-->
<!--        </el-table-column>-->
        <el-table-column prop="create_name" label="创建人" align="center"></el-table-column>
        <!--        <el-table-column prop="end_time" label="标签" align="center">-->
        <!--          <template #default="scope">-->
        <!--            <el-select v-model="scope.row.label_id" @change="handleUpdateLabel(scope.row)" clearable>-->
        <!--              <el-option-->
        <!--                v-for="item in tagList"-->
        <!--                :key="item.id"-->
        <!--                :label="item.label_name"-->
        <!--                :value="item.id"-->
        <!--              ></el-option>-->
        <!--            </el-select>-->
        <!--          </template>-->
        <!--        </el-table-column>-->
        <el-table-column label="操作" width="300" align="center">
          <template #default="scope">
            <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button>
            <el-button icon="el-icon-view" type="text" @click="handleLineTrajectory(scope.row)">轨迹</el-button>
            <el-button icon="el-icon-delete" type="text" @click="handleDelete(scope.row)">删除</el-button>
<!--            <el-button type="text" @click="handleStar(scope.row)">-->
<!--              <el-icon><Star /></el-icon>-->
<!--              {{ scope.row.is_favorite ? '取消收藏':'收藏' }}</el-button>-->
            <!--            <el-button type="text" @click="handleStar(scope.row)">-->
            <!--              <el-icon><Star /></el-icon>-->
            <!--              {{ scope.row.is_favorite ? '取消收藏':'收藏' }}</el-button>-->
            <el-button type="text" @click="handleExport(scope.row)"><el-icon><Download /></el-icon>导出</el-button>
          </template>
        </el-table-column>
@@ -84,33 +86,50 @@
                     @size-change="handleSizeChange" @current-change="handleCurrentChange" />
    </div>
  </div>
  <el-dialog class="ztzf-dialog" append-to-body v-model="isShowView" title="查看"
             :width="pxToRem(1000)" :close-on-click-modal="false" :destroy-on-close="true">
    <!-- <div class="content"> -->
  <el-dialog class="ztzf-dialog-mange" append-to-body v-model="isShowView" title="查看" :width="pxToRem(1200)" :close-on-click-modal="false" :destroy-on-close="true">
    <el-table border :data="tableDataDetails" height="466">
      <el-table-column label="序号" type="index" width="60"></el-table-column>
      <el-table-column prop="flight_type" label="飞行类型" align="center" show-overflow-tooltip></el-table-column>
      <el-table-column prop="latitude" label="经度" align="center"></el-table-column>
      <el-table-column prop="longitude" label="纬度" align="center"></el-table-column>
      <el-table-column prop="height" label="高度" align="center"></el-table-column>
      <el-table-column prop="elevation" label="海拔高度" align="center"></el-table-column>
      <el-table-column prop="create_time" label="飞行时间" align="center" show-overflow-tooltip></el-table-column>
      <el-table-column prop="longitude" label="经度" align="center"></el-table-column>
      <el-table-column prop="latitude" label="纬度" align="center"></el-table-column>
      <el-table-column prop="height" label="绝对高度" align="center"></el-table-column>
      <el-table-column prop="elevation" label="实时真高" align="center"></el-table-column>
    </el-table>
    <div class="pagination" style="display: flex;justify-content: end;margin-top: 10px;">
      <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background
                     :page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="detailParams.current"
                     v-model:page-size="detailParams.size" layout="total, sizes, prev, pager, next, jumper" :total="detailTotal"
                     @size-change="handleSizeChangeDetails" @current-change="handleCurrentChangeDetails" />
      <!-- </div> -->
    </div>
    <template #footer>
      <div class="pagination dialog-footer" style="display: flex;justify-content: end;margin-top: 10px;">
        <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background
                       :page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="detailParams.current"
                       v-model:page-size="detailParams.size" layout="total, sizes, prev, pager, next, jumper" :total="detailTotal"
                       @size-change="handleSizeChangeDetails" @current-change="handleCurrentChangeDetails" />
      </div>
    </template>
  </el-dialog>
  <el-dialog class="ztzf-dialog-mange" append-to-body v-model="isShowFlyMapView" title="查看" :width="pxToRem(1000)" :close-on-click-modal="false" :destroy-on-close="true">
    <div id="flyMap" class="ztzf-cesium"></div>
  </el-dialog>
</template>
<script setup>
import { getHistoryTrack, cancelStar, addStar, updateDroneFlight, droneFlightLogInfoPage } from '@/api/logs';
import { getHistoryTrack, cancelStar, addStar, updateDroneFlight, deleteDroneFlight, droneFlightLogInfoPage } from '@/api/logs';
// import { flightLogPage } from '@/api/airspace/airspace';
import { downloadXls } from '@/utils/util';
import { exportBlob } from '@/api/common'
import * as Cesium from 'cesium';
import { PublicCesium } from '@/utils/cesium/publicCesium';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { Delete, Search } from '@element-plus/icons-vue';
import { ArrowLineMaterialProperty } from '@/utils/cesium/Material'
import { flyVisual } from '@/utils/cesium/mapUtil'
import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png'
import endPointImg from '@/assets/images/EndPointicon.png'
import { nextTick } from 'vue';
let publicCesiumInstance = null;
let viewer = null;
const viewInstance = shallowRef(null);
const homeViewer = shallowRef(null);
let previewDataSource = null
const total = ref(0)
let rangTime = ref([])
@@ -128,6 +147,8 @@
let isShowView = ref(false)
let isShowFlyMapView = ref(false)
let tabType = ref('全部')
function timeFormatConvert(time) {
@@ -142,8 +163,8 @@
    startTime: '',
    endTime: '',
    isFavorite: tabType.value === '收藏' ? true : false,
    page: '1',
    page_size: '10',
    page: 1,
    page_size: 10,
    jobName: '',
    jobInfoNum: '',
  }
@@ -181,12 +202,119 @@
function handleDetail(row) {
  isShowView.value = true
  detailParams.value.current = 1
  detailParams.value.size = 10
  detailParams.value.flightId = row.id
  detailTotal.value = 0
  droneFlightLogInfoPage(detailParams.value).then(res => {
    tableDataDetails.value = res.data.data.records
    detailTotal.value = res.data.data.total
  })
}
// 地图
const initMap = () => {
  if (!document.getElementById('flyMap')) {
    return;
  }
  publicCesiumInstance = new PublicCesium({
    dom: 'flyMap',
    flatMode: false,
    terrain: true,
    layerMode: 4,
    contour: false,
  });
  homeViewer.value = publicCesiumInstance.getViewer();
  viewer = publicCesiumInstance.getViewer();
  viewInstance.value = publicCesiumInstance;
  viewer.scene.globe.depthTestAgainstTerrain = true;
  viewInstance.value.switchContour(true);
};
// 预览轨迹
let arrowLineMaterialProperty = new ArrowLineMaterialProperty({
  color: new Cesium.Color(128 / 255, 215 / 255, 255 / 255, 1),
  directionColor: new Cesium.Color(1, 1, 1, 1),
  outlineColor: new Cesium.Color(1, 1, 1, 1),
  outlineWidth: 0,
  speed: 5,
})
async function handleLineTrajectory(row) {
  isShowFlyMapView.value = true;
  // 确保地图容器已渲染
  await nextTick();
  // 确保地图初始化完成
  // if (!viewer) {
  //   initMap();
  // }
  initMap();
  detailParams.value.size = 9999
  detailParams.value.current = 1
  detailParams.value.flightId = row.id;
  const res = await droneFlightLogInfoPage(detailParams.value);
  tableDataDetails.value = res.data.data.records;
  // 清除现有数据源(如果有)
  if (previewDataSource) {
    viewer.dataSources.remove(previewDataSource);
  }
  // 创建新数据源
  previewDataSource = new Cesium.CustomDataSource('previewDataSource');
  await viewer.dataSources.add(previewDataSource);
  // 确保数据有效
  const validPositions = tableDataDetails.value
    .filter(i => i.longitude && i.latitude && i.height)
    .map(i => Cesium.Cartesian3.fromDegrees(
      Number(i.longitude),
      Number(i.latitude),
      Number(i.height)
    ));
  if (validPositions.length > 0) {
    previewDataSource.entities.add({
      polyline: {
        width: 4,
        positions: validPositions,
        material: arrowLineMaterialProperty,
        clampToGround: false,
      },
    });
    // 起点
    // previewDataSource.entities.add({
    //   position: validPositions[0],
    //   billboard: {
    //     image: rwqfdImg,
    //     width: 50,
    //     height: 50,
    //   },
    // })
    // 终点
    // previewDataSource.entities.add({
    //   position: validPositions[validPositions.length - 1],
    //   billboard: {
    //     image: new Cesium.ConstantProperty(endPointImg),
    //     width: 30,
    //     height: 30,
    //     verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐
    //   },
    // })
    flyVisual({
      positionsData: tableDataDetails.value.map(i => [
        Number(i.longitude),
        Number(i.latitude),
        Number(i.height)
      ]),
      viewer,
      multiple: 4.6,
      pitch: -60
    });
  } else {
    console.warn('No valid positions data');
  }
}
// 分页
function handleSizeChangeDetails(val) {
@@ -251,7 +379,7 @@
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    updateDroneFlight({ is_deleted: 1, id: row.id }).then(res => {
    deleteDroneFlight({ id: row.id }).then(res => {
      ElMessage.success('删除成功')
      getList()
    })
@@ -390,4 +518,8 @@
    }
  }
}
#flyMap {
  height: 500px;
  width: 100%;
}
</style>