Bläddra i källkod

feat: 地图更新&地图更新统计

HeWang 8 månader sedan
förälder
incheckning
00d7151c71

+ 204 - 27
electron/main.js

@@ -145,33 +145,6 @@ ipcMain.on('upload-file', async (event, {filePath, uploadUrl}) => {
         event.reply('upload-file-response', {success: false, message: 'File does not exist'});
         return;
     }
-    // 读取文件
-    // fs.readFile(filePath, async (err, data) => {
-    //     if(err) {
-    //         console.log("Error reading file:", err);
-    //         event.reply('upload-file-response', { success: false, message: err.message });
-    //         return;
-    //     }
-    //
-    //     // 创建formData对象
-    //     const formData = new FormData();
-    //     formData.append('file', new Blob([data]), path.basename(filePath));
-    //
-    //     try {
-    //         // 使用axios上传文件
-    //         const response = await axios.post(uploadUrl, formData, {
-    //             headers: {
-    //                 'Content-Type': 'multipart/form-data'
-    //             }
-    //         })
-    //         console.log('response', response)
-    //         event.reply('upload-file-response', { success: true, message: 'File uploaded successfully' });
-    //     } catch (err) {
-    //         console.log("Error uploading file:", err);
-    //         event.reply('upload-file-response', { success: false, message: err.message });
-    //     }
-    // })
-
     try {
         const result = await uploadFile(filePath, uploadUrl);
         console.log("result", result);
@@ -248,6 +221,27 @@ ipcMain.on('docker-import', (event, filePath, tag) => {
     });
 });
 
