Bladeren bron

feat: electron下载文件到指定目录

HeWang 10 maanden geleden
bovenliggende
commit
8423a8f970
3 gewijzigde bestanden met toevoegingen van 147 en 45 verwijderingen
  1. 40 22
      electron/main.js
  2. 8 0
      electron/preload.js
  3. 99 23
      src/views/ReportView.vue

+ 40 - 22
electron/main.js

@@ -2,6 +2,8 @@ import {app, BrowserWindow, ipcMain, dialog} from 'electron';
 import {exec, spawn} from 'child_process';
 import path from 'path';
 import {fileURLToPath} from 'url';
+import fs from 'fs';
+import axios from 'axios';
 
 
 const __filename = fileURLToPath(import.meta.url);
@@ -111,28 +113,6 @@ ipcMain.on('docker-import', (event, sudoPassword, filePath, tag) => {
     });
 });
 
-// ipcMain.on('generate-world', (event, rosbag_path) => {
-//
-//     const serviceScript = 'nonhup bash /home/cicv/work/pji_desktop/run_map2gazabo.sh >/dev/null 2>&1 & '
-//     const child1 = exec(serviceScript, (error, stdout, stderr) => {
-//         if (error) {
-//             console.error(`exec error: ${error}`);
-//             return;
-//         }
-//         console.log(`stdout: ${stdout}`);
-//         console.error(`stderr: ${stderr}`);
-//
-//         // 启动第二个脚本
-//         const script2 = exec('/home/cicv/work/pji_desktop/play_rosbag.sh /home/cicv/work/pji_desktop/map_bag/map_anqing.bag', (error, stdout, stderr) => {
-//             if (error) {
-//                 console.error(`执行第二个脚本时出错: ${error}`);
-//                 return;
-//             }
-//             console.log(`第二个脚本的输出: ${stdout}`);
-//         });
-//     });
-// });
-
 ipcMain.on('generate-world', (event, rosbag_path) => {
 
     // 使用 spawn 启动脚本
@@ -176,3 +156,41 @@ ipcMain.on('generate-world', (event, rosbag_path) => {
     }
 });
 
+
+ipcMain.handle('download-file', async (event, { url, fileName, savePath }) => {
+    try {
+        const response = await axios.get(url, { responseType: 'stream' });
+
+        // console.log("url", url)
+        // console.log("response", response)
+
+        const filePath = path.join(savePath, fileName);
+
+        // 写入文件
+        const writer = fs.createWriteStream(filePath);
+
+        return new Promise((resolve, reject) => {
+            response.data.pipe(writer);
+
+            let error = null;
+            writer.on('error', err => {
+                error = err;
+                writer.close();
+                reject(err);
+            });
+
+            writer.on('close', () => {
+                if (!error) {
+                    resolve({ success: true, filePath }); // 返回成功信息
+                } else {
+                    reject({ success: false, error: error.message }); // 返回错误信息
+                }
+            });
+        });
+    } catch (error) {
+        // console.error('下载文件出错:', error);
+        throw error;
+    }
+});
+
+

+ 8 - 0
electron/preload.js

@@ -38,6 +38,14 @@ contextBridge.exposeInMainWorld('electronAPI', {
         // 发送事件到主进程
         ipcRenderer.send('generate-world', rosbag_path);
     },
+    downloadFile: async (url, fileName, savePath) => {
+        try {
+            return await ipcRenderer.invoke('download-file', { url, fileName, savePath });
+        } catch (error) {
+            console.error('下载文件时出错:', error);
+            return { success: false, error: error.message };
+        }
+    },
 
 });
 

+ 99 - 23
src/views/ReportView.vue

@@ -49,13 +49,13 @@
               width="400"
               :before-close="handleClose"
           >
-            <el-steps style="max-width: 600px" :active="active" finish-status="success">
+            <el-steps style="max-width: 600px" :active="update_active" finish-status="success">
               <el-step title="数据格式检查"/>
               <el-step title="地图生成"/>
             </el-steps>
 
             <template #footer>
-              <el-button @click="goToMapUpdate" :disabled="active !== 2">去部署</el-button>
+              <el-button @click="goToMapUpdate" :disabled="update_active !== 2">去部署</el-button>
             </template>
           </el-dialog>
 
@@ -143,6 +143,24 @@
             <el-button style="margin-left: 10px;" type="primary" @click="goToTestRecord">仿真测试记录</el-button>
           </div>
         </div>
+
+
+        <el-dialog
+            v-model="worldDialogVisible"
+            title="生成world"
+            width="400"
+            :before-close="handleClose"
+        >
+          <el-steps style="max-width: 600px" :active="world_active" finish-status="success">
+            <el-step title="数据准备"/>
+            <el-step title="world生成"/>
+            <el-step title="world上传"/>
+          </el-steps>
+
+          <template #footer>
+            <el-button @click="goToMapUpdate" :disabled="world_active !== 2">去部署</el-button>
+          </template>
+        </el-dialog>
         <el-table stripe style="background-color: rgba(255,0,0,99%);width: 100%" border :data="tableData"
                   fixed ref="multipleTableRef" @selection-change="handleSelectionChange" :cell-style="{ textAlign: 'center'}" :header-cell-style="{ textAlign: 'center'}">
           <el-table-column type="selection" width="55"/>
