无人机管理后台前端(已迁走)
张含笑
2025-06-30 0a8570696ee758b51a979e8de69ca110a411952b
Merge branch 'refs/heads/feature/v3.0.0/帮助中心'
4 files modified
3 files added
416 ■■■■ changed files
src/api/helpCenter/helpCenter.js 27 ●●●●● patch | view | raw | blame | history
src/assets/images/helpCenter/helpIcon.png patch | view | raw | blame | history
src/page/index/top/index.vue 4 ●●●● patch | view | raw | blame | history
src/page/index/top/top-qna.vue 182 ●●●●● patch | view | raw | blame | history
src/router/views/index.js 16 ●●●●● patch | view | raw | blame | history
src/views/algorithmRepository/algorithmRepository.vue 25 ●●●●● patch | view | raw | blame | history
src/views/system/helpCenter.vue 162 ●●●●● patch | view | raw | blame | history
src/api/helpCenter/helpCenter.js
New file
@@ -0,0 +1,27 @@
import request from '@/axios';
// 文件上传
export const uploadFileAPI = (data,params) => {
    return request({
        url: `/blade-resource/oss/endpoint/put-file`,
        method: 'post',
        data,params
    })
  };
// 列表
export const listDataAPI = () => {
    return request({
        url: `/blade-system/helpCenter/list`,
        method: 'get',
    })
  };
//更新
export const updataDataAPI = (data,params) => {
    return request({
        url: `/blade-system/helpCenter/update`,
        method: 'put',
        data,params
    })
  };
src/assets/images/helpCenter/helpIcon.png
src/page/index/top/index.vue
@@ -7,13 +7,13 @@
      </div>
    </div>
    <div class="top-bar__title">
<!--      <top-menu ref="topMenu" v-if="setting.menu"></top-menu>-->
<!--<top-menu ref="topMenu" v-if="setting.menu"></top-menu>-->
      <top-search class="top-bar__item" v-if="setting.search"></top-search>
    </div>
    <div class="top-bar__right">
      <div class="icon-box">
        <top-lock v-if="setting.lock"/>
        <top-qna title="帮助中心"/>
        <top-qna />
        <top-full v-if="setting.fullscreen" title="全屏"/>
        <img class="gateway" @click="jumpMH" src="@/assets/images/mh.png" alt="进入门户" title="进入门户" width="20" height="20">
      </div>
src/page/index/top/top-qna.vue
@@ -1,66 +1,82 @@
<template>
  <div class="top-qna" @mouseenter="disableTooltip" @mouseleave="enableTooltip">
    <el-tooltip :disabled="tooltipDisabled" content="帮助中心" placement="bottom">
      <el-icon @click="showHelp" class="help-icon">
        <QuestionFilled />
      </el-icon>
    </el-tooltip>
    <el-dialog v-model="dialogVisible" title="帮助中心" width="30%" @close="closeDialog">
      <div class="dialog-content">
        <div class="qa-item">
          <span class="qa-title">Q1:智飞机场 2 支持哪些无人机?</span>
          <span class="qa-text">
            A1:智飞机场 2 仅支持 DJI Matrice 3D 系列无人机。
          </span>
        </div>
        <div class="qa-item">
          <span class="qa-title">Q2:智飞机场 2 如何应对意外断电?</span>
          <span class="qa-text">
            A2:若发生意外断电,机场仍可借助内置蓄电池独立工作超 5 小时,为飞行器预留充足的返航降落时间。
            断电后,机场不支持飞行器充电、空调、舱盖加热、风速计加热等功能,请及时排查故障。
          </span>
        </div>
        <div class="qa-item">
          <span class="qa-title">Q3:智飞机场 2 和第一代智飞机场有什么区别?</span>
          <span class="qa-text">
            A3:相对于第一代智飞机场,智飞机场 2 在体积、重量上大幅下降,不仅轻量化、易部署,
            且具备更强大的作业能力和云端智能功能,大幅降低了无人值守作业门槛,作业效率和质量也上升至全新高度。
          </span>
        </div>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="closeDialog">关闭</el-button>
        </span>
  <div class="top-qna">
    <el-dropdown @command="dropdownClick">
      <img alt="" src="@/assets/images/helpCenter/helpIcon.png" />
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item command="guide">入门指南</el-dropdown-item>
          <el-dropdown-item command="systemupdate">系统更新</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dialog>
    </el-dropdown>
  </div>