+// 更新地图
+ipcMain.on('update-map', (event, {container_name, file_path}) => {
+    const command = 'bash /home/cicv/work/pji_desktop/map_update/run_map_update.sh ' + container_name + ' ' + file_path;
+    console.log('command:', command);
+
+    processManager.startProcess('update-map', command, (error, stdout, stderr) => {
+        if (error) {
+            console.error(`exec error: ${error}`);
+            // event.reply('update-map-response', { success: false, message: error.message });
+        } else {
+            console.log(`stdout: ${stdout}`);
+            console.error(`stderr: ${stderr}`);
+            if (stdout.toString().includes('Result JSON file created')) { // 判断结束标志
+                event.reply('update-map-response', { success: true, message: 'Update map successfully' });
+            } else {
+                event.reply('update-map-response', { success: false, message: 'Error updating map' });
+            }
+        }
+    });
+});
+
 // 生成world
 ipcMain.on('generate-world', (event, {rosbag_path}) => {
     const command = 'bash /home/cicv/work/pji_desktop/simulation/generate_world.sh ' + rosbag_path
@@ -430,4 +424,187 @@ ipcMain.handle('process-evaluation-files', async (event, {N, equipmentNo, sceneN
     } else {
         return { success: false, message: "Error uploading evaluation results", data: [] }
     }
+})
+
+async function uploadMapResult(filePath, uploadUrl) {
+    // 查找文件是否存在
+    let fileExists = fs.existsSync(filePath)
+    let uploadResult = await uploadFileWithRetry(filePath, uploadUrl);
+    if (!fileExists) return { success: false, message: "Error uploading map results", data: [] }
+    // console.log("uploadResult", uploadResult);
+    if (!uploadResult.status) {
+        return { success: false, message: "Error uploading map results", data: [] }
+    }
+    return { success: true, message: "", data: uploadResult }
+}
+
+// 读取并上传地图更新结果
+ipcMain.handle('process-map-update-files', async (event, {equipmentNo, timeStamp}) => {
+    let result = {}
+    equipmentNo  = "pji-test"
+    timeStamp = Date.now()
+    // 记录时间戳
+    console.log("timeStamp", timeStamp);
+    const mapBufDir = "/home/cicv/work/pji_desktop/map_update/data/bag_folder/mapBuf";
+    const resultDir = "/home/cicv/work/pji_desktop/map_update/data/bag_folder/result";
+    const updateMapDir = "/home/cicv/work/pji_desktop/map_update/data/bag_folder/update_map";
+
+    // 读取result*.json
+    // 文件路径 - result*.json
+    const jsonPrefix = "result";
+    let files = fs.readdirSync(resultDir);
+    let matchedFile = files.find(file => file.startsWith(jsonPrefix))
+    let jsonFilePath = ""
+    if (matchedFile) {
+        // 如果找到匹配的文件
+        jsonFilePath = path.join(resultDir, matchedFile);
+    }
+
+    console.log("jsonFilePath", jsonFilePath);
+
+    // 文件路径 - 更新前pgm
+    const prePgmPath = path.join(mapBufDir, "map.pgm");
+    console.log("prePgmPath", prePgmPath);
+    // 文件路径 - 更新后pgm
+    const pgmSuffix = ".pgm";
+    files = fs.readdirSync(updateMapDir);
+    matchedFile = files.find(file => file.endsWith(pgmSuffix))
+    let updatePgmPath = ""
+    if (matchedFile) {
+        // 如果找到匹配的文件
+        updatePgmPath = path.join(updateMapDir, matchedFile);
+    }
+    console.log("updatePgmPath", updatePgmPath);
+    // 文件路径 - 更新前png
+    const prePngPath = path.join(mapBufDir, "map_pre.png");
+    console.log("prePngPath", prePngPath);
+    // 文件路径 - 更新后png
+    const updatePngPath = path.join(mapBufDir, "map_update.png");
+    console.log("updatePngPath", updatePngPath);
+
+    try {
+        // 读取json文件
+        const jsonData = fs.readFileSync(jsonFilePath, "utf-8");
+        const parsedData = JSON.parse(jsonData);
+        console.log("parsedData", parsedData);
+
+        const mapId = parsedData["origin_pgm_id"];
+
+        // 上传 更新前pgm
+        let uploadUrl = "http://127.0.0.1:8888/map/upload/map?equipmentNo=" + equipmentNo + "&mapId=" + mapId +
+            "&timeStamp=" + timeStamp ;
+
+        // 上传文件
+        // 上传 更新前pgm
+        let res = await uploadMapResult(prePgmPath, uploadUrl);
+        if (!res.success) {
+            return { success: false, message: "Error uploading map results", data: [] }
+        }
+        let prePgmUrl = res.data.details
+        console.log("prePgmUrl", prePgmUrl);
+
+        // 上传 更新前png
+        res = await uploadMapResult(prePngPath, uploadUrl);
+        if (!res.success) {
+            return { success: false, message: "Error uploading map results", data: [] }
+        }
+        let prePngUrl = res.data.details
+        console.log("prePngUrl", prePngUrl);
+
+        // 上传 更新后pgm
+        res = await uploadMapResult(updatePgmPath, uploadUrl);
+        if (!res.success) {
+            return { success: false, message: "Error uploading map results", data: [] }
+        }
+        let updatePgmUrl = res.data.details
+        console.log("updatePgmUrl", updatePgmUrl);
+
+        // 上传 更新后png
+        res = await uploadMapResult(updatePngPath, uploadUrl);
+        if (!res.success) {
+            return { success: false, message: "Error uploading map results", data: [] }
+        }
+        let updatePngUrl = res.data.details
+        console.log("updatePngUrl", updatePngUrl);
+
+        result = {
+            "jsonData": parsedData,
+            "prePgmUrl": prePgmUrl,
+            "prePngUrl": prePngUrl,
+            "updatePgmUrl": updatePgmUrl,
+            "updatePngUrl": updatePngUrl
+        }
+
+        return { success: true, message: "Evaluation results uploaded successfully", data: result }
+    } catch (error) {
+        console.log("error", error);
+    }
+
+
+
+    // // 遍历评价结果文件夹,读取并上传相关数据
+    // for (let i = 1; i <= N; i++) {
+    //     const subDir = path.join(evalDir, `${i}/result`);
+    //     console.log("subDir", subDir);
+    //     // 文件路径 - report.json
+    //     const jsonFilePath = path.join(subDir, "report.json");
+    //     console.log("jsonFilePath", jsonFilePath);
+    //     // 文件路径 - report.pdf
+    //     const pdfFilePath = path.join(subDir, "report.pdf");
+    //     console.log("pdfFilePath", pdfFilePath);
+    //     // 文件路径 - test-${i}.bag
+    //     const bagFilePath = path.join(bagDir, `test-${i}.bag`);
+    //     console.log("bagFilePath", bagFilePath);
+    //
+    //     const uploadPdfUrl = "http://127.0.0.1:8888/simulation/upload/pdf?equipmentNo=" + equipmentNo + "&sceneNo=" + sceneNo +
+    //         "&timeStamp=" + timeStamp + "&round=" + i;
+    //
+    //     const uploadBagUrl = "http://127.0.0.1:8888/simulation/upload/bag?equipmentNo=" + equipmentNo + "&sceneNo=" + sceneNo +
+    //         "&timeStamp=" + timeStamp + "&round=" + i;
+    //
+    //     try {
+    //         // 读取json文件
+    //         const jsonData = fs.readFileSync(jsonFilePath, "utf-8");
+    //         const parsedData = JSON.parse(jsonData);
+    //         console.log("parsedData", parsedData);
+    //         // 上传pdf文件
+    //         // 查找pdf文件是否存在
+    //         let pdfFileExists = fs.existsSync(pdfFilePath)
+    //         // pdf文件不存在
+    //         if (!pdfFileExists) break
+    //         // pdf文件存在
+    //         const uploadPdfResult = await uploadFileWithRetry(pdfFilePath, uploadPdfUrl);
+    //         console.log("uploadPdfResult", uploadPdfResult);
+    //         if (!uploadPdfResult.status) {
+    //             break
+    //         }
+    //
+    //         // 上传bag文件
+    //         // 查找bag文件是否存在
+    //         let bagFileExists = fs.existsSync(bagFilePath)
+    //         // bag文件不存在
+    //         if (!bagFileExists) break
+    //         // bag文件存在
+    //         const uploadBagResult = await uploadFile(bagFilePath, uploadBagUrl);
+    //         console.log("uploadBagResult", uploadBagResult);
+    //         if (!uploadBagResult.status) { break}
+    //         // 整合结果
+    //         result.push({
+    //             "round": i,
+    //             "jsonData": parsedData,
+    //             "uploadPdfKey": uploadPdfResult.details,
+    //             "uploadBagKey": uploadBagResult.details,
+    //             "timeStamp": timeStamp
+    //         })
+    //     } catch (error) {
+    //         console.log("error", error);
+    //         return { success: false, message: "Error uploading evaluation results", data: [] }
+    //     }
+    // }
+    // // 判断数据上传是否完整
+    // if (result.length === N) {
+    //     return { success: true, message: "Evaluation results uploaded successfully", data: result }
+    // } else {
+    //     return { success: false, message: "Error uploading evaluation results", data: [] }
+    // }
 })

+ 8 - 0
electron/preload.js

@@ -30,6 +30,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
         ipcRenderer.send('docker-import', filePath, tag);
     },
     onDockerImportResponse: (callback) => ipcRenderer.once('docker-import-response', callback),
+    updateMap: async (container_name, file_path) => {
+        // 异步
+        ipcRenderer.send('update-map', {container_name, file_path});
+    },
+    onUpdateMapResponse: (callback) => ipcRenderer.once('update-map-response', callback),
     runSimulation: async (random_flag, count, obstacle_flag, default_start_flag, default_end_flag, start_point, end_point) => {
         // 异步
         ipcRenderer.send('run-simulation', {random_flag, count, obstacle_flag, default_start_flag, default_end_flag, start_point, end_point});
@@ -48,6 +53,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
     processEvaluationFiles: async (N, equipmentNo, sceneNo) => {
         return await ipcRenderer.invoke('process-evaluation-files', {N, equipmentNo, sceneNo});
     },
+    processMapUpdateFiles: async (equipmentNo, timeStamp) => {
+        return await ipcRenderer.invoke('process-map-update-files', {equipmentNo, timeStamp});
+    },
 });
 
 