@@ -155,9 +173,12 @@
           <el-table-column prop="callbackTime" label="上报时间"/>
           <el-table-column prop="dataStateName" label="数据状态"/>
           <el-table-column width="300" fixed="right" label="操作">
-            <el-button size="small" type="danger" @click="generateWorld">生成world</el-button>
-            <el-button size="small" type="danger" @click="goToDetail">仿真测试</el-button>
-            <!--            <el-button size="small" type="danger" @click="goToDetail">算法评价</el-button>-->
+            <template v-slot="scope">
+              <el-button size="small" type="danger" @click="generateWorld(scope.row.id)">生成world</el-button>
+              <el-button size="small" type="danger" @click="goToDetail">仿真测试</el-button>
+              <!--            <el-button size="small" type="danger" @click="goToDetail">算法评价</el-button>-->
+            </template>
+
           </el-table-column>
         </el-table>
         <p></p> <!--空行-->
@@ -187,11 +208,13 @@ import {reactive} from 'vue'
 import {ElTable} from "element-plus";
 import { ElMessage } from "element-plus";
 import {useRouter} from 'vue-router'; // 导入 Vue Router 的 useRouter 钩子
+import * as fs from "fs";
 
 
 const value
     = ref(true)
-const active = ref(0)
+const update_active = ref(0)
+const world_active = ref(0)
 const router = useRouter();
 const algorithmContainerState = ref(false)
 const gazeboState = ref(false)
@@ -201,6 +224,7 @@ const multipleTableRef = ref<InstanceType<typeof ElTable>>
 const algorithmDialogVisible = ref(false)
 const mapDialogVisible = ref(false)
 const updateDialogVisible = ref(false)
+const worldDialogVisible = ref(false)
 
 const handleClose = (done: () => void) => {
   done()
@@ -342,25 +366,77 @@ const rviz = () => {
 }
 
 
-const generateWorld = () => {
-  // if (rvizState.value) {
-  //   if (window.electronAPI) {
-  //     window.electronAPI.generateWorld();
-  //   } else {
-  //     console.error('electronAPI is not defined');
-  //   }
-  // } else {
-  //   if (window.electronAPI) {
-  //     window.electronAPI.closeRviz();
-  //   } else {
-  //     console.error('electronAPI is not defined');
-  //   }
-  // }
-  console.log("11111")
-
-  window.electronAPI.generateWorld()
+const generateWorld = async (id) => {
+
+  console.log("id", id);
+  console.log("Starting generating world...")
+  worldDialogVisible.value = true
+
+  // axios.get('http://127.0.0.1:8888/map/downloadmapbagfile?id=1820978518251540482',
+  //     {
+  //       responseType: 'stream'
+  //     }
+  // ).then(function (response) {
+  //   console.log("response", response);
+  //   console.log("response", response.data.message);
+  //   // const url = window.URL.createObjectURL(new Blob([response.data]));
+  //   // const link = document.createElement('a');
+  //   // link.href = url;
+  //   // link.setAttribute('download', "test.pdf"); // 设置下载的文件名
+  //   // document.body.appendChild(link);
+  //   // link.click();
+  //
+  //   let filePath = "/home/cicv/work/pji_desktop"
+  //
+  //   //从header中读取文件名称
+  //   const headerFilename = response.headers['content-disposition']?.split(';')[1].split('=')[1];
+  //   console.log("response.headers", response.headers)
+  //   console.log("headerFilename",  headerFilename);
+  //   const fileName = decodeURIComponent(headerFilename);
+  //
+  //   downloadByData(response.data, fileName, 'application/json');
+  //
+  //
+  //
+  // }).catch(function (error) {
+  //   console.log(error);
+  // });
+
+  const url = "http://127.0.0.1:8888/map/downloadmapbagfile?id=" + id
+  const fileName = "map-" + id + ".bag"
+  const savePath = "/home/cicv/work"
+
+  const result = await window.electronAPI.downloadFile(url, fileName, savePath);
+  if (!result.success) {
+    console.error('File download failed:', result.error);
+    ElMessage.error("地图bag数据拉取失败!");
+  } else {
+    console.log('File downloaded successfully:', result.filePath);
+    world_active.value = 1
+  }
+
 }
 
+
+
+// function downloadByData(data: BlobPart, filename: string, mime?: string, bom?: BlobPart) {
+//   const blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
+//   const blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
+//
+//   const blobURL = window.URL.createObjectURL(blob);
+//   const tempLink = document.createElement('a');
+//   tempLink.style.display = 'none';
+//   tempLink.href = blobURL;
+//   tempLink.setAttribute('download', filename);
+//   if (typeof tempLink.download === 'undefined') {
+//     tempLink.setAttribute('target', '_blank');
+//   }
+//   document.body.appendChild(tempLink);
+//   tempLink.click();
+//   document.body.removeChild(tempLink);
+//   window.URL.revokeObjectURL(blobURL);
+// }
+
 const queryLine = reactive({
   dataName: '',
   equipmentName: '',