无人机管理后台前端(已迁走)
张含笑
2025-06-30 5fb3c9bcf219e60d4813c68ff4e82b7b0b811988
src/views/dataCenter/dataCenter.vue
@@ -1,258 +1,251 @@
<template>
  <div class="dataCenter-table">
    <searchData
      @search="searchClick"
      @downFun="downloadFile"
      @allDownFun="aLLDownloadFile"
    ></searchData>
    <!-- 表格部分 -->
    <div class="dataTable">
      <el-table
        v-loading="loadings"
        element-loading-text="加载中"
        stripe
        :data="tableData"
        class="custom-header"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55" />
        <el-table-column label="序号" type="index" width="60">
          <template #default="{ $index }">
            {{
              ($index + 1 + (jobListParams.current - 1) * jobListParams.size)
                .toString()
                .padStart(2, '0')
            }}
          </template>
        </el-table-column>
        <el-table-column prop="regionName" label="所属区域" v-if="!isDistrictLevel">
          <template #default="scope">
            <span>{{ processAddress(scope.row.regionName) }}</span>
          </template>
        </el-table-column>
        <el-table-column property="nestName" label="所属机巢" />
        <el-table-column property="jobName" label="任务名称" show-overflow-tooltip />
        <el-table-column prop="nickName" label="文件名称" show-overflow-tooltip />
        <el-table-column property="link" label="缩图" width="120">
          <template #default="scope">
            <img
              class="quanjing"
              @click="clickpanorama(scope.row)"
              v-if="scope.row?.resultType === 5"
              :src="scope.row?.smallUrl"
              alt=""
            />
            <img
              v-else-if="scope.row?.resultType === 1"
              :src="convertVideoUrlToThumbnail(scope.row?.link)"
              alt=""
              class="imageBox"
              @click="enterFullScreen(scope.row)"
            />
            <!-- 正射 -->
            <img
              v-else-if="scope.row?.resultType === 4"
              :src="getzsSmallImg(scope.row?.link)"
              alt=""
              class="imageBox"
            />
            <el-image
              v-else
              :src="scope.row?.smallUrl"
              :preview-src-list="[scope.row?.showUrl]"
              fit="cover"
              preview-teleported
            />
          </template>
        </el-table-column>
        <el-table-column prop="jobTime" label="任务时间" />
        <el-table-column property="photoType" label="文件类别">
          <template #default="scope">
            <span>{{ photoTypeMap[scope.row.photoType] }}</span>
          </template>
        </el-table-column>
        <el-table-column property="resultType" label="文件格式">
          <template #default="{ row }">
            <span>{{ resultTypeMap[row?.resultType] }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" align="center">
          <template #default="scope">
            <span class="look" @click="lookDetail(scope.row)">查看</span>
            <span class="delete" @click="deleteDetail(scope.row)" v-if="scope.row.resultType !== 2"
              >删除</span
            >
  <div
    class="manage-m-all-10 manage-m-t-0 manage-p-all-20 manage-h-0 manage-flex-1 manage-flex manage-f-d-c manage-b-r-5 manage-b-c-w"
  >
    <div class="dataCenter-table">
      <searchData
        @search="searchClick"
        @downFun="downloadFile"
        @allDownFun="aLLDownloadFile"
      ></searchData>
      <!-- 表格部分 -->
      <div class="dataTable">
        <el-table
          v-loading="loadings"
          element-loading-text="加载中"
          stripe
          :data="tableData"
          class="custom-header"
          @selection-change="handleSelectionChange"
        >
          <el-table-column type="selection" width="55" />
          <el-table-column label="序号" type="index" width="60">
            <template #default="{ $index }">
              {{
                ($index + 1 + (jobListParams.current - 1) * jobListParams.size)
                  .toString()
                  .padStart(2, '0')
              }}
            </template>
          </el-table-column>
          <el-table-column prop="regionName" label="所属区域" v-if="!isDistrictLevel">
            <template #default="scope">
              <span>{{ processAddress(scope.row.regionName) }}</span>
            </template>
          </el-table-column>
          <el-table-column property="nestName" label="所属机巢" />
          <el-table-column property="jobName" label="任务名称" show-overflow-tooltip />
          <el-table-column prop="nickName" label="文件名称" show-overflow-tooltip />
          <el-table-column property="link" label="缩图" width="120">
            <template #default="scope">
              <img
                class="quanjing"
                @click="clickpanorama(scope.row)"
                v-if="scope.row?.resultType === 5"
                :src="scope.row?.smallUrl"
                alt=""
              />
              <img
                v-else-if="scope.row?.resultType === 1"
                :src="convertVideoUrlToThumbnail(scope.row?.link)"
                alt=""
                class="imageBox"
                @click="enterFullScreen(scope.row)"
              />
              <!-- 正射 -->
              <img
                v-else-if="scope.row?.resultType === 4"
                :src="getzsSmallImg(scope.row?.link)"
                alt=""
                class="imageBox"
              />
              <el-image
                v-else
                :src="scope.row?.smallUrl"
                :preview-src-list="[scope.row?.showUrl]"
                fit="cover"
                preview-teleported
              />
            </template>
          </el-table-column>
          <el-table-column prop="jobTime" label="任务时间" />
          <el-table-column property="photoType" label="文件类别">
            <template #default="scope">
              <span>{{ photoTypeMap[scope.row.photoType] }}</span>
            </template>
          </el-table-column>
          <el-table-column property="resultType" label="文件格式">
            <template #default="{ row }">
              <span>{{ resultTypeMap[row?.resultType] }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="150" align="center">
            <template #default="scope">
              <span class="look" @click="lookDetail(scope.row)">查看</span>
              <span
                class="delete"
                @click="deleteDetail(scope.row)"
                v-if="scope.row.resultType !== 2"
                >删除</span
              >
            <span
              class="location"
              @click="positionDetail(scope.row)"
              v-if="shouldShowLocation(scope.row)"
              >定位</span
            >
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!-- 分页 -->
    <div class="pagination">
      <el-pagination
        v-model:current-page="jobListParams.current"
        v-model:page-size="jobListParams.size"
        :page-sizes="[10, 20, 30, 40]"
        background
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
    <!-- 查看弹框 -->
    <el-dialog v-model="dialogVisible" width="60%" append-to-body @close="dialogClose">
      <template #header="{ titleId, titleClass }">
        <div class="my-header">
          <h4 :id="titleId" :class="titleClass">{{ detailTitle }}</h4>
              <span
                class="location"
                @click="positionDetail(scope.row)"
                v-if="shouldShowLocation(scope.row)"
                >定位</span
              >
            </template>
          </el-table-column>
        </el-table>
      </div>
      <!-- 分页 -->
      <div class="pagination">
        <el-pagination
          v-model:current-page="jobListParams.current"
          v-model:page-size="jobListParams.size"
          :page-sizes="[10, 20, 30, 40]"
          background
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
      <!-- 查看弹框 -->
      <el-dialog v-model="dialogVisible" width="60%" append-to-body @close="dialogClose">
        <template #header="{ titleId, titleClass }">
          <div class="my-header">
            <h4 :id="titleId" :class="titleClass">{{ detailTitle }}</h4>
          </div>
        </template>
        <div class="detailContainer">
          <div class="leftImg">
            <!-- 视频 -->
            <video
              v-if="dialogDetailList?.resultType === 1"
              style="width: 100%"
              class="imageBox"
              ref="videoRefs"
              controls
              autoplay
              :src="dialogDetailList.link"
            ></video>
            <!-- 地图 -->
            <div
              v-else-if="dialogDetailList?.resultType === 4"
              id="detaildataCenterMap"
              class="ztzf-cesium"
            ></div>
            <img v-else :src="getSmallImg(dialogDetailList?.link)" alt="" />
          </div>
          <div class="rightDetail">
            <div class="title">
              <div class="inputEdit">
                文件名称:<span class="fileTitle" v-if="!dialogDetailList?.checkedinput">{{
                  dialogDetailList?.nickName ? dialogDetailList?.nickName : '--'
                }}</span>
                <el-input
                  v-else
                  v-model="dialogDetailList.nickName"
                  @blur="saveTitle(dialogDetailList)"
                  @keyup.enter="saveTitle(dialogDetailList)"
                  class="title-input"
                  clearable
                />
                 <span class="editname" @click="editTitle(dialogDetailList)"
                  ><el-icon>
                    <Edit /> </el-icon
                ></span>
              </div>
            </div>
            <div>任务名称:{{ dialogDetailList?.jobName ? dialogDetailList?.jobName : '--' }}</div>
            <div>
              所属区域:{{ dialogDetailList?.regionName ? dialogDetailList?.regionName : '--' }}
            </div>
            <div>
              拍摄机巢:{{ dialogDetailList?.nestName ? dialogDetailList?.nestName : '--' }}
            </div>
            <div>
              照片位置:{{ _.round(dialogDetailList?.longitude, 3) }},{{
                _.round(dialogDetailList?.latitude, 3)
              }}
            </div>
            <div>任务时间:{{ dialogDetailList?.jobTime ? dialogDetailList?.jobTime : '--' }}</div>
            <div>
              拍摄时间:{{ dialogDetailList?.createTime ? dialogDetailList?.createTime : '--' }}
            </div>
            <div>
              文件类型:{{
                photoTypeMap[dialogDetailList?.photoType]
                  ? photoTypeMap[dialogDetailList?.photoType]
                  : '--'
              }}
            </div>
            <div>
              文件格式:{{
                resultTypeMap[dialogDetailList?.resultType]
                  ? resultTypeMap[dialogDetailList?.resultType]
                  : '--'
              }}
            </div>
            <div>
              照片文件大小:{{
                bytesToMB(dialogDetailList?.attachSize)
                  ? bytesToMB(dialogDetailList?.attachSize)
                  : '--'
              }}
            </div>
            <div>
              <el-button
                type="success"
                plain
                icon="el-icon-download"
                @click="detailDownLoad(dialogDetailList)"
                >下载</el-button
              >
            </div>
          </div>
        </div>
      </template>
      <div class="detailContainer">
        <div class="leftImg">
          <!-- <img
            v-if="dialogDetailList?.resultType === 1"
            :src="convertVideoUrlToThumbnail(dialogDetailList?.link)"
            alt=""
            class="imageBox"
          /> -->
          <!-- 视频 -->
      </el-dialog>
      <!-- 全景预览 -->
      <PanoramaPopup
        v-model:panoramaParamsShow="panoramaParamsShow"
        v-model:panoramaParamsUrl="panoramaParamsUrl"
      >
      </PanoramaPopup>
      <!-- 视频预览 -->
      <el-dialog
        :title="currentVideoTitle"
        modal-class="videoDialog"
        append-to-body
        width="54%"
        v-model="VideoShow"
        :close-on-click-modal="false"
        :destroy-on-close="true"
        @close="currentVideoIndex = -1"
      >
        <div class="video-container">
          <video
            v-if="dialogDetailList?.resultType === 1"
            style="width: 100%"
            class="imageBox"
            class="videoBox"
            ref="videoRefs"
            controls
            autoplay
            :src="dialogDetailList.link"
            :src="currentVideoUrl"
          ></video>
          <!-- 全景 -->
           <!-- <img
              class="quanjing"
              @click="clickpanorama(dialogDetailList)"
              v-else-if="dialogDetailList?.resultType === 5"
              :src="dialogDetailList?.resultType?.smallUrl"
              alt=""
            /> -->
          <!-- 地图 -->
          <div
            v-else-if="dialogDetailList?.resultType === 4"
            id="detaildataCenterMap"
            class="ztzf-cesium"
          ></div>
          <img v-else :src="getSmallImg(dialogDetailList?.link)" alt="" />
        </div>
        <div class="rightDetail">
          <div class="title">
            <div class="inputEdit">
              文件名称:<span class="fileTitle" v-if="!dialogDetailList?.checkedinput">{{
                dialogDetailList?.nickName ? dialogDetailList?.nickName : '--'
              }}</span>
              <el-input
                v-else
                v-model="dialogDetailList.nickName"
                @keyup.enter="saveTitle()"
                class="title-input"
                clearable
              />
            </div>
            <div class="editname">
              <span v-if="!dialogDetailList?.checkedinput" @click="editTitle(dialogDetailList)"
                ><el-icon><Edit /></el-icon
              ></span>
              <div v-else class="suffixBoxEdit">
                <div class="editText" @click="submitEditSuffix(dialogDetailList)">✔</div>
                <div class="editText" @click="cancelEditSuffix(dialogDetailList)">✖</div>
              </div>
            </div>
          </div>
          <div>任务名称:{{ dialogDetailList?.jobName ? dialogDetailList?.jobName : '--' }}</div>
          <div>
            所属区域:{{ dialogDetailList?.regionName ? dialogDetailList?.regionName : '--' }}
          </div>
          <div>拍摄机巢:{{ dialogDetailList?.nestName ? dialogDetailList?.nestName : '--' }}</div>
          <div>
            照片位置:{{ _.round(dialogDetailList?.longitude, 3) }},{{
              _.round(dialogDetailList?.latitude, 3)
            }}
          </div>
          <div>任务时间:{{ dialogDetailList?.jobTime ? dialogDetailList?.jobTime : '--' }}</div>
          <div>
            拍摄时间:{{ dialogDetailList?.createTime ? dialogDetailList?.createTime : '--' }}
          </div>
          <div>
            文件类型:{{
              photoTypeMap[dialogDetailList?.photoType]
                ? photoTypeMap[dialogDetailList?.photoType]
                : '--'
            }}
          </div>
          <div>
            文件格式:{{
              resultTypeMap[dialogDetailList?.resultType]
                ? resultTypeMap[dialogDetailList?.resultType]
                : '--'
            }}
          </div>
          <div>
            照片文件大小:{{
              bytesToMB(dialogDetailList?.attachSize)
                ? bytesToMB(dialogDetailList?.attachSize)
                : '--'
            }}
          </div>
          <div>
            <el-button
              type="success"
              plain
              icon="el-icon-download"
              @click="detailDownLoad(dialogDetailList)"
              >下载</el-button
            >
          </div>
        </div>
      </div>
    </el-dialog>
    <!-- 全景预览 -->
    <PanoramaPopup
      v-model:panoramaParamsShow="panoramaParamsShow"
      v-model:panoramaParamsUrl="panoramaParamsUrl"
    ></PanoramaPopup>
    <!-- 视频预览 -->
    <el-dialog
      :title="currentVideoTitle"
      modal-class="videoDialog"
      append-to-body
      width="54%"
      v-model="VideoShow"
      :close-on-click-modal="false"
      :destroy-on-close="true"
      @close="currentVideoIndex = -1"
    >
      <div class="video-container">
        <video
          style="width: 100%"
          class="videoBox"
          ref="videoRefs"
          controls
          autoplay
          :src="currentVideoUrl"
        ></video>
      </div>
    </el-dialog>
    <!-- 地图弹框 -->
    <dataCenterMap
      ref="mapComponent"
      v-model:show="dataCenterMapVisible"
      :jobId="jobId"
      @lookDetail="lookDetail"
      :dotData="mapList"
    ></dataCenterMap>
      </el-dialog>
      <!-- 地图弹框 -->
      <dataCenterMap
        ref="mapComponent"
        v-model:show="dataCenterMapVisible"
        :jobId="jobId"
        @lookDetail="lookDetail"
        :dotData="mapList"
      ></dataCenterMap>
    </div>
  </div>
</template>
@@ -384,10 +377,10 @@
    orderByCreateTime: jobListParams.orderByCreateTime,
    ...jobListParams.searchParams,
  };
  getaiImagesPageAPI(params, {
    current: jobListParams.current,
    size: jobListParams.size
  getaiImagesPageAPI(params, {
    current: jobListParams.current,
    size: jobListParams.size,
  })
    .then(res => {
      total.value = res.data.data.total;
@@ -402,7 +395,7 @@
    })
    .catch(error => {
      // 可选:这里可以添加错误处理逻辑
      console.error("获取数据失败:", error);
      console.error('获取数据失败:', error);
    })
    .finally(() => {
      loadings.value = false; // 无论成功失败都会执行
@@ -465,12 +458,12 @@
const fileDownload = () => {
  const list = selectedRows.value.filter(i => i.checked);
  if (!list?.length) return ElMessage.warning('请选择文件');
    if (list.length === 1) {
      list.forEach((item, index) => {
         const suffix = item.url.split('.').pop()
         aLinkDownload(item.url, item.nickName + '.' + suffix)
      })
   } else {
  if (list.length === 1) {
    list.forEach((item, index) => {
      const suffix = item.url.split('.').pop();
      aLinkDownload(item.url, item.nickName + '.' + suffix);
    });
  } else {
    loading = ElLoading.service({ background: 'rgba(0, 0, 0, 0.5)', text: '打包中,请稍等...' });
    const fileIds = list.map(i => i.id);
    let aaa = {
@@ -497,7 +490,8 @@
  fileDownload();
};
const detailDownLoad = val => {
  aLinkDownload(val.link, val?.nickName);
  const suffix = val.link?.split('.').pop();
  aLinkDownload(val.link, val?.nickName + '.' + suffix);
};
// 全部下载
const aLLDownloadFile = () => {
@@ -536,14 +530,6 @@
const editTitle = val => {
  val.checkedinput = true;
  fileNameedit.value = val?.nickName;
};
// 取消
const cancelEditSuffix = item => {
  item.nickName = fileNameedit.value;
  item.checkedinput = false;
};
const submitEditSuffix = item => {
  saveTitle(item);
};
// 通用空值检查函数
const validateNickname = (name, fieldName) => {
@@ -725,32 +711,40 @@
<style scoped lang="scss">
.dataCenter-table {
  margin: 0 18px 16px 10px;
  background-color: #ffffff;
  padding: 14px 18px;
  height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  .dataTable {
    height: 700px;
    height: 0;
    flex: 1;
    overflow: auto;
    .look {
      color: #1c5cff;
      cursor: pointer;
      margin-right: 10px;
    }
    .delete {
      color: #ff241c;
      margin-right: 10px;
      cursor: pointer;
    }
    .location {
      color: #19876d;
      cursor: pointer;
    }
  }
  .pagination {
    display: flex;
    justify-content: end;
    margin-top: 20px;
  }
  .quanjing,
  .el-image,
  .imageBox {
@@ -758,54 +752,70 @@
    width: 76px;
    height: 72px;
  }
  .videoDialog :deep(.el-dialog) {
    height: 600px;
    width: 54%;
  }
  .video-container {
    width: 100%;
    aspect-ratio: 16/9; /* 按视频比例设置(如16:9) */
    overflow: hidden; /* 隐藏溢出部分 */
    aspect-ratio: 16/9;
    /* 按视频比例设置(如16:9) */
    overflow: hidden;
    /* 隐藏溢出部分 */
  }
  .videoBox {
    width: 100%;
    height: 100%;
    object-fit: contain; /* 保持比例完整显示 */
    object-fit: contain;
    /* 保持比例完整显示 */
    display: block;
  }
}
:deep(.custom-header th.el-table__cell) {
  color: rgba(0, 0, 0, 0.85);
}
// 弹框
.detailContainer {
  display: flex;
  justify-content: space-between;
  .leftImg {
    width: 70%;
    height: 500px;
    img {
      width: 100%;
      height: 100%;
    }
    #detaildataCenterMap {
      width: 100%;
      height: 100%;
    }
  }
  .rightDetail {
    width: 30%;
    padding-left: 40px;
    .title {
      display: flex;
      margin: 0 !important;
      .editname {
        cursor: pointer;
      }
      .inputEdit {
        display: flex;
        align-items: center;
        width: 100%;
        .fileTitle {
          width: 70%;
          white-space: nowrap;
@@ -814,46 +824,57 @@
        }
      }
    }
    div {
      margin-bottom: 20px;
    }
  }
}
.my-header :deep(.el-dialog__title) {
  margin: 0 !important;
  height: 19px;
}
.my-header {
  display: flex;
  align-items: center;
  .el-button {
    margin-left: 20px;
  }
}
.title-input {
  margin-bottom: 0 !important;
  width: 70%;
}
.editname {
  margin-bottom: 0 !important;
}
.suffixBoxEdit {
  display: flex;
  // align-items: center;
  justify-content: space-between;
  margin-bottom: 0 !important;
  font-size: 16px;
  > .editText {
    cursor: pointer;
    margin-right: 6px;
    &:hover {
      transform: scale(1.2);
    }
  }
  .editimg {
    cursor: pointer;
    width: 15px;
    height: 15px;
    &:hover {
      transform: scale(1.2);
    }