+ 5 - 5
src/views/AboutView.vue

@@ -165,8 +165,8 @@
         </template>
       </el-dialog>
 
-<!--      <el-button style="margin-left: 10px;" type="primary" @click="goToMain">更换设置并执行</el-button> :disabled="evalResult.length === 0" -->
-      <el-button style="margin-left: 10px;" type="primary" @click="showEvalResult" >算法评价结果</el-button>
+<!--      <el-button style="margin-left: 10px;" type="primary" @click="goToMain">更换设置并执行</el-button>  -->
+      <el-button style="margin-left: 10px;" type="primary" @click="showEvalResult" :disabled="evalResult.length === 0">算法评价结果</el-button>
     </el-form-item>
 <!--    <el-form-item label="            ">-->
 <!--      <el-button type="primary" @click="goToAlgorithmEval">算法评价结果</el-button>-->
@@ -223,8 +223,8 @@ console.log("worldPath", worldPath)
 const selectLevel = ref("")
 const algoLevels = ['较差', '一般', '良好', '优秀']
 
-const testTime = ref("1726113464184")
-// const testTime = ref("")
+// const testTime = ref("1726113464184")
+const testTime = ref("")
 
 const resetEvalTableData = ref([])
 
@@ -337,7 +337,7 @@ const showEvalResult = async (value: string) => {
       return
     }
     // 解析结果
