From 8eba7f2a5f54500f632511d8db114c2a9931b916 Mon Sep 17 00:00:00 2001
From: rain <167982779@qq.com>
Date: Thu, 27 Feb 2025 17:30:43 +0800
Subject: [PATCH] 媒体文件页面

---
 src/api/media/media.js       |   33 ++++
 src/api/device/device.js     |   10 
 src/views/resource/media.vue |  378 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+), 3 deletions(-)

diff --git a/src/api/device/device.js b/src/api/device/device.js
index cd84c9a..f21e186 100644
--- a/src/api/device/device.js
+++ b/src/api/device/device.js
@@ -66,8 +66,6 @@
   });
 };
 
-
-
 export const getDeviceUpgradeInfo = (params) => {
   return request({
     url: '/drone-yw/manage/api/v1/workspaces/firmware-release-notes/latest',
@@ -83,7 +81,6 @@
     data: row,
   });
 };
-
 
 export const getDeviceFirmwareList = (current, size, params) => {
   return request({
@@ -129,4 +126,11 @@
     url: `/drone-yw/manage/api/v1/devices/${workspace_id}/devices/${device_sn}`,
     method: 'get',
   });
+};
+
+export const getAirportList = () => {
+  return request({
+    url: '/drone-yw/manage/api/v1/devices/getAirportList',
+    method: 'get',
+  });
 };