</template>
<script>
export default {
  name: 'top-qna',
  data() {
    return {
      dialogVisible: false, // 确保初始值为 false
      tooltipDisabled: false, // 控制 tooltip 是否显示
    };
  },
  methods: {
    showHelp() {
      this.dialogVisible = true;
    },
    closeDialog() {
      this.dialogVisible = false;
    },
    disableTooltip() {
      this.tooltipDisabled = true; // 禁用 tooltip
    },
    enableTooltip() {
      this.tooltipDisabled = false; // 启用 tooltip
    },
  },
<script setup>
import { listDataAPI } from '@/api/helpCenter/helpCenter';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
const router = useRouter();
const systemupdateFilePath = ref(null);
const rumenPath = ref(null);
const fileData = ref([]); // 存储所有文件数据
const loading = ref(false);
const getlistDataAPI = async () => {
  loading.value = true;
  try {
    const res = await listDataAPI();
    if (res.data.code === 200 && res.data.data) {
      fileData.value = res.data.data;
      // 使用 find 方法查找特定条目
      const systemUpdateItem = res.data.data.find(item => item.id === 4);
      const rumenItem = res.data.data.find(item => item.id === 2);
      if (systemUpdateItem) {
        systemupdateFilePath.value = systemUpdateItem.filePath;
      } else {
        console.warn('未找到系统更新条目');
      }
      if (rumenItem) {
        rumenPath.value = rumenItem.filePath;
      } else {
        console.warn('未找到入门指南条目');
      }
    } else {
      ElMessage.error('获取帮助数据失败');
    }
  } catch (error) {
    console.error('获取数据出错:', error);
    ElMessage.error('请求失败');
  } finally {
    loading.value = false;
  }
};
const dropdownClick = val => {
  // 确保数据已加载
  if (loading.value) {
    ElMessage.warning('数据正在加载,请稍后');
    return;
  }
  if (val === 'guide') {
    if (!rumenPath.value) {
      ElMessage.warning('入门指南文件未找到');
      return;
    }
  window.open(rumenPath.value, '_blank');
  } else if (val === 'systemupdate') {
  window.open(systemupdateFilePath.value, '_blank');
  }
};
onMounted(() => {
  getlistDataAPI();
});
</script>
<style lang="scss" scoped>
@@ -70,57 +86,5 @@
  font-size: 18px;
  justify-content: center;
  cursor: pointer;
}
/* 优化弹出框样式 */
:deep(.el-dialog) {
  border-radius: 8px; /* 圆角边框 */
  overflow: visible; /* 防止内容溢出 */
  .el-dialog__header {
    padding: 15px 20px;
    border-bottom: 1px solid #e8e8e8; /* 标题下边框 */
    .el-dialog__title {
      font-size: 16px;
      font-weight: bold;
      color: #333;
    }
  }
  .el-dialog__body {
    padding: 20px;
    max-height: none; /* 取消高度限制 */
    overflow: visible; /* 取消滚动条 */
    word-wrap: break-word; /* 自动换行 */
    word-break: break-word; /* 防止长单词溢出 */
    white-space: normal; /* 确保文字自动换行 */
  }
  .el-dialog__footer {
    padding: 10px 20px;
    border-top: 1px solid #e8e8e8; /* 底部上边框 */
    text-align: right;
  }
}
/* 优化内容样式 */
.dialog-content {
  .qa-item {
    margin-bottom: 15px;
    padding: 10px;
    border: 1px solid #e8e8e8; /* 边框 */
    border-radius: 4px; /* 圆角 */
    background-color: #f9f9f9; /* 背景色 */
    .qa-title {
      font-size: 14px;
      font-weight: bold;
      color: #333;
      display: block; /* 确保换行 */
      margin-bottom: 5px;
    }
    .qa-text {
      font-size: 14px;
      color: #666;
      line-height: 1.6; /* 行间距 */
      display: block; /* 确保换行 */
    }
  }
}
</style>
src/router/views/index.js
@@ -141,4 +141,20 @@
      },
    ],
  },
  {
    path: '/helpCenter',
    component: Layout,
    redirect: '/system/helpCenter',
    children: [
      {
        path: 'system',
        name: '帮助中心',
        meta: {
          i18n: 'info',
        },
        component: () => import(/* webpackChunkName: "views" */ '@/views/system/helpCenter.vue'),
      },
    ],
  },
];
src/views/algorithmRepository/algorithmRepository.vue
@@ -102,9 +102,7 @@
</template>
<script setup>
defineOptions({
  name: 'algorithmRepository',
});
import { getDictionaryByCode } from '@/api/system/dictbiz';
import { getalgorithmList, selectDeviceList } from '@/api/algorithm';
import { getSmallImg } from '@/utils/util';
@@ -124,7 +122,7 @@
  device_name: '',
  name: '',
  current: 1,
  size: 10,
  size: 15,
});
// 请求字典字段
@@ -153,7 +151,18 @@
};
// 详情
const getList = () => {
  getalgorithmList(params.value).then(res => {
const detailParams={
   ai_type_key: params.value.ai_type_key,
  start_date:params.value.start_date,
  end_date: params.value.end_date,
  device_name: params.value.device_name,
  name:params.value.name,
}
  getalgorithmList(detailParams,{  current: params.value.current,
    size: params.value.size,}).then(res => {
  console.log('算法仓库',res.data.data);
    loading.value = true;
    detailData.value = res.data.data.records;
    total.value = res.data.data.total;
@@ -279,14 +288,14 @@
  .pictureitem {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 24px;
    gap: 14px;
    .imgitem {
      border-radius: 12px 12px 0 0;
      overflow: hidden;
      .el-image {
        width: 100%;
        height: 200px;
        height: 170px;
        display: block;
        margin: 0;
        padding: 0;
@@ -295,7 +304,7 @@
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 42px;
        height: 35px;
        border-radius: 0 0 12px 12px;
        overflow: hidden;
        background: linear-gradient(180deg, #ffffff 0%, #e5edff 100%);
src/views/system/helpCenter.vue
New file
@@ -0,0 +1,162 @@
<template>
  <basic-container>
    <div class="helpContainer">
      <el-table
        class="custom-table"
        :data="helpData"
        style="width: 100%"
        :row-class-name="tableRowClassName"
      >
        <el-table-column label="序号" type="index" width="100">
          <template #default="{ $index }">
            {{ $index + 1 }}
          </template>
        </el-table-column>
        <el-table-column prop="levelOneType" label="一级类别" />
        <el-table-column prop="levelTwoType" label="二级类别" />
        <el-table-column prop="uploadUser" label="上传者" />
        <el-table-column prop="createTime" label="上传时间" />
        <el-table-column label="操作" width="150" align="center">
          <template #default="scope">
            <span class="look" @click="clickDetail(scope.row)" v-if="permission.helpCenterLook"
              >查看</span
            >
            <el-upload
              style="display: inline-block"
              :show-file-list="false"
              :before-upload="file => onUploadFileBefore(file, scope.row)"
              :limit="1"
              accept=".pdf"
            >
              <span class="uploads" v-if="permission.helpCenterUpload">上传</span>
            </el-upload>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </basic-container>
</template>
<script setup>
import { uploadFileAPI, listDataAPI, updataDataAPI } from '@/api/helpCenter/helpCenter';
import { ElMessage } from 'element-plus';
import { computed, onMounted } from 'vue';
const helpData = ref([]);
import { useStore } from 'vuex';
const store = useStore();
const permission = computed(() => store.state.user.permission);
// 表格隔行变色
const tableRowClassName = ({ row, rowIndex }) => {
  if (rowIndex % 2 === 1) {
    return 'warning-row';
  } else {
    return 'success-row';
  }
};
const getlistDataAPI = () => {
  listDataAPI().then(res => {
    helpData.value = res.data.data;
  });
};
// 查看
// const clickDetail = row => {
//   if (!row.filePath) {
//     ElMessage.warning('没有可预览的文件');
//     return;
//   }
//   fetch(row.filePath)
//     .then(response => response.blob())
//     .then(res => {
//       let blob = new Blob([res], { type: 'application/pdf' });
//       // pdfurl即转化后的结果
//       let pdfurl = window.URL.createObjectURL(blob);
//       // 新标签页打开,即可预览并下载
//       window.open(pdfurl);
//     });
// };
const clickDetail = val => {
  const filePath = val.filePath;
  if (!val.filePath) {
    ElMessage.warning('没有可预览的文件');
    return;
  }
  window.open(filePath, '_blank');
};
// 文件上传
const onUploadFileBefore = (file, row) => {
  const fileFormat = file.name?.split('.')[1];
  if (fileFormat !== 'pdf') return ElMessage.error('请上传pdf格式的文件');
  const formData = new FormData();
  formData.append('file', file, file.name);
  uploadFileAPI(formData).then(res => {
    if (res.data.code === 200) {
      const params = {
        id: row.id,
        filePath: res.data.data.link,
      };
      ElMessage.success('上传成功');
      updataDataAPI(params);
    } else {
      ElMessage.error('上传失败');
    }
    getlistDataAPI();
  });
};
onMounted(() => {
  getlistDataAPI();
});
</script>
<style lang="scss">
.helpContainer {
  .el-table .success-row {
    --el-table-tr-bg-color: #fff;
  }
  .el-table .warning-row {
    --el-table-tr-bg-color: #f3f6ff;
  }
}
</style>
<style scoped lang="scss">
/* 表头样式 */
.custom-table :deep(.el-table__header) th {
  height: 70px;
  font-family: Source Han Sans CN, Source Han Sans CN;
  font-weight: bold;
  font-size: 14px;
  color: #49556e;
  background-color: #f3f6ff;
  text-align: center;
}
/* 行样式 */
.custom-table :deep(.el-table__body) tr {
  height: 70px;
  font-family: Source Han Sans CN, Source Han Sans CN;
  font-weight: 400;
  font-size: 14px;
  color: #363636;
  text-align: center;
}
.custom-table :deep(.el-table__body) td.el-table__cell {
  text-align: center;
}
.helpContainer {
  height: 100%;
  .look {
    font-family: Source Han Sans CN, Source Han Sans CN;
    color: #1c5cff;
    cursor: pointer;
    margin-right: 15px;
    font-size: 14px;
  }
  .uploads {
    font-family: Source Han Sans CN, Source Han Sans CN;
    font-weight: 400;
    font-size: 14px;
    color: #19876d;
    cursor: pointer;
  }
}
</style>