-    evalTableData.value = JSON.parse(response.data.details)
+    evalTableData.value = JSON.parse(response.data.data)
     resetEvalTableData.value = evalTableData.value // for reset purpose
     await nextTick() // 避免vue warning: onMounted is called when there is no active component instance...
     // 开启弹窗

+ 15 - 9
src/views/MapRescanView.vue

@@ -23,7 +23,7 @@
             <el-form-item label="设备类型">
               <el-input v-model="queryLine.equipmentTypeName" placeholder="请输入设备类型" clearable/>
             </el-form-item>
-            <el-form-item label="更新阈值设置" label-width="150">
+            <el-form-item label="更新阈值设置" label-width="100">
               <el-input v-model="queryLine.threshold" min="0" max="100" step="1" style="width: 65px">
                 <template #suffix>
                   <i slot="suffix" style="color: #181818">%</i>
@@ -38,14 +38,20 @@
 <!--                  style="width: 100px"-->
 <!--              />-->
             </el-form-item>
-            <div style="float: right">
-              <el-form-item>
-                <el-button type="danger" @click="onSubmit">查询</el-button>
-              </el-form-item>
-              <el-form-item>
-                <el-button type="danger" @click="onSubmit">重置</el-button>
-              </el-form-item>
-            </div>
+            <el-form-item>
+              <el-button type="danger" @click="onSubmit">查询</el-button>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="danger" @click="onSubmit">重置</el-button>
+            </el-form-item>
+<!--            <div style="float: right">-->
+<!--              <el-form-item>-->
+<!--                <el-button type="danger" @click="onSubmit">查询</el-button>-->
+<!--              </el-form-item>-->
+<!--              <el-form-item>-->
+<!--                <el-button type="danger" @click="onSubmit">重置</el-button>-->
+<!--              </el-form-item>-->
+<!--            </div>-->
           </el-form>
         </div>
         <el-table stripe style="background-color: rgba(255,0,0,99%);width: 100%" border :data="tableData"

+ 106 - 11
src/views/ReportView.vue

@@ -41,9 +41,11 @@
           <el-button type="primary" @click="goToUpdateStat">地图更新统计</el-button>
           <el-button type="primary" @click="mapDialogVisible = true">地图续扫提醒阈值</el-button>
           <el-button type="primary" @click="goToMapRescan">地图续扫提醒</el-button>
+<!--          <el-button type="primary" @click="goToMapUpdate">地图更新</el-button>-->
 
           <el-dialog
               v-model="updateDialogVisible"
+              v-if="updateDialogVisible"
               title="地图更新"
               width="400"
               :before-close="handleClose"
@@ -55,7 +57,7 @@
             </el-steps>
 
             <template #footer>
-              <el-button @click="goToMapUpdate" :disabled="update_active !== 2">去部署</el-button>
+              <el-button @click="goToMapUpdate" :disabled="update_active !== 2">上传地图</el-button>
             </template>
           </el-dialog>
 
@@ -134,6 +136,7 @@
 
         <el-dialog
             v-model="worldDialogVisible"
+            v-if="worldDialogVisible"
             title="生成world"
             width="400"
             :before-close="handleWorldClose"
@@ -167,6 +170,7 @@
 
         <el-dialog
             v-model="simulationDialogVisible"