\ No newline at end of file
diff --git a/src/api/media/media.js b/src/api/media/media.js
new file mode 100644
index 0000000..1c16745
--- /dev/null
+++ b/src/api/media/media.js
@@ -0,0 +1,33 @@
+import request from '@/axios';
+
+export const getMedia = (page, page_size, workspace_id = null, create_time = null, end_time = null) => {
+  return request({
+    url: '/drone-yw/media/api/v1/files/filesByUser',
+    method: 'get',
+    params: {
+      page,
+      page_size,
+      workspace_id,
+      create_time,
+      end_time,
+    },
+  });
+};
+
+export const getFilesByWorkspace = (workspace_id, page, page_size) => {
+  return request({
+    url: `/drone-yw/media/api/v1/files/${workspace_id}/files`,
+    method: 'get',
+    params: {
+      page,
+      page_size,
+    },
+  });
+};
+
+export const deleteAllFile = (id) => {
+  return request({
+    url: `/drone-yw/media/api/v1/files/deleteAllFile?id=${id}`,
+    method: 'delete',
+  });
+};
diff --git a/src/views/resource/media.vue b/src/views/resource/media.vue
new file mode 100644
index 0000000..205dfe0
--- /dev/null
+++ b/src/views/resource/media.vue
@@ -0,0 +1,378 @@
+<template>
+  <basic-container>
+    <avue-crud :option="option" :table-loading="loading" :data="data" v-model:page="page" :permission="permissionList"
+      v-model="form" ref="crud" @row-del="rowDel" @search-change="searchChange" @search-reset="searchReset"
+      @selection-change="selectionChange" @current-change="currentChange" @size-change="sizeChange"
+      @refresh-change="refreshChange" @on-load="onLoad">
+      <template #menu="scope">
+        <el-button type="primary" text icon="el-icon-view" v-if="permission.attach_delete"
+          @click="handleRowView(scope.row)">查看
+        </el-button>
+        <el-button type="danger" text icon="el-icon-delete" v-if="permission.attach_delete"
+          @click="handleRowDelete(scope.row)">删除
+        </el-button>
+      </template>
+    </avue-crud>
+    <el-dialog title="媒体文件" append-to-body v-model="taskBox" width="555px">
+      <avue-form ref="form" :option="taskOption" v-model="taskForm" :upload-after="uploadAfter">
+      </avue-form>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+import { getMedia, deleteAllFile } from '@/api/media/media'; // 导入媒体相关的 API 方法
+import { getAirportList } from '@/api/device/device';        // 导入设备相关的 API 方法
+import { mapGetters } from 'vuex';                           // 从 Vuex 导入 mapGetters
+import func from '@/utils/func';                             // 导入工具函数
+
+export default {
+  data() {
+    return {
+      form: {},           // 表单数据对象
+      query: {},          // 搜索查询条件
+      loading: true,      // 表格加载状态
+      page: {             // 分页数据
+        pageSize: 10,     // 每页显示数量
+        currentPage: 1,   // 当前页码
+        total: 0,         // 总记录数
+      },
+      taskBox: false,     // 控制弹窗显示状态
+      selectionList: [],  // 选中的行数据列表
+      selectedWorkspaceId: null, // 选中的工作区 ID
+      option: {           // Avue CRUD 表格配置
+        height: 'auto',   // 表格高度自动调整
+        calcHeight: 32,   // 计算高度的偏移量
+        tip: false,       // 不显示提示
+        searchShow: true, // 显示搜索栏
+        searchMenuSpan: 6,// 搜索栏宽度占比
+        border: true,     // 显示边框
+        index: true,      // 显示序号列
+        viewBtn: true,    // 显示查看按钮
+        selection: true,  // 允许多选
+        dialogClickModal: false, // 对话框点击遮罩不关闭
+        delBtn: false,    // 不显示默认删除按钮
+        column: [         // 表格列配置
+          {
+            label: '机场选择',       // 列标题
+            prop: 'airportNickname', // 数据字段
+            type: 'select',         // 下拉选择类型
+            search: true,           // 可搜索
+            searchSpan: 5,          // 搜索栏宽度占比
+            dicData: [],            // 下拉选项数据
+            props: {                // 下拉选项映射
+              label: 'nickname',
+              value: 'nickname',
+            },
+            hide: true,             // 默认隐藏
+          },
+          {
+            label: '创建日期',       // 列标题
+            prop: 'daterange',      // 数据字段
+            type: 'daterange',      // 日期范围选择类型
+            search: true,           // 可搜索
+            searchRange: true,      // 支持范围搜索
+            searchSpan: 6,          // 搜索栏宽度占比
+            format: 'YYYY-MM-DD',   // 显示格式
+            valueFormat: 'YYYY-MM-DD', // 值格式
+            startPlaceholder: '开始时间', // 开始时间占位符
+            endPlaceholder: '结束时间',   // 结束时间占位符
+            viewDisplay: false,     // 查看时不显示
+            hide: true,             // 默认隐藏
+            value: [new Date(new Date().setMonth(new Date().getMonth() - 1)), new Date()], // 默认值:过去一个月至今
+          },
+          { label: '任务名称', prop: 'job_name' },    // 任务名称列
+          { label: '文件名称', prop: 'file_name' },   // 文件名称列
+          { label: '拍摄时间', prop: 'create_time' }, // 拍摄时间列
+          { label: '文件路径', prop: 'object_key' },  // 文件路径列
+          { label: '设备负载', prop: 'payload' },     // 设备负载列
+        ],
+      },
+      data: [],         // 表格数据
+      taskForm: {},     // 弹窗表单数据
+      taskOption: {     // 弹窗表单配置
+        submitBtn: false, // 不显示提交按钮
+        emptyBtn: false,  // 不显示清空按钮
+        column: [         // 表单列配置
+          {
+            label: '任务上传',         // 上传字段标题
+            prop: 'taskFile',         // 数据字段
+            type: 'upload',           // 上传类型
+            drag: true,               // 支持拖拽上传
+            loadText: '任务上传中,请稍等', // 上传中提示
+            span: 24,                 // 占用整行
+            propsHttp: {              // HTTP 响应映射
+              res: 'data',
+            },
+            action: '/blade-resource/oss/endpoint/put-file-task', // 上传接口地址
+          },
+        ],
+      },
+      domainUrl: '',    // 媒体文件域名,从 API 获取
+    };
+  },
+  computed: {
+    func() {           // 计算属性,返回工具函数
+      return func;
+    },
+    ...mapGetters(['permission']), // 从 Vuex 获取权限数据
+    permissionList() { // 计算权限列表
+      return {
+        addBtn: false,  // 不显示添加按钮
+        editBtn: false, // 不显示编辑按钮
+        viewBtn: this.validData(this.permission.attach_view, false), // 查看权限
+        delBtn: this.validData(this.permission.attach_delete, false), // 删除权限
+      };
+    },
+    ids() {            // 计算选中的行 ID 列表
+      let ids = [];
+      this.selectionList.forEach(ele => {
+        ids.push(ele.id);
+      });
+      return ids.join(',');
+    },
+  },
+  mounted() {         // 组件挂载时执行
+    this.loadAirportList(); // 加载机场列表
+    this.onLoad(this.page); // 加载初始数据
+  },
+  methods: {
+    // 加载机场下拉列表数据
+    loadAirportList() {
+      getAirportList().then(res => {
+        const airportData = res.data.data || [];
+        const airportColumn = this.option.column.find(col => col.prop === 'airportNickname');
+        if (airportColumn) {
+          airportColumn.dicData = airportData.map(item => ({
+            nickname: item.nickname,
+            workspace_id: item.workspace_id,
+          }));
+        }
+      }).catch(error => {
+        console.error('加载机场列表时出错:', error);
+      });
+    },
+    // 打开上传弹窗
+    handleUpload() {
+      this.taskBox = true;
+    },
+    // 处理上传完成后的操作
+    uploadAfter(res, done) {
+      this.taskBox = false; // 关闭弹窗
+      this.refreshChange(); // 刷新表格
+      done();               // 完成上传
+    },
+    // 删除单行数据
+    handleRowDelete(row) {
+      this.$confirm('确定删除此文件?', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          return deleteAllFile(row.id); // 调用删除 API
+        })
+        .then(() => {
+          this.onLoad(this.page);       // 重新加载数据
+          this.$message({
+            type: 'success',
+            message: '删除成功!',
+          });
+        })
+        .catch(error => {
+          console.error('删除文件时出错:', error);
+          this.$message({
+            type: 'error',
+            message: '删除失败,请稍后重试!',
+          });
+        });
+    },
+    // 删除行(由 avue-crud 触发)
+    rowDel(row) {
+      this.$confirm('确定将选择数据及对应的文件删除?', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          return deleteAllFile(row.id); // 调用删除 API
+        })
+        .then(() => {
+          this.onLoad(this.page);       // 重新加载数据
+          this.$message({
+            type: 'success',
+            message: '操作成功!',
+          });
+        });
+    },
+    // 重置搜索条件
+    searchReset() {
+      this.query = {};
+      this.selectedWorkspaceId = null;
+      this.onLoad(this.page);
+    },
+    // 处理搜索条件变化
+    searchChange(params, done) {
+      this.query = params;
+      this.page.currentPage = 1;
+
+      const airportColumn = this.option.column.find(col => col.prop === 'airportNickname');
+      const selectedAirport = airportColumn.dicData.find(item => item.nickname === params.airportNickname);
+      this.selectedWorkspaceId = selectedAirport ? selectedAirport.workspace_id : null;
+
+      this.onLoad(this.page, params);
+      done();
+    },
+    // 更新选中的行列表
+    selectionChange(list) {
+      this.selectionList = list;
+    },
+    // 清空选择
+    selectionClear() {
+      this.selectionList = [];
+      this.$refs.crud.toggleSelection();
+    },
+    // 处理页码变化
+    currentChange(currentPage) {
+      this.page.currentPage = currentPage;
+      this.onLoad(this.page, this.query);
+    },
+    // 处理每页数量变化
+    sizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.onLoad(this.page, this.query);
+    },
+    // 刷新表格数据
+    refreshChange() {
+      this.onLoad(this.page, this.query);
+    },
+    // 从 API 加载表格数据
+    onLoad(page, params = {}) {
+      this.loading = true;
+      const { daterange } = params;
+      let create_time = this.create_time;
+      let end_time = this.end_time;
+
+      if (daterange && Array.isArray(daterange) && daterange.length === 2) {
+        const startStr = daterange[0];
+        const endStr = daterange[1];
+        const startDate = new Date(startStr + ' 00:00:00').getTime();
+        const endDate = new Date(endStr + ' 23:59:59').getTime();
+        if (!isNaN(startDate) && !isNaN(endDate)) {
+          create_time = startDate;
+          end_time = endDate;
+        }
+      }
+
+      let values = {
+        ...params,
+        ...this.query,
+      };
+      if (daterange) {
+        values.daterange = null;
+      }
+
+      getMedia(
+        page.currentPage,
+        page.pageSize,
+        this.selectedWorkspaceId || null,
+        create_time,
+        end_time
+      ).then(res => {
+        const data = res.data;
+        if (data && data.data && data.data.list) {
+          this.page.total = data.data.pagination.total;
+          this.data = data.data.list.map(item => ({
+            job_name: item.job_name,
+            file_name: item.file_name,
+            create_time: this.formatCreateTime(item.create_time),
+            object_key: item.object_key,
+            payload: item.payload,
+            airportNickname: item.airportNickname,
+            id: item.id,
+          }));
+          this.domainUrl = data.data.list.length > 0 ? data.data.list[0].domain_url : 'http://localhost:2888/manage/resource'; // 设置域名
+        } else {
+          this.data = [];
+        }
+        this.loading = false;
+        this.selectionClear();
+        this.$refs.crud.refreshTable();
+      }).catch(error => {
+        this.loading = false;
+        console.error('加载媒体数据时出错:', error);
+      });
+    },
+    // 格式化时间戳为可读日期
+    formatCreateTime(createTime) {
+      if (typeof createTime !== 'number' || isNaN(createTime)) {
+        return '';
+      }
+      const timestamp = createTime < 10000000000 ? createTime * 1000 : createTime;
+      const date = new Date(timestamp);
+      if (isNaN(date.getTime())) {
+        return '';
+      }
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      const hours = String(date.getHours()).padStart(2, '0');
+      const minutes = String(date.getMinutes()).padStart(2, '0');
+      const seconds = String(date.getSeconds()).padStart(2, '0');
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+    // 处理查看行(打开图片或视频)
+    handleRowView(row) {
+      const mediaUrl = this.domainUrl + row.object_key; // 拼接完整媒体 URL
+      const mediaType = this.getMediaType(row.object_key); // 判断媒体类型
+
+      if (mediaType === 'image') {
+        window.open(mediaUrl, '_blank'); // 图片在新窗口打开
+      } else if (mediaType === 'video') {
+        // 临时测试:视频也在新窗口打开
+        window.open(mediaUrl, '_blank');
+        // this.showVideo(mediaUrl);        // 原逻辑:视频在弹窗中播放
+      }
+    },
+    // 判断文件是图片还是视频
+    getMediaType(objectKey) {
+      const extension = objectKey.split('.').pop().toLowerCase(); // 获取文件扩展名
+      if (['jpg', 'jpeg', 'png', 'gif'].includes(extension)) {
+        return 'image'; // 是图片
+      } else if (['mp4', 'avi', 'mov'].includes(extension)) {
+        return 'video'; // 是视频
+      }
+      return 'unknown'; // 未知类型
+    },
+    // 在弹窗中显示视频
+    showVideo(url) {
+      this.taskBox = true; // 打开弹窗
+      this.taskForm = {
+        videoUrl: url,     // 设置视频 URL
+      };
+      this.taskOption = {  // 配置视频播放选项
+        submitBtn: false,
+        emptyBtn: false,
+        column: [
+          {
+            label: '视频播放',
+            prop: 'videoUrl',
+            type: 'video',
+            span: 24,
+            props: {
+              controls: true,  // 显示控制条
+              autoplay: false, // 不自动播放
+            },
+          },
+        ],
+      };
+    },
+    // 检查权限有效性(假设这是定义在其他地方的工具方法)
+    validData(val, def) {
+      return typeof val !== 'undefined' ? val : def;
+    },
+  },
+};
+</script>
+
+<style></style>
\ No newline at end of file

--
Gitblit v1.9.3