1 files modified
2 files added
| | |
| | | }); |
| | | }; |
| | | |
| | | |
| | | |
| | | export const getDeviceUpgradeInfo = (params) => { |
| | | return request({ |
| | | url: '/drone-yw/manage/api/v1/workspaces/firmware-release-notes/latest', |
| | |
| | | data: row, |
| | | }); |
| | | }; |
| | | |
| | | |
| | | export const getDeviceFirmwareList = (current, size, params) => { |
| | | return request({ |
| | |
| | | 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', |
| | | }); |
| | | }; |
| New file |
| | |
| | | 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', |
| | | }); |
| | | }; |
| New file |
| | |
| | | <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> |