+            v-if="simulationDialogVisible"
             title="启动仿真测试环境"
             width="400"
             :before-close="handleSimulationClose"
@@ -180,6 +184,7 @@
             <el-button @click="goToDetail" :disabled="simulation_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"/>
@@ -284,6 +289,10 @@ const goToTestRecord = () => {
   router.push('/test_record')
 }
 
+const goToPgmViewer = () => {
+  router.push('/pgm_viewer')
+}
+
 const handleClose = (done: () => void) => {
   done()
 }
@@ -453,28 +462,47 @@ const updateMap = async () => {
     return
   }
   // 检查记录的mapBuf是否一致
-  const ids = multipleSelection.value.map(item => item["id"])
+  let ids = multipleSelection.value.map(item => item["id"])
   console.log("ids:",ids)
   const status = checkMapbufConsistency(ids)
   if(!status) { // mapBuf不一致
     ElMessage.error("所选择的记录mapBuf不一致,请重新选择!")
     return
   }
+
+  // 准备数据
+  const currentRow = multipleSelection.value[0]
+  const device_id = currentRow.equipmentId
+  const device_no = currentRow.equipmentNo
+  const device_name = currentRow.equipmentName
+  const device_type = currentRow.equipmentTypeName
+  const updateTime = Date.now()
+  const updateFlag = 0
+
+  console.log(device_id, device_no, device_name, device_type, device_no, updateTime, updateFlag)
+
   // 开启对话框
   updateDialogVisible.value = true
   await nextTick()
 
+  // 保证相同场景id列表下载压缩包文件名一致
+  ids = ids.sort()
+
   // 根据id下载地图更新需要的数据(压缩包)
-  const id = ids[0]
-  const url = "http://localhost:8888/map/download/zip?id=" + id // 此处url不受配置的代理规则影响,应传递后端完整url地址
-  const fileName = "data-" + id + ".zip"
-  const savePath = "/home/cicv/work/pji_desktop/tmp_download/map_zip"
+  const idList = ids.reduce((acc, id) => {return acc + "+" + id}, "")
+  const url = "http://localhost:8888/map/download/zip?id=" + ids.flat() // 此处url不受配置的代理规则影响,应传递后端完整url地址
+
+  const fileName = "data" + idList + ".zip"
+  const savePath = "/home/cicv/work/pji_desktop/tmp_download/map_zip/"
+  const filePath = savePath + fileName
+  const containerName = " map_update_20240923"
 
   // 开启loading
-  const loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog'})
+  let loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: '依赖数据拉取中...'})
   const result = await window.electronAPI.downloadFile(url, fileName, savePath, false, false, "get", {});
   if (!result.success) { // 下载失败
     console.error('File download failed:', result.error);
+    loadingInstance.close()
     ElMessage.error("地图更新数据拉取失败!");
   } else { // 下载成功
     console.log('File downloaded successfully:', result.filePath);
@@ -482,6 +510,65 @@ const updateMap = async () => {
     loadingInstance.close()
     // 更新步骤条状态
     update_active.value = 1
+    console.log("Starting update map...")
+    // 执行脚本 - 生成world,启动gazebo
+    window.electronAPI.updateMap(containerName, filePath);
+    // 开启loading
+    loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: '地图更新中...'})
+    // 监听脚本执行状态
+    window.electronAPI.onUpdateMapResponse( async (event, result) => {
+      if (result.success) { // 脚本执行成功
+        console.log('Script execution completed successfully.')
+        // 关闭loading
+        loadingInstance.close()
+        // 更新步骤条状态
+        update_active.value = 2
+        // // 使用 Electron 进行文件删除操作
+        // window.electronAPI.deleteFile(fileName, savePath)
+        // // 监听删除文件的响应
+        // window.electronAPI.onDeleteFileResponse((event, response) => {
+        //   if (response.success) { // 删除成功
+        //     console.log("File deleted successfully.")
+        //   } else { // 删除失败
+        //     console.log(`Error: ${response.message}`)
+        //   }
+        // })
+
+        const res = await window.electronAPI.processMapUpdateFiles();
+        console.log("res", res)
+        if (res.success) {
+          let data = res.data
+          // 拼接待上传数据
+          let map_update_data = {
+            "map_id": data["jsonData"]["origin_pgm_id"],
+            "device_id": device_id,
+            "device_sn": device_no,
+            "device_name": device_name,
+            "device_type": device_type,
+            "pre_pgm_url": data["prePgmUrl"],
+            "pre_png_url": data["prePngUrl"],
+            "current_pgm_url": data["updatePgmUrl"],
+            "current_png_url": data["updatePngUrl"],
+            "update_rate": data["jsonData"]["update_perecent"],
+            "cumulative_update_rate": data["jsonData"]["origin_update_perecent"],
+            "update_time": String(updateTime),
+            "from_scene_list": "1, 2",
+            "update_flag": updateFlag
+          }
+          console.log("map_update_data", map_update_data)
+          // 上传数据
+          let response = await axios.post('/local/map/add/record', map_update_data)
+          console.log("res", response)
+        } else {
+          ElMessage.error("地图更新数据保存失败!");
+          loadingInstance.close()
+        }
+      } else { // 脚本执行过程中发生错误
+        console.error('Script execution failed.');
+        loadingInstance.close()
+        ElMessage.error("地图更新发生错误!");
+      }
+    })
   }
 }
 
@@ -527,13 +614,18 @@ const generateWorld = async (row) => {
   console.log("Downloading file: map.bag...")
   // 开启对话框
   worldDialogVisible.value = true
-
+  // 开启loading
+  let loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: "依赖数据拉取中..."})
   // 下载map.bag
   const result = await window.electronAPI.downloadFile(url, fileName, savePath, false, false, "get", {});
   if (!result.success) { // 下载失败
     console.error('File download failed:', result.error);
+    // 关闭loading
+    loadingInstance.close()
     ElMessage.error("地图bag数据拉取失败!");
   } else { // 下载成功
+    // 关闭loading
+    loadingInstance.close()
     console.log('File downloaded successfully:', result.filePath);
     // 更新步骤条状态
     world_active.value = 1
@@ -541,7 +633,7 @@ const generateWorld = async (row) => {
     // 执行脚本 - 生成world,启动gazebo
     window.electronAPI.generateWorld(result.filePath);
     // 开启loading
-    const loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog'})
+    loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: "world文件生成中..."})
     // 监听脚本执行状态
     window.electronAPI.onGenerateWorldResponse( (event, result) => {
       if (result.success) { // 脚本执行成功
@@ -560,6 +652,8 @@ const generateWorld = async (row) => {
         })
       } else { // 脚本执行过程中发生错误
         console.error('Script execution failed.');
+        // 关闭loading
+        loadingInstance.close()
         ElMessage.error("world生成发生错误!");
       }
     })
@@ -607,10 +701,11 @@ const startSimulation = async (row) => {
 
   console.log("Starting download files...")
   // 开启loading
-  let loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog'})
+  let loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: "依赖数据拉取中..."})
   const result = await window.electronAPI.downloadFile(url, fileName, savePath, false, false, "get", {});
   if (!result.success) { // 下载失败
     console.error('File download failed:', result.error);
+    loadingInstance.close()
     ElMessage.error("仿真测试数据拉取失败!");
   } else { // 下载成功
     console.log('File downloaded successfully:', result.filePath);
@@ -620,7 +715,7 @@ const startSimulation = async (row) => {
     // // 延时
     // setTimeout(() => {}, 500)
     // 开启loading
-    loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog'})
+    loadingInstance = ElLoading.service({fullscreen: false, target: '.el-dialog', text: "仿真环境准启动中..."})
     // 执行脚本 - 数据准备,启动容器
     window.electronAPI.startContainer(result.filePath, imageName, containerName);
     // 监听脚本执行状态

+ 0 - 1
src/views/TestRecordView.vue

@@ -26,7 +26,6 @@
                   v-model="queryLine.equipmentType"
                   placeholder="请选择"
                   size="default"
-                  @click.native="getKeywordsByField('device_type')"
                   style="width: 180px; "
                   clearable
               >

+ 137 - 36
src/views/UpdateStatView.vue

@@ -19,37 +19,81 @@
             <el-form-item label="设备名称">
               <el-input v-model="queryLine.equipmentName" placeholder="请输入设备名称" clearable/>
             </el-form-item>
+<!--            <el-form-item label="设备类型">-->
+<!--              <el-input v-model="queryLine.equipmentTypeName" placeholder="请输入设备类型" clearable/>-->
+<!--            </el-form-item>-->
+
             <el-form-item label="设备类型">
-              <el-input v-model="queryLine.equipmentTypeName" placeholder="请输入设备类型" clearable/>
+              <!--              <el-input v-model="queryLine.equipmentType" placeholder="请输入设备类型" clearable/>-->
+              <el-select
+                  v-model="queryLine.equipmentType"
+                  placeholder="请选择"
+                  size="default"
+                  style="width: 180px; "
+                  clearable
+              >
+                <el-option
+                    v-for="item in equipmentTypes"
+                    :key="item"
+                    :label="item"
+                    :value="item"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item >
+              <el-button type="danger" @click="queryRecordByCondition">查询</el-button>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="danger" @click="onSubmit">重置</el-button>
             </el-form-item>
-            <div style="float: right">
-              <el-form-item >
-                <el-button type="danger" @click="onSubmit">查询</el-button>
-              </el-form-item>
-              <el-form-item>
-                <el-button type="danger" @click="onSubmit">重置</el-button>
-              </el-form-item>
-            </div>
+<!--            <div style="float: right">-->
+<!--              <el-form-item >-->
+<!--                <el-button type="danger" @click="onSubmit">查询</el-button>-->
+<!--              </el-form-item>-->
+<!--              <el-form-item>-->
+<!--                <el-button type="danger" @click="onSubmit">重置</el-button>-->
+<!--              </el-form-item>-->
+<!--            </div>-->
 
           </el-form>
         </div>
+
+        <el-image-viewer @close="closeImgViewer" :url-list="imageUrl" v-if="showImageViewer"></el-image-viewer>
         <el-table stripe style="background-color: rgba(255,0,0,99%);width: 100%" border :data="tableData"
                   fixed ref="multipleTableRef" :cell-style="{ textAlign: 'center'}" :header-cell-style="{ textAlign: 'center'}">
           <el-table-column type="selection" width="55"/>
-          <el-table-column prop="equipmentName" label="设备名称"/>
-          <el-table-column prop="equipmentTypeName" label="设备类型"/>
-          <el-table-column prop="mapId" label="地图id"/>
-          <el-table-column prop="originalPgm" label="原始pgm"/>
-          <el-table-column prop="updateTime" label="地图更新时间"/>
-          <el-table-column prop="cumulativeUpdateRate" label="累积地图更新率"/>
-          <el-table-column prop="currentPgm" label="当前pgm"/>
+          <el-table-column prop="device_name" label="设备名称"/>
+          <el-table-column prop="device_type" label="设备类型"/>
+          <el-table-column prop="map_id" label="地图id"/>
+          <el-table-column prop="update_time" label="地图更新时间" :formatter="formatDate"/>
+          <el-table-column prop="update_rate" label="地图更新率"/>
+          <el-table-column prop="cumulative_update_rate" label="累积地图更新率"/>
+          <el-table-column prop="update_flag" label="地图更新状态" :formatter="formatStatus"/>
+          <el-table-column prop="pre_pgm_url" label="原始pgm" width="400px">
+            <template v-slot="scope">
+              <img :src="'http://oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com/pji-bucket1/' + scope.row.pre_png_url" @click="viewImg" alt="" style="width:300px; height: 100%; cursor: pointer">
+            </template>
+
+          </el-table-column>
+          <el-table-column prop="current_pgm_url" label="当前pgm" width="400px">
+            <template v-slot="scope">
+              <img :src="'http://oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com/pji-bucket1/' + scope.row.current_png_url" @click="viewImg" alt="" style="width:300px; height: 100%; cursor: pointer">
+            </template>
+          </el-table-column>
+
+          <el-table-column width="200" fixed="right" label="操作">
+            <template v-slot="scope">
+              <el-button size="small" type="danger" @click="generateWorld(scope.row)" :disabled="scope.row.update_flag!= 0">上传地图</el-button>
+            </template>
+
+          </el-table-column>
         </el-table>
 
         <p></p> <!--空行-->
         <el-pagination
             v-model:current-page="currentPage"
             v-model:page-size="pageSize"
-            :page-sizes="[10]"
+            :page-sizes="[5,10]"
             :small="small"
             :disabled="disabled"
             :background="true"
@@ -68,48 +112,105 @@
 <script lang="ts" setup>
 import {onBeforeMount, reactive, ref} from "vue";
 import axios from "axios";
-import {ElTable} from "element-plus";
+import {ElMessage, ElTable} from "element-plus";
+import moment from "moment/moment";
 
 
 const multipleTableRef = ref<InstanceType<typeof ElTable>>
-
+const showImageViewer = ref(false);
+const imageUrl = ref([])
+const resetTableData = ref([]);
 
 const queryLine = reactive({
   dataName: '',
   equipmentName: '',
   equipmentTypeName: '',
+  equipmentType: '',
 })
+const equipmentTypes =ref(["引导服务机器人"])
 
 const onSubmit = () => {
   page()
 }
 
+// 根据条件筛选结果
+const queryRecordByCondition = async () => {
+  let response = await axios.post('/local/map/query/update/record?page=' + currentPage.value + '&pageSize=' + pageSize.value, {
+    "device_name": queryLine.equipmentName,
+    "device_type": queryLine.equipmentType
+  })
+
+  if (!response.data.status){ // 不存在
+    ElMessage.error("仿真测试记录查询失败!");
+    return
+  }
+  // 解析结果
+  tableData.value = JSON.parse(response.data.data)
+  total.value = response.data.total
+}
+
 let total = ref(0)
 let tableData = ref([]);
 onBeforeMount(() => {
   page()
 })
 
-function page() {
-  axios.get('http://1.202.169.139:8081/open/scene/list?equipmentType=YI_DAO_JI_QI_REN&page=' + currentPage.value + '&size=' + pageSize.value,
-      {
-        headers: {
-          "Authorization": "4773hd92ysj54paflw2jem3onyhywxt2"
-        }
-      }
-  ).then(function (response) {
-    tableData.value = response.data.data.content
-    total.value = response.data.data.totalElements
-    // total.value = tableData.value.length
-    // console.log(tableData);
-    // console.log(response.data.data);
-  }).catch(function (error) {
-    console.log(error);
-  });
+const formatDate =  (row) => {
+  return moment(+row.update_time).format("YYYY-MM-DD HH:mm:ss")
+}
+
+const formatStatus =  (row) => {
+  if (row.update_flag == 0) return "未上传";
+  if (row.update_flag == 1) return "已上传,未部署";
+  if (row.update_flag == 2) return "已部署";
+  return
+}
+
+const viewImg = (event) => {
+  if (event.target.nodeName == "IMG") {
+    let src = event.target.currentSrc;
+    imageUrl.value = [src]
+    showImageViewer.value = true
+  }
+}
+
+const closeImgViewer = () => {
+  showImageViewer.value = false;
+}
+
+async function page() {
+  // axios.get('http://1.202.169.139:8081/open/scene/list?equipmentType=YI_DAO_JI_QI_REN&page=' + currentPage.value + '&size=' + pageSize.value,
+  //     {
+  //       headers: {
+  //         "Authorization": "4773hd92ysj54paflw2jem3onyhywxt2"
+  //       }
+  //     }
+  // ).then(function (response) {
+  //   tableData.value = response.data.data.content
+  //   total.value = response.data.data.totalElements
+  //   // total.value = tableData.value.length
+  //   // console.log(tableData);
+  //   // console.log(response.data.data);
+  // }).catch(function (error) {
+  //   console.log(error);
+  // });
+
+  // 查询算法评价记录
+  let response = await axios.post('/local/map/query/update/record?page=' + currentPage.value + '&pageSize=' + pageSize.value)
+
+  if (!response.data.status){ // 不存在
+    ElMessage.error("地图更新记录查询失败!");
+    return
+  }
+  // 解析结果
+  tableData.value = JSON.parse(response.data.data)
+  console.log("tableData.value", tableData.value)
+  resetTableData.value = tableData.value // for reset purpose
+  total.value = response.data.total
 }
 
 const currentPage = ref(1)
-const pageSize = ref(10)
+const pageSize = ref(5)
 const small = ref(false)
 const disabled = ref(false)