yawuga hace 8 meses
padre
commit
f36ea19cc9

+ 116 - 15
src/components/OlMap/index.vue

@@ -8,11 +8,21 @@
       </span>
     </div>
     <div id="tooltip" class="tooltip">
-      <div id="tooltip-content"></div> <!-- 用于动态内容 -->
-      <el-button style="width: 40%; position: absolute; bottom: 10px; margin: 0;" size="mini"
-        @click="addNowPoint">添加点位</el-button>
-      <el-button style="width: 40%; position: absolute; bottom: 10px; margin: 0; left: 55%;" size="mini"
-        @click="clearNowPoint">取消添加</el-button>
+      <div class="tooltip-header">
+        <i class="el-icon-location"></i>
+        <span class="tooltip-title">添加目标点</span>
+      </div>
+      <div id="tooltip-content" class="tooltip-content"></div>
+      <div class="tooltip-actions">
+        <el-button type="primary" size="small" @click="addNowPoint" class="action-btn">
+          <i class="el-icon-check"></i>
+          添加点位
+        </el-button>
+        <el-button size="small" @click="clearNowPoint" class="action-btn">
+          <i class="el-icon-close"></i>
+          取消添加
+        </el-button>
+      </div>
     </div>
   </div>
 </template>
@@ -447,8 +457,8 @@ export default {
           // 清空动态内容
           tooltipContent.innerHTML = '';
           // 添加新的内容
-          tooltipContent.innerHTML += "<p style='margin-top: 0; margin-bottom: 5px; text-align: center; font-size: 15px'>添加目标点</p>";
-          tooltipContent.innerHTML += `<p style="color: red; text-align: center; margin-bottom: 35px; margin-top: 5px; font-size: 14px">X:  ${xy[0].toFixed(3)}, Y: ${xy[1].toFixed(3)}</p>`;
+          tooltipContent.innerHTML += `<p>确认在此位置添加目标点?</p>`;
+          tooltipContent.innerHTML += `<p>X: ${xy[0].toFixed(3)}, Y: ${xy[1].toFixed(3)}</p>`;
           // 设置 tooltip 的位置和显示
           const tooltip = document.getElementById('tooltip');
           tooltip.style.display = 'block';
@@ -1721,14 +1731,105 @@ export default {
 
 .tooltip {
   position: absolute;
-  background-color: rgba(255, 255, 255, 1);
-  color: rgb(0, 0, 0);
-  padding: 5px;
-  border-radius: 4px;
-  white-space: nowrap;
+  background: white;
+  border-radius: 12px;
   display: none;
-  box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
-  width: 200px;
-  padding: 10px;
+  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
+  width: 240px;
+  overflow: hidden;
+  border: 1px solid #e2e8f0;
+  z-index: 1000;
+  
+  .tooltip-header {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    color: white;
+    padding: 12px 16px;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    
+    .tooltip-title {
+      font-size: 14px;
+      font-weight: 600;
+      margin: 0;
+    }
+    
+    i {
+      font-size: 16px;
+    }
+  }
+  
+  .tooltip-content {
+    padding: 16px;
+    background: #f8fafc;
+    
+    p {
+      margin: 0;
+      padding: 8px 12px;
+      background: white;
+      border-radius: 6px;
+      border: 1px solid #e2e8f0;
+      text-align: center;
+      
+      &:first-child {
+        font-size: 13px;
+        color: #4a5568;
+        margin-bottom: 8px;
+      }
+      
+      &:last-child {
+        font-family: 'Courier New', monospace;
+        color: #e53e3e;
+        font-weight: 600;
+        font-size: 14px;
+        background: #fff5f5;
+        border-color: #fed7d7;
+      }
+    }
+  }
+  
+  .tooltip-actions {
+    padding: 12px 16px;
+    background: white;
+    display: flex;
+    gap: 8px;
+    border-top: 1px solid #e2e8f0;
+    
+    .action-btn {
+      flex: 1;
+      border-radius: 6px;
+      font-weight: 500;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+      
+      &.el-button--primary {
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+        border: none;
+        
+        &:hover {
+          opacity: 0.9;
+          transform: translateY(-1px);
+        }
+      }
+      
+      &:not(.el-button--primary) {
+        background: #f7fafc;
+        border: 1px solid #e2e8f0;
+        color: #4a5568;
+        
+        &:hover {
+          background: #edf2f7;
+          border-color: #cbd5e0;
+          transform: translateY(-1px);
+        }
+      }
+      
+      i {
+        font-size: 12px;
+      }
+    }
+  }
 }
 </style>

+ 3 - 3
src/router/index.js

@@ -172,7 +172,7 @@ export const dynamicRoutes = [
       {
         path: 'index/:mapId(\\d+)',
         component: () => import('@/views/map/maplist/navigation'),
-        name: 'Navigation',
+        name: 'MapNavigation',
         meta: { title: '地图导航', activeMenu: '/map/maplist' }
       }
     ]
@@ -187,7 +187,7 @@ export const dynamicRoutes = [
       {
         path: 'index/:mapId(\\d+)',
         component: () => import('@/views/map/maplist/edit'),
-        name: 'Edit',
+        name: 'MapEdit',
         meta: { title: '地图编辑', activeMenu: '/map/maplist' }
       }
     ]
@@ -202,7 +202,7 @@ export const dynamicRoutes = [
       {
         path: 'index/:mapId(\\d+)',
         component: () => import('@/views/map/maplist/calibration'),
-        name: 'Calibration',
+        name: 'MapCalibration',
         meta: { title: '坐标系标定', activeMenu: '/map/maplist' }
       }
     ]

+ 1 - 1
src/styles/overrides-element.scss

@@ -683,7 +683,7 @@
   &__content {
     background: var(--color-bg-card);
     color: var(--color-text-primary);
-    padding: var(--spacing-6);
+    // padding: var(--spacing-6);  // 保持注释(不要启用)
   }
 
   /* 卡片式标签页 */

+ 229 - 0
src/utils/map-operations.js

@@ -0,0 +1,229 @@
+/**
+ * 地图操作工具类
+ * 提供通用的地图操作方法,供导航页和标定页共同使用
+ */
+
+export class MapOperations {
+  constructor(mapRef) {
+    this.mapRef = mapRef
+  }
+
+  /**
+   * 放大地图
+   */
+  zoomIn() {
+    if (this.mapRef && this.mapRef.zoomIn) {
+      this.mapRef.zoomIn()
+      return true
+    }
+    return false
+  }
+
+  /**
+   * 缩小地图
+   */
+  zoomOut() {
+    if (this.mapRef && this.mapRef.zoomOut) {
+      this.mapRef.zoomOut()
+      return true
+    }
+    return false
+  }
+
+  /**
+   * 居中到机器人位置
+   * @param {Object} robotPosition - 机器人位置信息 {x, y} 或 经纬度
+   */
+  centerToRobot(robotPosition = null) {
+    if (!this.mapRef) {
+      return false
+    }
+
+    // 如果传入了位置参数,使用传入的位置
+    if (robotPosition && (robotPosition.x !== undefined || robotPosition.lng !== undefined)) {
+      if (this.mapRef.centerToPosition) {
+        this.mapRef.centerToPosition(robotPosition)
+        return true
+      }
+    }
+
+    // 否则尝试调用地图组件的centerToRobot方法
+    if (this.mapRef.centerToRobot) {
+      this.mapRef.centerToRobot()
+      return true
+    }
+
+    return false
+  }
+
+  /**
+   * 适配地图到画布
+   */
+  fitToCanvas() {
+    if (this.mapRef && this.mapRef.fitToCanvas) {
+      this.mapRef.fitToCanvas()
+      return true
+    }
+    return false
+  }
+
+  /**
+   * 更新地图尺寸
+   */
+  updateSize() {
+    if (this.mapRef && this.mapRef.updateSize) {
+      this.mapRef.updateSize()
+      return true
+    }
+    return false
+  }
+
+  /**
+   * 检查地图是否已就绪
+   */
+  isMapReady() {
+    return !!(this.mapRef && this.mapRef.getMap)
+  }
+
+  /**
+   * 获取地图实例
+   */
+  getMapInstance() {
+    if (this.mapRef && this.mapRef.getMap) {
+      return this.mapRef.getMap()
+    }
+    return null
+  }
+}
+
+/**
+ * 全屏操作工具类
+ */
+export class FullscreenOperations {
+  /**
+   * 切换全屏状态
+   * @param {HTMLElement} element - 要全屏的元素
+   * @param {Function} onStateChange - 状态变化回调
+   */
+  static toggleFullscreen(element, onStateChange = null) {
+    if (!element) return false
+
+    const isCurrentlyFullscreen = !!(
+      document.fullscreenElement || 
+      document.webkitFullscreenElement || 
+      document.mozFullScreenElement
+    )
+
+    if (!isCurrentlyFullscreen) {
+      // 进入全屏
+      const requestFullscreen = element.requestFullscreen || 
+        element.webkitRequestFullscreen || 
+        element.mozRequestFullScreen
+
+      if (requestFullscreen) {
+        requestFullscreen.call(element)
+        return true
+      }
+    } else {
+      // 退出全屏
+      const exitFullscreen = document.exitFullscreen || 
+        document.webkitExitFullscreen || 
+        document.mozCancelFullScreen
+
+      if (exitFullscreen) {
+        exitFullscreen.call(document)
+        return true
+      }
+    }
+
+    return false
+  }
+
+  /**
+   * 添加全屏状态监听器
+   * @param {Function} callback - 状态变化回调
+   */
+  static addFullscreenListener(callback) {
+    const events = ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange']
+    const handler = () => {
+      const isFullscreen = !!(
+        document.fullscreenElement || 
+        document.webkitFullscreenElement || 
+        document.mozFullScreenElement
+      )
+      callback(isFullscreen)
+    }
+
+    events.forEach(event => {
+      document.addEventListener(event, handler)
+    })
+
+    // 返回清理函数
+    return () => {
+      events.forEach(event => {
+        document.removeEventListener(event, handler)
+      })
+    }
+  }
+}
+
+/**
+ * 机器人位置工具类
+ */
+export class RobotPositionUtils {
+  /**
+   * 解析坐标字符串
+   * @param {String} coordinates - 坐标字符串,如 "(1.813, -63.931, 0.000)"
+   * @returns {Object|null} - {x, y, z} 或 null
+   */
+  static parseCoordinates(coordinates) {
+    if (!coordinates || typeof coordinates !== 'string') {
+      return null
+    }
+
+    // 匹配形如 "(x, y, z)" 的字符串
+    const match = coordinates.match(/\(([^,]+),\s*([^,]+),\s*([^)]+)\)/)
+    if (!match) {
+      return null
+    }
+
+    const x = parseFloat(match[1])
+    const y = parseFloat(match[2])
+    const z = parseFloat(match[3])
+
+    if (isNaN(x) || isNaN(y) || isNaN(z)) {
+      return null
+    }
+
+    return { x, y, z }
+  }
+
+  /**
+   * 检查机器人位置是否有效
+   * @param {Object} position - 位置对象
+   * @returns {Boolean}
+   */
+  static isValidPosition(position) {
+    if (!position) return false
+    
+    // 检查是否为零点或无效值
+    if (position.x === 0 && position.y === 0) return false
+    if (isNaN(position.x) || isNaN(position.y)) return false
+    
+    return true
+  }
+
+  /**
+   * 从实时信息中获取机器人位置
+   * @param {Object} realtimeInfo - 实时信息对象
+   * @returns {Object|null}
+   */
+  static getRobotPosition(realtimeInfo) {
+    if (!realtimeInfo || !realtimeInfo.coordinates) {
+      return null
+    }
+
+    const position = this.parseCoordinates(realtimeInfo.coordinates)
+    return this.isValidPosition(position) ? position : null
+  }
+}

+ 6 - 6
src/utils/route-helpers.js

@@ -10,32 +10,32 @@ export function pickName(row) {
 
 // === 根据真实路由配置构造跳转对象 ===
 
-// Nav route: name: 'Navigation', path: '/map/maplist/navigation/index/:mapId(\\d+)', params: { mapId }
+// Nav route: name: 'MapNavigation', path: '/map/maplist/navigation/index/:mapId(\\d+)', params: { mapId }
 export function buildNavTo(row) {
   const id = pickId(row);
   const mapName = pickName(row);
   console.log("路由跳转mapName:", mapName);
   return { 
-    name: 'Navigation', 
+    name: 'MapNavigation', 
     params: { mapId: id, mapName:mapName } 
   };
 }
 
-// Edit route: name: 'Edit', path: '/map/maplist/edit/index/:mapId(\\d+)', params: { mapId }
+// Edit route: name: 'MapEdit', path: '/map/maplist/edit/index/:mapId(\\d+)', params: { mapId }
 export function buildEditTo(row) {
   const id = pickId(row);
   return { 
-    name: 'Edit', 
+    name: 'MapEdit', 
     params: { mapId: id } 
   };
 }
 
-// Calibration route: name: 'Calibration', path: '/map/maplist/calibration/index/:mapId(\\d+)', params: { mapId }
+// Calibration route: name: 'MapCalibration', path: '/map/maplist/calibration/index/:mapId(\\d+)', params: { mapId }
 export function buildCalibrateTo(row) {
   const id = pickId(row);
   const mapName = pickName(row);
   return { 
-    name: 'Calibration', 
+    name: 'MapCalibration', 
     params: { mapId: id , mapName:mapName} 
   };
 }

+ 40 - 48
src/views/map/maplist/calibration.vue

@@ -19,12 +19,15 @@
       <!-- 地图工具条 -->
       <MapToolbar 
         class="map-toolbar"
-        :canAddCalibration="canAddCalibration"
-        :hasRobotPosition="hasRobotPosition"
+        preset="calibration"
+        :canAddCalibration="true"
+        :hasRobotPosition="true"
         :isFullscreen="isFullscreen"
+        :isConnected="true"
+        :isBusy="false"
         @zoom-in="handleZoomIn"
         @zoom-out="handleZoomOut"
-        @center-to-robot="handleCenterToRobot"
+        @center-robot="handleCenterToRobot"
         @toggle-fullscreen="handleToggleFullscreen"
         @add-calibration-point="addCalibration"
       />
@@ -32,31 +35,24 @@
       <!-- 右侧信息面板 (宽屏模式,浮层) -->
       <RightPanel 
         v-if="!isMobileMode"
+        mode="calib"
         class="right-panel"
-        :class="{ 'panel-collapsed': isPanelCollapsed }"
-        :style="{ width: isPanelCollapsed ? '0px' : rightPanelWidth + 'px' }"
+        v-model="isPanelVisible"
+        :width="rightPanelWidth"
+        :title="'实时标定信息'"
+        :subtitle="`(当前地图: ${currentMap.name})`"
         :laserPositionData="laserPositionData"
         :gnssPositionData="gnssPositionData"
         :calibrationList="calibrationList"
         :currentMap="currentMap"
         :panelWidth="rightPanelWidth"
         :mapName="mapName"
-        @panel-toggle="handlePanelToggle"
         @panel-resize="handlePanelResize"
         @add-calibration="addCalibration"
         @remove-calibration="removeCalibration"
         @execute-calibration="executeCalibration"
       />
 
-      <!-- 面板展开按钮 (面板收起时显示) -->
-      <div 
-        class="panel-reopen-btn" 
-        v-if="shouldShowExpandButton"
-        @click="expandPanel"
-        title="展开面板"
-      >
-        <i class="el-icon-arrow-left"></i>
-      </div>
 
       <!-- 右上角信息按钮 (窄屏模式) -->
       <div class="info-toggle-btn" v-if="isMobileMode" @click="showInfoDrawer">
@@ -109,12 +105,12 @@
 
 <script>
 import OlMap from "@/components/OlMap";
-import RightPanel from "./components/RightPanel.vue";
-import MapToolbar from "./components/MapToolbar.vue";
 import MqttComp from "@/components/Mqtt/mqttComp.vue";
+import { RightPanel, MapToolbar } from "./components/shared";
+import { MapOperations, FullscreenOperations } from "@/utils/map-operations";
 
 export default {
-  name: "Calibration",
+  name: "CalibrationPage",
   components: {
     OlMap,
     RightPanel,
@@ -151,7 +147,7 @@ export default {
       
       // 布局相关状态
       rightPanelWidth: 360, // 右侧面板宽度
-      isPanelCollapsed: false, // 面板是否折叠
+      isPanelVisible: true, // 面板是否可见 (v-model)
       windowWidth: window.innerWidth, // 窗口宽度
       drawerVisible: false, // 抽屉是否可见
       isFullscreen: false, // 是否全屏状态
@@ -175,10 +171,6 @@ export default {
       return this.laserPositionData.x !== 0 || this.laserPositionData.y !== 0;
     },
     
-    // 是否显示展开按钮
-    shouldShowExpandButton() {
-      return !this.isMobileMode && this.isPanelCollapsed;
-    }
   },
   created() {
     // 从 localStorage 恢复状态
@@ -189,7 +181,7 @@ export default {
       this.rightPanelWidth = Math.max(320, Math.min(420, parseInt(savedPanelWidth)));
     }
     if (savedPanelCollapsed) {
-      this.isPanelCollapsed = savedPanelCollapsed === 'true';
+      this.isPanelVisible = savedPanelCollapsed !== 'true'; // 注意逻辑反转
     }
   },
   mounted() {
@@ -276,40 +268,27 @@ export default {
     // 更新右侧面板宽度
     updateRightPanelWidth() {
       if (this.isMobileMode) {
-        this.rightPanelWidth = 0;
+        // 移动模式下隐藏面板,使用抽屉
+        this.isPanelVisible = false;
       } else {
         const savedWidth = localStorage.getItem('calibration-panel-width');
         const savedCollapsed = localStorage.getItem('calibration-panel-collapsed');
         
         if (savedCollapsed === 'true') {
-          this.isPanelCollapsed = true;
+          this.isPanelVisible = false;
           this.rightPanelWidth = 360; // 保持原宽度,但面板是折叠状态
         } else if (savedWidth) {
           this.rightPanelWidth = Math.max(320, Math.min(420, parseInt(savedWidth)));
-          this.isPanelCollapsed = false;
+          this.isPanelVisible = true;
         } else {
           this.rightPanelWidth = 360;
-          this.isPanelCollapsed = false;
+          this.isPanelVisible = true;
         }
       }
       
       this.updateOlCss();
     },
     
-    // 处理面板切换
-    handlePanelToggle(isCollapsed) {
-      this.isPanelCollapsed = isCollapsed;
-      localStorage.setItem('calibration-panel-collapsed', String(isCollapsed));
-      // 面板宽度不变,只是改变显示状态
-      this.updateOlCss();
-    },
-    
-    // 展开面板
-    expandPanel() {
-      this.isPanelCollapsed = false;
-      localStorage.setItem('calibration-panel-collapsed', 'false');
-      this.updateOlCss();
-    },
     
     // 处理面板调整大小
     handlePanelResize(newWidth) {
@@ -372,17 +351,22 @@ export default {
     
     handleCenterToRobot() {
       try {
-        if (!this.hasRobotPosition) {
-          this.$message.warning('暂无机器人定位数据');
-          return;
-        }
+        // 移除位置检查限制,允许直接操作
         
         const map = this.getMapInstance();
         if (map) {
           // OpenLayers API
           const view = map.getView();
+          
+          // 如果有真实位置数据则使用,否则使用地图中心点
+          let centerPoint = [this.laserPositionData.x, this.laserPositionData.y];
+          if (this.laserPositionData.x === 0 && this.laserPositionData.y === 0) {
+            // 使用当前地图中心点作为默认位置
+            centerPoint = view.getCenter();
+          }
+          
           view.animate({
-            center: [this.laserPositionData.x, this.laserPositionData.y],
+            center: centerPoint,
             zoom: Math.max(view.getZoom(), 15),
             duration: 500
           });
@@ -513,6 +497,14 @@ removeCalibration(id) {
       this.$nextTick(() => {
         this.updateOlCss();
       });
+    },
+    
+    // 监听面板可见性变化
+    isPanelVisible(newVal) {
+      localStorage.setItem('calibration-panel-collapsed', String(!newVal));
+      this.$nextTick(() => {
+        this.updateOlCss();
+      });
     }
   }
 };
@@ -549,7 +541,7 @@ removeCalibration(id) {
       position: absolute;
       left: 16px;
       top: 16px;
-      z-index: 11;
+      z-index: 50;
       pointer-events: auto;
     }
 

+ 0 - 294
src/views/map/maplist/components/MapToolbar.vue

@@ -1,294 +0,0 @@
-<template>
-  <div class="map-toolbar">
-    <!-- 地图控制按钮组 -->
-    <el-tooltip content="放大" placement="right">
-      <el-button 
-        size="small" 
-        icon="el-icon-plus" 
-        circle
-        @click="zoomIn"
-        class="toolbar-btn"
-      />
-    </el-tooltip>
-    
-    <el-tooltip content="缩小" placement="right">
-      <el-button 
-        size="small" 
-        icon="el-icon-minus" 
-        circle
-        @click="zoomOut"
-        class="toolbar-btn"
-      />
-    </el-tooltip>
-    
-    <!-- <el-tooltip content="居中到机器人" placement="right">
-      <el-button 
-        size="small" 
-        icon="el-icon-location" 
-        circle
-        @click="centerToRobot"
-        :disabled="!hasRobotPosition"
-        class="toolbar-btn"
-      />
-    </el-tooltip> -->
-    
-    <el-tooltip :content="isFullscreen ? '退出全屏' : '全屏'" placement="right">
-      <el-button 
-        size="small" 
-        :icon="isFullscreen ? 'el-icon-aim' : 'el-icon-full-screen'"
-        circle
-        @click="toggleFullscreen"
-        class="toolbar-btn"
-      />
-    </el-tooltip>
-
-    <!-- 分割线 -->
-    <div class="toolbar-divider"></div>
-
-    <!-- 主要操作按钮 -->
-    <el-tooltip content="添加标定点" placement="right">
-      <el-button 
-        type="primary"
-        size="small" 
-        icon="el-icon-circle-plus"
-        circle
-        @click="addCalibrationPoint"
-        class="toolbar-btn primary-btn"
-        :disabled="!canAddCalibration"
-      />
-    </el-tooltip>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'MapToolbar',
-  props: {
-    canAddCalibration: {
-      type: Boolean,
-      default: true
-    },
-    hasRobotPosition: {
-      type: Boolean,
-      default: false
-    },
-    isFullscreen: {
-      type: Boolean,
-      default: false
-    },
-    showAdvanced: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {
-      measureToolActive: false
-    }
-  },
-  methods: {
-    zoomIn() {
-      this.$emit('zoom-in')
-    },
-    
-    zoomOut() {
-      this.$emit('zoom-out')
-    },
-    
-    centerToRobot() {
-      if (!this.hasRobotPosition) {
-        return
-      }
-      this.$emit('center-to-robot')
-    },
-    
-    toggleFullscreen() {
-      this.$emit('toggle-fullscreen')
-    },
-    
-    addCalibrationPoint() {
-      this.$emit('add-calibration-point')
-    },
-    
-    resetView() {
-      this.$emit('reset-view')
-      this.showToast('视图已重置')
-    },
-    
-    toggleMeasureTool() {
-      this.measureToolActive = !this.measureToolActive
-      this.$emit('toggle-measure-tool', this.measureToolActive)
-      this.showToast(this.measureToolActive ? '测量工具已启用' : '测量工具已关闭')
-    },
-    
-    showToast(message) {
-      // 简单的提示信息,避免过多弹窗
-      console.log('地图操作:', message)
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.map-toolbar {
-  /* 位置由父组件控制 */
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 8px; /* 固定间距确保一致性 */
-  background: var(--color-bg-card);
-  border-radius: var(--radius-lg);
-  box-shadow: var(--shadow-lg);
-  padding: 12px; /* 统一内边距 */
-  border: 1px solid var(--color-border-primary);
-  backdrop-filter: blur(8px);
-  pointer-events: auto;
-  width: 60px; /* 固定宽度确保对齐 */
-
-  .toolbar-btn {
-    width: 36px !important;
-    height: 36px !important;
-    min-width: 36px !important;
-    min-height: 36px !important;
-    border-radius: 50% !important;
-    border: 1px solid var(--color-border-secondary);
-    background: var(--color-bg-card);
-    color: var(--color-text-secondary);
-    transition: all var(--duration-200) var(--ease-out);
-    display: flex !important;
-    align-items: center !important;
-    justify-content: center !important;
-    padding: 0 !important;
-    margin: 0 !important;
-    flex-shrink: 0;
-
-    &:hover {
-      background: var(--color-bg-tertiary);
-      color: var(--color-text-primary);
-      border-color: var(--color-border-primary);
-      transform: translateY(-1px);
-      box-shadow: var(--shadow-md);
-    }
-
-    &:active {
-      transform: translateY(0);
-      box-shadow: var(--shadow-sm);
-    }
-
-    &.primary-btn {
-      background: var(--color-primary) !important;
-      color: var(--color-text-inverse) !important;
-      border-color: var(--color-primary) !important;
-
-      &:hover {
-        background: var(--color-primary-light) !important;
-        border-color: var(--color-primary-light) !important;
-      }
-
-      &:disabled {
-        background: var(--color-text-quaternary) !important;
-        border-color: var(--color-text-quaternary) !important;
-        color: var(--color-text-inverse) !important;
-        opacity: 0.6;
-        cursor: not-allowed;
-        transform: none;
-        box-shadow: none;
-      }
-    }
-
-    &.active {
-      background: var(--color-primary);
-      color: var(--color-text-inverse);
-      border-color: var(--color-primary);
-    }
-
-    &:disabled {
-      opacity: 0.5;
-      cursor: not-allowed;
-      transform: none;
-      
-      &:hover {
-        background: var(--color-bg-card);
-        color: var(--color-text-secondary);
-        border-color: var(--color-border-secondary);
-        transform: none;
-        box-shadow: none;
-      }
-    }
-
-    ::v-deep .el-icon {
-      font-size: var(--font-size-base) !important;
-      line-height: 1 !important;
-    }
-
-    ::v-deep i {
-      font-size: var(--font-size-base) !important;
-      line-height: 1 !important;
-    }
-  }
-
-  .toolbar-divider {
-    width: 24px;
-    height: 1px;
-    background: var(--color-border-secondary);
-    margin: 4px 0;
-    flex-shrink: 0;
-  }
-}
-
-// 暗色主题适配
-html.dark {
-  .map-toolbar {
-    background: rgba(31, 41, 55, 0.9);
-    border-color: var(--color-border-tertiary);
-
-    .toolbar-group {
-      .toolbar-btn {
-        background: var(--color-bg-tertiary);
-        border-color: var(--color-border-tertiary);
-
-        &:hover {
-          background: var(--color-bg-quaternary);
-          border-color: var(--color-border-secondary);
-        }
-      }
-    }
-
-    .toolbar-divider {
-      background: var(--color-border-tertiary);
-    }
-  }
-}
-
-// 响应式适配
-@media (max-width: 768px) {
-  .map-toolbar {
-    .toolbar-group {
-      .toolbar-btn {
-        width: 32px;
-        height: 32px;
-
-        ::v-deep .el-icon {
-          font-size: var(--font-size-sm);
-        }
-      }
-    }
-  }
-}
-
-// 动画效果
-@keyframes toolbarSlideIn {
-  from {
-    opacity: 0;
-    transform: translateX(-20px);
-  }
-  to {
-    opacity: 1;
-    transform: translateX(0);
-  }
-}
-
-.map-toolbar {
-  animation: toolbarSlideIn 0.3s ease-out;
-}
-</style>

+ 0 - 575
src/views/map/maplist/components/RightPanel.vue

@@ -1,575 +0,0 @@
-<template>
-  <div class="right-panel">
-    <!-- 面板头部 -->
-    <div class="panel-header">
-      <div class="panel-title">
-        <h3>实时标定信息</h3>
-        <span class="map-name">(当前地图: {{ mapName }})</span>
-      </div>
-      <el-button 
-        @click="toggleCollapse" 
-        type="text" 
-        size="mini" 
-        class="collapse-btn"
-        icon="el-icon-arrow-right"
-      />
-    </div>
-
-    <!-- 面板内容 -->
-    <div class="panel-content">
-      <!-- 实时位姿卡片 -->
-      <div class="info-card">
-        <div class="card-header">
-          <h4 class="card-title">实时位姿</h4>
-        </div>
-        <div class="card-content">
-          <!-- 激光定位 -->
-          <div class="pose-section">
-            <div class="section-title">激光定位</div>
-            <div class="pose-item">
-              <span class="pose-label">X坐标</span>
-              <span class="pose-value">{{ laserPositionData.x }}</span>
-            </div>
-            <div class="pose-item">
-              <span class="pose-label">Y坐标</span>
-              <span class="pose-value">{{ laserPositionData.y }}</span>
-            </div>
-            <div class="pose-item">
-              <span class="pose-label">航向角</span>
-              <span class="pose-value">{{ laserPositionData.angle }}</span>
-            </div>
-          </div>
-
-          <!-- GNSS定位 -->
-          <div class="pose-section">
-            <div class="section-title">GNSS定位</div>
-            <div class="pose-item">
-              <span class="pose-label">状态</span>
-              <el-tag 
-                :type="getGnssStatusType(gnssPositionData.status)" 
-                size="mini"
-                class="pose-value"
-              >
-                {{ gnssPositionData.status }}
-              </el-tag>
-            </div>
-            <div class="pose-item">
-              <span class="pose-label">经度</span>
-              <span class="pose-value">{{ gnssPositionData.longitude }}</span>
-            </div>
-            <div class="pose-item">
-              <span class="pose-label">纬度</span>
-              <span class="pose-value">{{ gnssPositionData.latitude }}</span>
-            </div>
-            <div class="pose-item">
-              <span class="pose-label">方向角</span>
-              <span class="pose-value">{{ gnssPositionData.angle }}</span>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <!-- 当前标定点卡片 -->
-      <div class="info-card">
-        <div class="card-header">
-          <h4 class="card-title">当前标定点</h4>
-        </div>
-        <div class="card-content">
-          <div class="calibration-table" v-if="calibrationList.length > 0">
-            <div class="table-header">
-              <div class="col-id">序号</div>
-              <div class="col-coord">坐标(X,Y)</div>
-              <div class="col-action">操作</div>
-            </div>
-            <div class="table-body">
-              <div 
-                v-for="item in calibrationList" 
-                :key="item.id" 
-                class="table-row"
-              >
-                <div class="col-id">{{ item.id }}</div>
-                <div class="col-coord">{{ item.coordinate }}</div>
-                <div class="col-action">
-                  <el-popconfirm
-                    title="确定要删除这个标定点吗?"
-                    @confirm="removeCalibration(item.id)"
-                    placement="left"
-                  >
-                    <el-button 
-                      slot="reference"
-                      type="text" 
-                      size="mini" 
-                      icon="el-icon-delete"
-                      class="delete-btn"
-                    />
-                  </el-popconfirm>
-                </div>
-              </div>
-            </div>
-          </div>
-          
-          <!-- 空状态 -->
-          <div v-else class="empty-state">
-            <i class="el-icon-position"></i>
-            <p>暂无标定点</p>
-          </div>
-
-          <!-- 操作按钮组 -->
-          <div class="action-buttons">
-            <el-button 
-              type="primary" 
-              size="small" 
-              icon="el-icon-plus"
-              @click="addCalibration"
-              :disabled="!canAddCalibration"
-            >
-              添加标定点
-            </el-button>
-            <el-button 
-              size="small" 
-              icon="el-icon-check"
-              @click="executeCalibration"
-              :disabled="calibrationList.length === 0"
-            >
-              一键标定
-            </el-button>
-          </div>
-        </div>
-      </div>
-
-    </div>
-
-    <!-- 拖拽调宽手柄 -->
-    <div class="resize-handle" @mousedown="startResize" v-show="!isDrawerMode"></div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RightPanel',
-  props: {
-    mapName: {
-      type: String,
-      required: true
-    },
-    laserPositionData: {
-      type: Object,
-      default: () => ({ x: 0, y: 0, angle: 0 })
-    },
-    gnssPositionData: {
-      type: Object,
-      default: () => ({ status: '0/0', longitude: 0, latitude: 0, angle: 0 })
-    },
-    calibrationList: {
-      type: Array,
-      default: () => []
-    },
-    currentMap: {
-      type: Object,
-      default: () => ({ name: 'sh02' })
-    },
-    isDrawerMode: {
-      type: Boolean,
-      default: false
-    },
-    panelWidth: {
-      type: Number,
-      default: 360
-    }
-  },
-  data() {
-    return {
-      panelWidth: 360,
-      isResizing: false
-    }
-  },
-  computed: {
-    canAddCalibration() {
-      return this.laserPositionData.x !== 0 || this.laserPositionData.y !== 0
-    }
-  },
-  mounted() {
-    // 在浮层模式下,宽度由父组件控制
-    if (!this.isDrawerMode) {
-      this.panelWidth = this.panelWidth || 360
-    }
-    
-    // 添加全局鼠标事件监听
-    document.addEventListener('mousemove', this.handleResize)
-    document.addEventListener('mouseup', this.stopResize)
-  },
-  beforeDestroy() {
-    document.removeEventListener('mousemove', this.handleResize)
-    document.removeEventListener('mouseup', this.stopResize)
-  },
-  methods: {
-    toggleCollapse() {
-      // 直接通知父组件切换状态,不维护内部状态
-      this.$emit('panel-toggle', true) // 总是发送折叠信号
-    },
-    
-    updatePanelWidth() {
-      // 在浮层模式下,宽度由CSS和父组件控制
-      if (!this.isDrawerMode) {
-        this.$nextTick(() => {
-          if (this.$el) {
-            this.$el.style.width = this.panelWidth + 'px'
-          }
-        })
-      }
-    },
-    
-    startResize(event) {
-      this.isResizing = true
-      this.startX = event.clientX
-      this.startWidth = this.panelWidth
-      document.body.style.cursor = 'col-resize'
-      document.body.style.userSelect = 'none'
-    },
-    
-    handleResize(event) {
-      if (!this.isResizing || this.isDrawerMode) return
-      
-      const diff = this.startX - event.clientX
-      const newWidth = Math.max(320, Math.min(420, this.startWidth + diff))
-      
-      if (newWidth !== this.panelWidth) {
-        this.panelWidth = newWidth
-        this.updatePanelWidth()
-        this.$emit('panel-resize', newWidth)
-      }
-    },
-    
-    stopResize() {
-      if (this.isResizing) {
-        this.isResizing = false
-        document.body.style.cursor = ''
-        document.body.style.userSelect = ''
-        localStorage.setItem('calibration-panel-width', this.panelWidth)
-      }
-    },
-    
-    getGnssStatusType(status) {
-      if (status === '0/0') return 'info'
-      if (status.includes('锁定')) return 'success'
-      if (status.includes('异常')) return 'warning'
-      return 'info'
-    },
-    
-    addCalibration() {
-      this.$emit('add-calibration')
-    },
-    
-    removeCalibration(id) {
-      this.$emit('remove-calibration', id)
-    },
-    
-    executeCalibration() {
-      this.$emit('execute-calibration')
-    }
-  },
-
-  watch: {
-    panelWidth(newWidth) {
-      if (!this.isDrawerMode) {
-        this.updatePanelWidth()
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.right-panel {
-  /* 浮层模式下的基础样式由父组件控制 */
-  height: 100%;
-  background: var(--color-bg-card);
-  border: 1px solid var(--color-border-primary);
-  border-radius: var(--radius-lg);
-  transition: all var(--duration-200) var(--ease-out);
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
-  box-shadow: var(--shadow-xl);
-
-  &.collapsed {
-    opacity: 0;
-    pointer-events: none;
-  }
-
-  .panel-header {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding: var(--spacing-4) var(--spacing-4) var(--spacing-3) var(--spacing-4);
-    border-bottom: 1px solid var(--color-border-secondary);
-    background: var(--color-bg-tertiary);
-
-    .panel-title {
-      h3 {
-        margin: 0;
-        font-size: var(--font-size-lg);
-        font-weight: var(--font-weight-semibold);
-        color: var(--color-text-primary);
-        line-height: var(--line-height-tight);
-      }
-
-      .map-name {
-        font-size: var(--font-size-xs);
-        color: var(--color-danger);
-        margin-left: var(--spacing-2);
-      }
-    }
-
-    .collapse-btn {
-      color: var(--color-text-tertiary);
-      
-      &:hover {
-        color: var(--color-primary);
-      }
-    }
-  }
-
-  .panel-content {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    padding: var(--spacing-4);
-    opacity: 1;
-    transition: opacity var(--duration-200) var(--ease-out);
-    overflow: hidden;
-
-    .info-card {
-      background: var(--color-bg-card);
-      border-radius: var(--radius-lg);
-      box-shadow: var(--shadow-card);
-      margin-bottom: 16px; /* 统一卡片间距 */
-      overflow: hidden;
-
-      &:last-child {
-        margin-bottom: 0;
-        flex: 1;
-        display: flex;
-        flex-direction: column;
-        min-height: 0;
-      }
-
-      .card-header {
-        padding: var(--spacing-3) var(--spacing-4);
-        border-bottom: 1px solid var(--color-border-secondary);
-        background: var(--color-bg-secondary);
-
-        .card-title {
-          margin: 0;
-          font-size: var(--font-size-base);
-          font-weight: var(--font-weight-semibold);
-          color: var(--color-text-primary);
-        }
-      }
-
-      .card-content {
-        padding: var(--spacing-4);
-      }
-      
-      /* 为最后一个卡片(标定点卡片)设置可滚动 */
-      &:last-child {
-        .card-content {
-          flex: 1;
-          overflow-y: auto;
-          
-          /* 自定义滚动条样式 */
-          &::-webkit-scrollbar {
-            width: 6px;
-          }
-
-          &::-webkit-scrollbar-track {
-            background: var(--color-bg-tertiary);
-            border-radius: var(--radius-full);
-          }
-
-          &::-webkit-scrollbar-thumb {
-            background: var(--color-border-primary);
-            border-radius: var(--radius-full);
-            
-            &:hover {
-              background: var(--color-text-quaternary);
-            }
-          }
-        }
-      }
-
-      .pose-section {
-        margin-bottom: var(--spacing-4);
-
-        &:last-child {
-          margin-bottom: 0;
-        }
-
-        .section-title {
-          font-size: var(--font-size-sm);
-          font-weight: var(--font-weight-medium);
-          color: var(--color-text-tertiary);
-          margin-bottom: var(--spacing-2);
-          padding-bottom: var(--spacing-1);
-          border-bottom: 1px solid var(--color-border-tertiary);
-        }
-
-        .pose-item {
-          display: flex;
-          justify-content: space-between;
-          align-items: center;
-          padding: var(--spacing-2) 0;
-          border-bottom: 1px solid var(--color-border-tertiary);
-
-          &:last-child {
-            border-bottom: none;
-          }
-
-          .pose-label {
-            font-size: var(--font-size-sm);
-            color: var(--color-text-secondary);
-            font-weight: var(--font-weight-medium);
-          }
-
-          .pose-value {
-            font-size: var(--font-size-sm);
-            color: var(--color-text-primary);
-            font-weight: var(--font-weight-normal);
-            text-align: right;
-          }
-        }
-      }
-
-      .calibration-table {
-        .table-header,
-        .table-row {
-          display: grid;
-          grid-template-columns: 48px 1fr 48px;
-          gap: var(--spacing-2);
-          align-items: center;
-        }
-
-        .table-header {
-          padding: var(--spacing-2) 0;
-          border-bottom: 1px solid var(--color-border-secondary);
-          font-size: var(--font-size-xs);
-          font-weight: var(--font-weight-semibold);
-          color: var(--color-text-tertiary);
-          text-align: center;
-        }
-
-        .table-row {
-          padding: var(--spacing-2) 0;
-          border-bottom: 1px solid var(--color-border-tertiary);
-          font-size: var(--font-size-sm);
-
-          &:last-child {
-            border-bottom: none;
-          }
-
-          &:hover {
-            background: var(--color-bg-secondary);
-          }
-
-          .col-id {
-            text-align: center;
-            font-weight: var(--font-weight-medium);
-            color: var(--color-primary);
-          }
-
-          .col-coord {
-            font-family: var(--font-family-mono);
-            font-size: var(--font-size-xs);
-            color: var(--color-text-secondary);
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-          }
-
-          .col-action {
-            text-align: center;
-
-            .delete-btn {
-              color: var(--color-danger);
-              
-              &:hover {
-                color: var(--color-danger-dark);
-              }
-            }
-          }
-        }
-      }
-
-      .action-buttons {
-        display: flex;
-        gap: var(--spacing-2);
-        margin-top: var(--spacing-4);
-
-        .el-button {
-          flex: 1;
-        }
-      }
-
-      .empty-state {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        justify-content: center;
-        padding: var(--spacing-6) var(--spacing-4);
-        color: var(--color-text-quaternary);
-
-        i {
-          font-size: var(--font-size-2xl);
-          margin-bottom: var(--spacing-2);
-          opacity: 0.5;
-        }
-
-        p {
-          margin: 0;
-          font-size: var(--font-size-sm);
-          opacity: 0.8;
-        }
-      }
-    }
-  }
-
-  .resize-handle {
-    position: absolute;
-    left: 0;
-    top: 0;
-    bottom: 0;
-    width: 8px;
-    cursor: col-resize;
-    background: transparent;
-    z-index: 10;
-
-    &:hover {
-      background: var(--color-primary);
-      opacity: 0.3;
-    }
-
-    &:active {
-      background: var(--color-primary);
-      opacity: 0.5;
-    }
-  }
-}
-
-// 暗色主题适配
-html.dark {
-  .right-panel {
-    .panel-header {
-      background: var(--color-bg-quaternary);
-    }
-
-    .info-card {
-      background: var(--color-bg-tertiary);
-      box-shadow: var(--shadow-card);
-
-      .card-header {
-        background: var(--color-bg-quaternary);
-      }
-    }
-  }
-}
-</style>

+ 485 - 0
src/views/map/maplist/components/shared/MapToolbar.vue

@@ -0,0 +1,485 @@
+<template>
+  <div class="map-toolbar" :style="toolbarStyle">
+    <!-- 内置工具或自定义工具 -->
+    <template v-if="preset !== 'custom' || tools.length > 0">
+      <!-- 预设或自定义工具模式 -->
+      <div v-for="(tool, index) in visibleTools" :key="tool.key" class="toolbar-item-wrapper">
+        <!-- 按钮类型 -->
+        <div v-if="tool.type === 'btn'" class="toolbar-item">
+          <el-tooltip 
+            :content="getToolTooltip(tool)" 
+            :placement="vertical ? 'right' : 'bottom'"
+          >
+            <el-button 
+              :size="buttonSize" 
+              :icon="tool.icon"
+              :type="tool.buttonType || 'default'"
+              circle
+              :disabled="tool.disabled || isToolDisabled(tool.key)"
+              :class="[
+                'toolbar-btn',
+                { 
+                  'primary-btn': tool.buttonType === 'primary',
+                  'active': selectedKey === tool.key 
+                }
+              ]"
+              @click="handleToolClick(tool)"
+            />
+          </el-tooltip>
+        </div>
+        <!-- 分隔线类型 -->
+        <div 
+          v-else-if="tool.type === 'divider'" 
+          class="toolbar-divider"
+          aria-hidden="true"
+        ></div>
+      </div>
+    </template>
+
+    <template v-else>
+      <!-- 默认内置工具模式(兼容原有标定页) -->
+      <el-tooltip content="放大" :placement="vertical ? 'right' : 'bottom'">
+        <el-button 
+          :size="buttonSize" 
+          icon="el-icon-plus" 
+          circle
+          @click="zoomIn"
+          class="toolbar-btn"
+        />
+      </el-tooltip>
+      
+      <el-tooltip content="缩小" :placement="vertical ? 'right' : 'bottom'">
+        <el-button 
+          :size="buttonSize" 
+          icon="el-icon-minus" 
+          circle
+          @click="zoomOut"
+          class="toolbar-btn"
+        />
+      </el-tooltip>
+      
+      <el-tooltip content="居中到机器人" :placement="vertical ? 'right' : 'bottom'">
+        <el-button 
+          :size="buttonSize" 
+          icon="el-icon-location" 
+          circle
+          @click="centerToRobot"
+          :disabled="!hasRobotPosition"
+          class="toolbar-btn"
+        />
+      </el-tooltip>
+      
+      <el-tooltip :content="isFullscreen ? '退出全屏' : '全屏'" :placement="vertical ? 'right' : 'bottom'">
+        <el-button 
+          :size="buttonSize" 
+          :icon="isFullscreen ? 'el-icon-aim' : 'el-icon-full-screen'"
+          circle
+          @click="toggleFullscreen"
+          class="toolbar-btn"
+        />
+      </el-tooltip>
+
+      <!-- 分割线 -->
+      <div class="toolbar-divider"></div>
+
+      <!-- 主要操作按钮 -->
+      <el-tooltip content="添加标定点" :placement="vertical ? 'right' : 'bottom'">
+        <el-button 
+          type="primary"
+          :size="buttonSize" 
+          icon="el-icon-circle-plus"
+          circle
+          @click="addCalibrationPoint"
+          class="toolbar-btn primary-btn"
+          :disabled="!canAddCalibration"
+        />
+      </el-tooltip>
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MapToolbar',
+  props: {
+    // 预设配置
+    preset: {
+      type: String,
+      default: 'custom',
+      validator: value => ['custom', 'calibration', 'nav'].includes(value)
+    },
+    // 自定义工具配置
+    tools: {
+      type: Array,
+      default: () => []
+    },
+    // 布局方向
+    vertical: {
+      type: Boolean,
+      default: true
+    },
+    // 按钮尺寸
+    size: {
+      type: String,
+      default: 'md', // 'sm'|'md'|'lg'
+      validator: value => ['sm', 'md', 'lg'].includes(value)
+    },
+    // 当前选中的工具
+    selectedKey: {
+      type: String,
+      default: ''
+    },
+    // 禁用的工具列表
+    disabledKeys: {
+      type: Array,
+      default: () => []
+    },
+    // 位置偏移
+    offset: {
+      type: Object,
+      default: () => ({ top: '16px', left: '16px' })
+    },
+    
+    // === 兼容原标定页的props ===
+    canAddCalibration: {
+      type: Boolean,
+      default: true
+    },
+    hasRobotPosition: {
+      type: Boolean,
+      default: false
+    },
+    isFullscreen: {
+      type: Boolean,
+      default: false
+    },
+    showAdvanced: {
+      type: Boolean,
+      default: false
+    },
+    // 连接状态
+    isConnected: {
+      type: Boolean,
+      default: true
+    },
+    // 系统忙碌状态
+    isBusy: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    // 当前使用的工具配置
+    currentTools() {
+      if (this.preset === 'custom' && this.tools.length > 0) {
+        return this.tools
+      }
+      return this.getPresetTools()
+    },
+    
+    // 可见的工具列表
+    visibleTools() {
+      return this.currentTools.filter(tool => tool.visible !== false)
+    },
+    
+    // 按钮尺寸映射
+    buttonSize() {
+      const sizeMap = {
+        'sm': 'mini',
+        'md': 'small', 
+        'lg': 'medium'
+      }
+      return sizeMap[this.size] || 'small'
+    },
+    
+    // 工具栏样式
+    toolbarStyle() {
+      return {
+        top: this.offset.top,
+        left: this.offset.left,
+        right: this.offset.right,
+        bottom: this.offset.bottom,
+        flexDirection: this.vertical ? 'column' : 'row'
+      }
+    }
+  },
+  methods: {
+    // 获取预设工具配置
+    getPresetTools() {
+      const presets = {
+        calibration: [
+          { key: 'zoom-in', type: 'btn', icon: 'el-icon-plus', tooltip: '放大' },
+          { key: 'zoom-out', type: 'btn', icon: 'el-icon-minus', tooltip: '缩小' },
+          { key: 'center-robot', type: 'btn', icon: 'el-icon-location', tooltip: '居中到机器人' },
+          { key: 'toggle-fullscreen', type: 'btn', icon: this.isFullscreen ? 'el-icon-aim' : 'el-icon-full-screen', tooltip: this.isFullscreen ? '退出全屏' : '进入全屏' },
+          { key: 'divider-1', type: 'divider' },
+          { key: 'add-calibration', type: 'btn', icon: 'el-icon-circle-plus', tooltip: '添加标定点', buttonType: 'primary' }
+        ],
+        nav: [
+          { key: 'zoom-in', type: 'btn', icon: 'el-icon-plus', tooltip: '放大' },
+          { key: 'zoom-out', type: 'btn', icon: 'el-icon-minus', tooltip: '缩小' },
+          { key: 'center-robot', type: 'btn', icon: 'el-icon-location', tooltip: '居中到机器人' },
+          { key: 'toggle-fullscreen', type: 'btn', icon: this.isFullscreen ? 'el-icon-aim' : 'el-icon-full-screen', tooltip: this.isFullscreen ? '退出全屏' : '进入全屏' },
+          { key: 'divider-1', type: 'divider' },
+          { key: 'init-pose', type: 'btn', icon: 'el-icon-position', tooltip: '初始化' },
+          { key: 'reboot', type: 'btn', icon: 'el-icon-refresh', tooltip: '重启' },
+          { key: 'emergency-stop', type: 'btn', icon: 'el-icon-switch-button', tooltip: '结束/急停' }
+        ]
+      }
+      return presets[this.preset] || []
+    },
+    
+    // 获取工具的tooltip
+    getToolTooltip(tool) {
+      // 始终显示正常的tooltip,不再显示连接状态相关提示
+      return tool.tooltip || tool.key
+    },
+    
+    // 处理需要确认的操作
+    handleConfirmAction(actionKey) {
+      const confirmMessages = {
+        'init-pose': '确定要进行位姿初始化吗?',
+        'reboot': '确定要重启系统吗?',
+        'emergency-stop': '确定要急停/结束当前操作吗?'
+      }
+      
+      const message = confirmMessages[actionKey]
+      if (!message) return
+      
+      this.$confirm(message, '确认操作', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const eventMap = {
+          'init-pose': 'confirm-init',
+          'reboot': 'confirm-reboot', 
+          'emergency-stop': 'confirm-stop'
+        }
+        this.$emit(eventMap[actionKey])
+      }).catch(() => {
+        // 用户取消操作
+      })
+    },
+    
+    // 统一工具点击处理
+    handleToolClick(tool) {
+      // 需要二次确认的操作
+      if (['init-pose', 'reboot', 'emergency-stop'].includes(tool.key)) {
+        this.handleConfirmAction(tool.key)
+        return
+      }
+      
+      // 发送统一点击事件
+      this.$emit('click', { key: tool.key, tool })
+      
+      // 兼容特定工具的专用事件
+      if (tool.key === 'zoom-in') {
+        this.$emit('zoom-in')
+      } else if (tool.key === 'zoom-out') {
+        this.$emit('zoom-out')
+      } else if (tool.key === 'center-robot') {
+        this.$emit('center-robot')
+      } else if (tool.key === 'toggle-fullscreen') {
+        this.$emit('toggle-fullscreen')
+      } else if (tool.key === 'add-calibration') {
+        this.$emit('add-calibration-point')
+      }
+    },
+    
+    // 检查工具是否禁用
+    isToolDisabled(key) {
+      // 只保留手动指定禁用的情况,移除所有自动禁用逻辑
+      if (this.disabledKeys.includes(key)) {
+        return true
+      }
+      
+      // 其他所有按钮都允许操作
+      return false
+    },
+    
+    // === 兼容原标定页的方法 ===
+    zoomIn() {
+      this.$emit('zoom-in')
+      this.$emit('click', { key: 'zoom-in' })
+    },
+    
+    zoomOut() {
+      this.$emit('zoom-out')
+      this.$emit('click', { key: 'zoom-out' })
+    },
+    
+    centerToRobot() {
+      if (!this.hasRobotPosition) {
+        return
+      }
+      this.$emit('center-to-robot')
+      this.$emit('click', { key: 'center-to-robot' })
+    },
+    
+    toggleFullscreen() {
+      this.$emit('toggle-fullscreen')
+      this.$emit('click', { key: 'toggle-fullscreen' })
+    },
+    
+    addCalibrationPoint() {
+      this.$emit('add-calibration-point')
+      this.$emit('click', { key: 'add-calibration-point' })
+    },
+    
+    resetView() {
+      this.$emit('reset-view')
+      this.$emit('click', { key: 'reset-view' })
+    },
+    
+    toggleMeasureTool() {
+      this.$emit('toggle-measure-tool')
+      this.$emit('click', { key: 'toggle-measure-tool' })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import './_map-shared.scss';
+
+.map-toolbar {
+  /* 位置由父组件控制 */
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 6px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+  padding: 8px;
+  pointer-events: auto;
+  width: auto;
+  z-index: 1;
+
+  .toolbar-item-wrapper {
+    display: contents; /* 让wrapper不影响布局 */
+  }
+
+  .toolbar-item {
+    display: flex;
+    flex-direction: inherit;
+    align-items: center;
+    gap: inherit;
+  }
+
+  .toolbar-btn {
+    width: 36px;
+    height: 36px;
+    min-width: 36px;
+    min-height: 36px;
+    padding: 0;
+    margin: 0;
+    border: 1px solid #dcdfe6;
+    background-color: #fff;
+    color: #606266;
+    transition: all 0.2s ease;
+
+    &:hover {
+      background-color: #f5f7fa;
+      border-color: #c0c4cc;
+      color: #409eff;
+    }
+
+    &:active {
+      background-color: #e6f7ff;
+      border-color: #409eff;
+      color: #409eff;
+      transform: scale(0.98);
+    }
+
+    &.primary-btn {
+      background-color: #409eff;
+      color: #fff;
+      border-color: #409eff;
+
+      &:hover {
+        background-color: #66b1ff;
+        border-color: #66b1ff;
+      }
+
+      &:active {
+        background-color: #3a8ee6;
+        border-color: #3a8ee6;
+        transform: scale(0.98);
+      }
+    }
+
+    &.active {
+      background: #409eff;
+      color: #fff;
+      border-color: #409eff;
+    }
+
+    &:disabled {
+      color: #c0c4cc;
+      background-color: #fff;
+      border-color: #ebeef5;
+      cursor: not-allowed;
+    }
+
+    ::v-deep .el-icon {
+      font-size: 16px !important;
+      line-height: 1 !important;
+    }
+
+    ::v-deep i {
+      font-size: var(--font-size-base) !important;
+      line-height: 1 !important;
+    }
+  }
+
+  .toolbar-divider {
+    width: 100%;
+    height: 1px;
+    margin: 10px 0;
+    background: rgba(0, 0, 0, 0.08);
+    flex-shrink: 0;
+  }
+}
+
+// 暗色主题适配
+html.dark {
+  .map-toolbar {
+    @include dark-theme-toolbar-content;
+  }
+}
+
+// 响应式适配
+@media (max-width: 768px) {
+  .map-toolbar {
+    .toolbar-btn {
+      width: $toolbar-btn-size-sm !important;
+      height: $toolbar-btn-size-sm !important;
+      min-width: $toolbar-btn-size-sm !important;
+      min-height: $toolbar-btn-size-sm !important;
+
+      ::v-deep .el-icon {
+        font-size: var(--font-size-sm);
+      }
+    }
+  }
+}
+
+// 动画效果
+@keyframes toolbarSlideIn {
+  from {
+    opacity: 0;
+    transform: translateX(-20px);
+  }
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+.map-toolbar {
+  animation: toolbarSlideIn 0.3s ease-out;
+}
+</style>

+ 2231 - 0
src/views/map/maplist/components/shared/RightPanel.vue

@@ -0,0 +1,2231 @@
+<template>
+  <div :class="['right-panel-container', mode === 'nav' ? 'rp--nav' : 'rp--calib']">
+    <!-- 标定页面板(保持原有结构不变) -->
+    <template v-if="panelType !== 'nav'">
+    <!-- 主面板 -->
+    <div 
+      class="right-panel" 
+      :class="{ 'panel-collapsed': !value }"
+      :style="{ width: value ? width + 'px' : '0px' }"
+    >
+      <!-- 面板头部 -->
+      <div class="panel-header" v-if="!hideHeader">
+        <div class="panel-title">
+          <slot name="header">
+            <h3>{{ title }}</h3>
+            <span v-if="subtitle" class="panel-subtitle">{{ subtitle }}</span>
+          </slot>
+        </div>
+        <el-button 
+          @click="togglePanel" 
+          type="text" 
+          size="mini" 
+          class="collapse-btn"
+          :icon="value ? 'el-icon-arrow-right' : 'el-icon-arrow-left'"
+        />
+      </div>
+
+      <!-- 面板内容 -->
+      <div class="panel-content">
+        <!-- 标签页模式 -->
+        <template v-if="tabs.length > 0">
+          <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+            <el-tab-pane 
+              v-for="tab in processedTabs" 
+              :key="tab.key"
+              :label="tab.label"
+              :name="tab.key"
+            >
+              <!-- 实时信息Tab -->
+              <template v-if="tab.key === 'info'">
+                <div class="realtime-info-content">
+                  <div class="info-section">
+                    <div class="info-title">
+                      <div class="title-bar"></div>
+                      <span>当前地图</span>
+                    </div>
+                    <span class="info-content">{{ realtimeInfo.currentMap }}</span>
+                  </div>
+                  
+                  <div class="info-section">
+                    <div class="info-title">
+                      <div class="title-bar"></div>
+                      <span>当前任务</span>
+                    </div>
+                    <span class="info-content">{{ realtimeInfo.currentTask }}</span>
+                  </div>
+                  
+                  <div class="info-section">
+                    <div class="info-title">
+                      <div class="title-bar"></div>
+                      <span>实时信息</span>
+                    </div>
+                    <div class="info-details">
+                      <span class="info-item">
+                        <span class="info-label">速度:</span>
+                        <span class="info-value">{{ realtimeInfo.speed }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">速度指令:</span>
+                        <span class="info-value">{{ realtimeInfo.speedCommand }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">坐标:</span>
+                        <span class="info-value">{{ realtimeInfo.coordinates }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">航向:</span>
+                        <span class="info-value">{{ realtimeInfo.heading }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">累计里程:</span>
+                        <span class="info-value">{{ realtimeInfo.totalDistance }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">配准误差:</span>
+                        <span class="info-value">{{ realtimeInfo.registrationError }}</span>
+                      </span>
+                      <span class="info-item">
+                        <span class="info-label">电量:</span>
+                        <span class="info-value">{{ realtimeInfo.batteryLevel }}</span>
+                      </span>
+                    </div>
+                  </div>
+                </div>
+              </template>
+              
+              <!-- 其他Tab使用插槽 -->
+              <template v-else>
+                <slot :name="`tab-${tab.key}`">
+                  <div class="tab-placeholder">
+                    {{ tab.label }} 内容
+                  </div>
+                </slot>
+              </template>
+            </el-tab-pane>
+          </el-tabs>
+        </template>
+
+        <!-- 默认内容模式 -->
+        <template v-else>
+          <slot>
+            <!-- 兼容原标定页内容 -->
+            <div class="default-content">
+              <!-- 实时位姿卡片 -->
+              <div class="info-card" v-if="showPoseCard">
+                <div class="card-header">
+                  <h4 class="card-title">实时位姿</h4>
+                </div>
+                <div class="card-content">
+                  <!-- 激光定位 -->
+                  <div class="pose-section">
+                    <div class="section-title">激光定位</div>
+                    <div class="pose-item">
+                      <span class="pose-label">X坐标</span>
+                      <span class="pose-value">{{ laserPositionData.x }}</span>
+                    </div>
+                    <div class="pose-item">
+                      <span class="pose-label">Y坐标</span>
+                      <span class="pose-value">{{ laserPositionData.y }}</span>
+                    </div>
+                    <div class="pose-item">
+                      <span class="pose-label">航向角</span>
+                      <span class="pose-value">{{ laserPositionData.angle }}</span>
+                    </div>
+                  </div>
+
+                  <!-- GNSS定位 -->
+                  <div class="pose-section">
+                    <div class="section-title">GNSS定位</div>
+                    <div class="pose-item">
+                      <span class="pose-label">状态</span>
+                      <el-tag 
+                        :type="getGnssStatusType(gnssPositionData.status)" 
+                        size="mini"
+                        class="pose-value"
+                      >
+                        {{ gnssPositionData.status }}
+                      </el-tag>
+                    </div>
+                    <div class="pose-item">
+                      <span class="pose-label">经度</span>
+                      <span class="pose-value">{{ gnssPositionData.longitude }}</span>
+                    </div>
+                    <div class="pose-item">
+                      <span class="pose-label">纬度</span>
+                      <span class="pose-value">{{ gnssPositionData.latitude }}</span>
+                    </div>
+                    <div class="pose-item">
+                      <span class="pose-label">方向角</span>
+                      <span class="pose-value">{{ gnssPositionData.angle }}</span>
+                    </div>
+                  </div>
+                </div>
+              </div>
+
+              <!-- 当前标定点卡片 -->
+              <div class="info-card" v-if="showCalibrationCard">
+                <div class="card-header">
+                  <h4 class="card-title">当前标定点</h4>
+                </div>
+                <div class="card-content">
+                  <div class="calibration-table" v-if="calibrationList.length > 0">
+                    <div class="table-header">
+                      <div class="col-id">序号</div>
+                      <div class="col-coord">坐标(X,Y)</div>
+                      <div class="col-action">操作</div>
+                    </div>
+                    <div class="table-body">
+                      <div 
+                        v-for="item in calibrationList" 
+                        :key="item.id" 
+                        class="table-row"
+                      >
+                        <div class="col-id">{{ item.id }}</div>
+                        <div class="col-coord">{{ item.coordinate }}</div>
+                        <div class="col-action">
+                          <el-popconfirm
+                            title="确定要删除这个标定点吗?"
+                            @confirm="removeCalibration(item.id)"
+                            placement="left"
+                          >
+                            <el-button 
+                              slot="reference"
+                              type="text" 
+                              size="mini" 
+                              icon="el-icon-delete"
+                              class="delete-btn"
+                            />
+                          </el-popconfirm>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  
+                  <!-- 空状态 -->
+                  <div v-else class="empty-state">
+                    <i class="el-icon-position"></i>
+                    <p>暂无标定点</p>
+                  </div>
+
+                  <!-- 操作按钮组 -->
+                  <div class="action-buttons">
+                    <el-button 
+                      type="primary" 
+                      size="small" 
+                      icon="el-icon-plus"
+                      @click="addCalibration"
+                      :disabled="!canAddCalibration"
+                    >
+                      添加标定点
+                    </el-button>
+                    <el-button 
+                      size="small" 
+                      icon="el-icon-check"
+                      @click="executeCalibration"
+                      :disabled="calibrationList.length === 0"
+                    >
+                      一键标定
+                    </el-button>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </slot>
+        </template>
+      </div>
+
+      <!-- 拖拽调宽手柄 -->
+      <div 
+        class="resize-handle" 
+        @mousedown="startResize" 
+        v-if="resizable && !isDrawerMode && value"
+      ></div>
+    </div>
+
+    <!-- 展开拉手 (收起时显示) -->
+    <div 
+      v-if="overlay && !value" 
+      class="expand-handle"
+      @click="expandPanel"
+      :title="expandTooltip"
+    >
+      <i class="el-icon-arrow-left"></i>
+    </div>
+    </template>
+    
+    <!-- 导航页面板(全新独立结构) -->
+    <template v-else>
+      <aside 
+        class="right-panel nav-right-panel"
+        :class="{ 'is-hidden': !visible }"
+      >
+        <!-- 导航页Tabs -->
+        <div class="nav-panel-header">
+          <el-tabs v-model="navActiveTab" class="nav-tabs">
+          <!-- Tab1: 实时信息 -->
+          <el-tab-pane label="实时信息" name="realtime">
+            <div class="nav-tab-content">
+              <div class="nav-info-grid">
+                <div class="nav-info-header">
+                  <h3 class="nav-info-title">实时信息</h3>
+                </div>
+                <div class="nav-info-content">
+                  <div class="nav-info-item">
+                    <span class="label">当前地图:</span>
+                    <span class="value">{{ realtimeInfo.currentMap }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">坐标:</span>
+                    <span class="value">{{ realtimeInfo.coordinates }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">航向:</span>
+                    <span class="value">{{ realtimeInfo.heading }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">速度:</span>
+                    <span class="value">{{ realtimeInfo.speed }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">指令速度:</span>
+                    <span class="value">{{ realtimeInfo.speedCommand }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">总里程:</span>
+                    <span class="value">{{ realtimeInfo.totalDistance }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">配准误差:</span>
+                    <span class="value">{{ realtimeInfo.registrationError }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">电池电量:</span>
+                    <span class="value">{{ realtimeInfo.batteryLevel }}</span>
+                  </div>
+                  <div class="nav-info-item">
+                    <span class="label">当前任务:</span>
+                    <span class="value">{{ realtimeInfo.currentTask }}</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+          
+          <!-- Tab2: 功能设置 -->
+          <el-tab-pane label="功能设置" name="settings">
+            <div class="nav-tab-content">
+              <div class="settings-list">
+                <div class="setting-item">
+                  <div class="setting-info">
+                    <span class="setting-label">点云</span>
+                    <span class="setting-desc">显示/隐藏点云数据</span>
+                  </div>
+                  <el-switch 
+                    v-model="settingParams.pointCloud"
+                    @change="onSettingChange('pointCloud', $event)"
+                  />
+                </div>
+
+                <div class="setting-item">
+                  <div class="setting-info">
+                    <span class="setting-label">底图</span>
+                    <span class="setting-desc">显示/隐藏地图底图</span>
+                  </div>
+                  <el-switch 
+                    v-model="settingParams.baseMap"
+                    @change="onSettingChange('baseMap', $event)"
+                  />
+                </div>
+
+                <div class="setting-item">
+                  <div class="setting-info">
+                    <span class="setting-label">点ID</span>
+                    <span class="setting-desc">显示/隐藏点位ID标识</span>
+                  </div>
+                  <el-switch 
+                    v-model="settingParams.pointId"
+                    @change="onSettingChange('pointId', $event)"
+                  />
+                </div>
+
+                <div class="setting-item">
+                  <div class="setting-info">
+                    <span class="setting-label">位置跟随</span>
+                    <span class="setting-desc">地图自动跟随机器人位置</span>
+                  </div>
+                  <el-switch 
+                    v-model="settingParams.follow"
+                    @change="onSettingChange('follow', $event)"
+                  />
+                </div>
+
+                <div class="setting-item">
+                  <div class="setting-info">
+                    <span class="setting-label">网络邻居</span>
+                    <span class="setting-desc">显示网络邻居设备</span>
+                  </div>
+                  <el-switch 
+                    v-model="settingParams.network"
+                    @change="onSettingChange('network', $event)"
+                  />
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+          
+          <!-- Tab3: 目标点 -->
+          <el-tab-pane label="目标点" name="waypoint">
+            <div class="nav-tab-content">
+              <!-- 操作工具栏 -->
+              <div class="waypoint-toolbar">
+                <!-- 2行3列网格布局 -->
+                <div class="toolbar-grid">
+                  <!-- 第一行:上移、下移、批量删除 -->
+                  <el-button type="primary" size="small" :disabled="waypointSingle" @click="$emit('wp-move-up')" class="grid-btn">
+                    <i class="el-icon-arrow-up"></i>
+                    <span>上移</span>
+                  </el-button>
+                  <el-button type="primary" size="small" :disabled="waypointSingle" @click="$emit('wp-move-down')" class="grid-btn">
+                    <i class="el-icon-arrow-down"></i>
+                    <span>下移</span>
+                  </el-button>
+                  <el-popconfirm title="确定批量删除选中的目标点?" @confirm="$emit('wp-batch-remove')">
+                    <el-button type="danger" size="small" :disabled="waypointMultiple" slot="reference" class="grid-btn">
+                      <i class="el-icon-delete"></i>
+                      <span>批量删除</span>
+                    </el-button>
+                  </el-popconfirm>
+                  
+                  <!-- 第二行:立即前往、生成任务、地图选点 -->
+                  <el-button type="warning" size="small" :disabled="waypointSingle" @click="$emit('wp-goto')" class="grid-btn">
+                    <i class="el-icon-position"></i>
+                    <span>立即前往</span>
+                  </el-button>
+                  <el-button type="success" size="small" :disabled="waypointMultiple" @click="$emit('wp-create-task')" class="grid-btn">
+                    <i class="el-icon-plus"></i>
+                    <span>生成任务</span>
+                  </el-button>
+                  <el-button 
+                    :type="mapSelectMode ? 'danger' : 'info'" 
+                    size="small"
+                    @click="toggleMapSelectMode"
+                    class="grid-btn"
+                  >
+                    <i :class="mapSelectMode ? 'el-icon-close' : 'el-icon-location'"></i>
+                    <span>{{ mapSelectMode ? '关闭选点' : '地图选点' }}</span>
+                  </el-button>
+                </div>
+              </div>
+              
+              <!-- 目标点列表 -->
+              <div class="nav-list-content nav-list-scrollable">
+                <div v-if="waypointList.length > 0" class="nav-waypoint-list">
+                  <div 
+                    v-for="waypoint in waypointList" 
+                    :key="waypoint.id"
+                    class="nav-waypoint-item"
+                    :class="{ 'selected': selectedWaypoints.some(w => w.id === waypoint.id) }"
+                    @click="onWaypointItemClick(waypoint)"
+                  >
+                    <div class="waypoint-checkbox" @click.stop="handleCheckboxClick(waypoint)">
+                      <div 
+                        class="custom-checkbox" 
+                        :class="{ 'checked': selectedWaypoints.some(w => w.id === waypoint.id) }"
+                        @click.stop="handleCheckboxClick(waypoint)"
+                      >
+                        <i v-if="selectedWaypoints.some(w => w.id === waypoint.id)" class="el-icon-check"></i>
+                      </div>
+                    </div>
+                    <div class="waypoint-info">
+                      <div class="waypoint-main">
+                        <span class="waypoint-id">编号: {{ waypoint.id }}</span>
+                        <span class="waypoint-coords">坐标: ({{ waypoint.x }}, {{ waypoint.y }})</span>
+                      </div>
+                    </div>
+                    <div class="waypoint-actions">
+                      <el-button size="mini" type="text" @click.stop="$emit('wp-edit', waypoint)" class="action-btn">编辑</el-button>
+                      <el-popconfirm title="删除当前目标点?" @confirm="$emit('wp-remove', waypoint)">
+                        <el-button size="mini" type="text" slot="reference" @click.stop class="action-btn">删除</el-button>
+                      </el-popconfirm>
+                    </div>
+                  </div>
+                </div>
+                
+                <!-- 空状态 -->
+                <div v-else class="nav-empty-state">
+                  <i class="el-icon-location-outline"></i>
+                  <p>暂无目标点</p>
+                  <p class="empty-hint">点击上方工具栏中的"地图选点"按钮在地图上添加目标点</p>
+                </div>
+              </div>
+
+              <!-- 底部快捷操作 -->
+              <div v-if="selectedWaypoints.length > 0" class="waypoint-quick-actions">
+                <div class="quick-actions-info">
+                  <span>已选择 {{ selectedWaypoints.length }} 个目标点</span>
+                </div>
+                <div class="quick-actions-buttons">
+                  <el-button size="small" @click="clearSelection">取消选择</el-button>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+          
+          <!-- Tab4: 任务 -->
+          <el-tab-pane label="任务" name="task">
+            <div class="nav-tab-content">
+              
+              <div class="nav-list-content">
+                <div v-if="taskList.length > 0" class="nav-task-list">
+                  <div 
+                    v-for="task in taskList" 
+                    :key="task.taskId"
+                    class="nav-task-item"
+                  >
+                    <div class="task-info">
+                      <span class="task-name">{{ task.taskName }}</span>
+                      <span class="task-status" :class="'status-' + task.status">{{ getTaskStatusText(task.status) }}</span>
+                    </div>
+                    <div class="task-actions">
+                      <el-button size="mini" type="text" @click="$emit('task-view', task)">查看</el-button>
+                      <el-button size="mini" type="text" @click="$emit('task-start', task)">开始</el-button>
+                      <el-button size="mini" type="text" @click="$emit('task-pause', task)">暂停</el-button>
+                      <el-button size="mini" type="text" @click="$emit('task-stop', task)">停止</el-button>
+                      <el-button size="mini" type="text" @click="$emit('task-remove', task)">删除</el-button>
+                    </div>
+                  </div>
+                </div>
+                <div v-else class="nav-empty-state">
+                  <i class="el-icon-s-order"></i>
+                  <p>暂无任务</p>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+
+        </el-tabs>
+        
+        <!-- 导航页面的收起按钮 -->
+        <el-button 
+          v-if="panelType === 'nav'"
+          class="nav-panel-close-btn"
+          type="text" 
+          size="mini" 
+          icon="el-icon-arrow-right"
+          @click="$emit('update:visible', false)"
+          title="收起面板"
+        />
+      </div>
+        
+      </aside>
+      
+      <!-- 导航页展开拉手 (收起时显示) - 复用标定页面逻辑 -->
+      <div 
+        v-if="overlay && !visible" 
+        class="expand-handle nav-expand-handle"
+        @click="$emit('update:visible', true)"
+        title="展开面板"
+        @mouseenter="$event.target.style.background = 'var(--color-primary, #409eff)'; $event.target.style.borderColor = 'var(--color-primary, #409eff)'; $event.target.style.transform = 'translateY(-50%) translateX(-2px)'; $event.target.querySelector('i').style.color = '#ffffff';"
+        @mouseleave="$event.target.style.background = 'var(--color-bg-card, #ffffff)'; $event.target.style.borderColor = 'var(--color-border-primary, #dcdfe6)'; $event.target.style.transform = 'translateY(-50%)'; $event.target.querySelector('i').style.color = 'var(--color-text-primary, #303133)';"
+        style="position: fixed !important; right: 0 !important; top: 50% !important; transform: translateY(-50%) !important; z-index: 9999 !important; width: 36px !important; height: 72px !important; background: var(--color-bg-card, #ffffff) !important; border: 1px solid var(--color-border-primary, #dcdfe6) !important; border-radius: 8px 0 0 8px !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; transition: all 0.3s ease !important;"
+      >
+        <i class="el-icon-arrow-left" style="font-size: 16px !important; color: var(--color-text-primary, #303133) !important; font-weight: bold !important; transition: color 0.3s ease !important;"></i>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RightPanel',
+  props: {
+    // 面板模式 - 区分导航/标定
+    mode: {
+      type: String,
+      default: 'calib', // 'calib' 或 'nav'
+      validator: value => ['calib', 'nav'].includes(value)
+    },
+    // 面板类型 - 新增
+    panelType: {
+      type: String,
+      default: 'calibration'
+    },
+    // v-model 支持
+    value: {
+      type: Boolean,
+      default: true
+    },
+    // 面板是否可见 - 新增(导航页面板控制)
+    visible: {
+      type: Boolean,
+      default: true
+    },
+    // 面板宽度
+    width: {
+      type: Number,
+      default: 360
+    },
+    // 标签页配置 - 支持字符串数组或对象数组
+    tabs: {
+      type: Array,
+      default: () => []
+    },
+    // 初始标签页
+    initialTab: {
+      type: String,
+      default: ''
+    },
+    // 收起后是否保留拉手
+    overlay: {
+      type: Boolean,
+      default: true
+    },
+    // 是否可调整大小
+    resizable: {
+      type: Boolean,
+      default: true
+    },
+    // 面板标题
+    title: {
+      type: String,
+      default: '面板'
+    },
+    // 面板副标题
+    subtitle: {
+      type: String,
+      default: ''
+    },
+    // 是否隐藏头部
+    hideHeader: {
+      type: Boolean,
+      default: false
+    },
+    // 展开提示文本
+    expandTooltip: {
+      type: String,
+      default: '展开面板'
+    },
+    
+    // === 兼容原标定页的props ===
+    laserPositionData: {
+      type: Object,
+      default: () => ({ x: 0, y: 0, angle: 0 })
+    },
+    gnssPositionData: {
+      type: Object,
+      default: () => ({ status: '0/0', longitude: 0, latitude: 0, angle: 0 })
+    },
+    calibrationList: {
+      type: Array,
+      default: () => []
+    },
+    currentMap: {
+      type: Object,
+      default: () => ({ name: 'sh02' })
+    },
+    isDrawerMode: {
+      type: Boolean,
+      default: false
+    },
+    showPoseCard: {
+      type: Boolean,
+      default: true
+    },
+    showCalibrationCard: {
+      type: Boolean,
+      default: true
+    },
+    
+    // === 实时信息相关props ===
+    realtimeInfo: {
+      type: Object,
+      default: () => ({
+        currentMap: 'shanghai',
+        currentTask: '测试任务',
+        speed: '0.35m/s',
+        speedCommand: '0.22m/s',
+        coordinates: '(1.813, -63.931, 0.000)',
+        heading: '-79.6°',
+        totalDistance: '5965352.00m',
+        registrationError: '10.000',
+        batteryLevel: '67%'
+      })
+    },
+    
+    // === 导航页专用props ===
+    waypointList: {
+      type: Array,
+      default: () => []
+    },
+    taskList: {
+      type: Array,
+      default: () => []
+    },
+    settingParams: {
+      type: Object,
+      default: () => ({
+        pointCloud: false,
+        baseMap: true,
+        pointId: false,
+        follow: false,
+        network: false
+      })
+    }
+  },
+  data() {
+    return {
+      activeTab: '',
+      navActiveTab: 'realtime', // 导航页默认激活的tab
+      isResizing: false,
+      startX: 0,
+      startWidth: 0,
+      // 目标点相关状态
+      selectedWaypoints: [], // 选中的目标点
+      mapSelectMode: false // 地图选点模式
+    }
+  },
+  computed: {
+    canAddCalibration() {
+      return this.laserPositionData.x !== 0 || this.laserPositionData.y !== 0
+    },
+
+    // 目标点操作按钮状态
+    waypointSingle() {
+      return this.selectedWaypoints.length !== 1
+    },
+    waypointMultiple() {
+      return this.selectedWaypoints.length === 0
+    },
+    
+    
+    // 处理Tab配置,支持字符串数组和对象数组
+    processedTabs() {
+      const tabMap = {
+        'info': { key: 'info', label: '实时信息' },
+        'settings': { key: 'settings', label: '功能设置' },
+        'task': { key: 'task', label: '任务配置' },
+        'points': { key: 'points', label: '目标点' },
+        'system': { key: 'system', label: '系统状态' }
+      }
+      
+      return this.tabs.map(tab => {
+        if (typeof tab === 'string') {
+          return tabMap[tab] || { key: tab, label: tab }
+        }
+        return tab
+      })
+    }
+  },
+  created() {
+    // 初始化标签页
+    if (this.tabs.length > 0) {
+      const firstTab = this.processedTabs[0]
+      this.activeTab = this.initialTab || (firstTab ? firstTab.key : '')
+    }
+  },
+  mounted() {
+    // 添加全局鼠标事件监听
+    document.addEventListener('mousemove', this.handleResize)
+    document.addEventListener('mouseup', this.stopResize)
+  },
+  beforeDestroy() {
+    document.removeEventListener('mousemove', this.handleResize)
+    document.removeEventListener('mouseup', this.stopResize)
+  },
+  mounted() {
+    // 组件挂载完成
+  },
+  methods: {
+    // 切换面板展开/收起
+    togglePanel() {
+      this.$emit('input', !this.value)
+    },
+    
+    
+    // 展开面板
+    expandPanel() {
+      this.$emit('input', true)
+    },
+    
+    // 标签页切换
+    handleTabClick(tab) {
+      this.activeTab = tab.name
+      this.$emit('tab-change', tab.name)
+    },
+    
+    // 开始拖拽调整大小
+    startResize(event) {
+      if (this.isDrawerMode || !this.resizable) return
+      
+      this.isResizing = true
+      this.startX = event.clientX
+      this.startWidth = this.width
+      document.body.style.cursor = 'col-resize'
+      document.body.style.userSelect = 'none'
+    },
+    
+    // 处理拖拽调整大小
+    handleResize(event) {
+      if (!this.isResizing || this.isDrawerMode) return
+      
+      const diff = this.startX - event.clientX
+      const newWidth = Math.max(320, Math.min(420, this.startWidth + diff))
+      
+      if (newWidth !== this.width) {
+        this.$emit('panel-resize', newWidth)
+      }
+    },
+    
+    // 停止拖拽调整大小
+    stopResize() {
+      if (this.isResizing) {
+        this.isResizing = false
+        document.body.style.cursor = ''
+        document.body.style.userSelect = ''
+      }
+    },
+    
+    // === 兼容原标定页的方法 ===
+    getGnssStatusType(status) {
+      if (status === '0/0') return 'info'
+      if (status.includes('锁定')) return 'success'
+      if (status.includes('异常')) return 'warning'
+      return 'info'
+    },
+    
+    addCalibration() {
+      this.$emit('add-calibration')
+    },
+    
+    removeCalibration(id) {
+      this.$emit('remove-calibration', id)
+    },
+    
+    executeCalibration() {
+      this.$emit('execute-calibration')
+    },
+    
+    // === 导航页专用方法 ===
+    getTaskStatusText(status) {
+      const statusMap = {
+        'idle': '空闲',
+        'running': '运行中',
+        'paused': '暂停',
+        'completed': '已完成',
+        'failed': '失败'
+      }
+      return statusMap[status] || '未知'
+    },
+
+    // 设置项变更处理
+    onSettingChange(settingKey, value) {
+      console.log(`设置项 ${settingKey} 变更为:`, value)
+      this.$emit('setting-change', { key: settingKey, value: value })
+    },
+
+    // === 目标点相关方法 ===
+    
+    // 目标点表格选择变更
+    onWaypointSelectionChange(selection) {
+      this.selectedWaypoints = selection
+      this.$emit('wp-selection-change', selection)
+    },
+
+    // 切换地图选点模式
+    toggleMapSelectMode() {
+      this.mapSelectMode = !this.mapSelectMode
+      this.$emit('map-select-mode-change', this.mapSelectMode)
+    },
+
+
+    // 目标点项点击
+    onWaypointItemClick(waypoint) {
+      // 单击选择/取消选择
+      const isSelected = this.selectedWaypoints.some(w => w.id === waypoint.id)
+      if (isSelected) {
+        this.selectedWaypoints = this.selectedWaypoints.filter(w => w.id !== waypoint.id)
+      } else {
+        this.selectedWaypoints.push(waypoint)
+      }
+      this.$emit('wp-selection-change', this.selectedWaypoints)
+    },
+
+    // 自定义复选框点击处理(完全可控)
+    handleCheckboxClick(waypoint) {
+      console.log('Custom checkbox clicked for waypoint:', waypoint.id)
+      const isSelected = this.selectedWaypoints.some(w => w.id === waypoint.id)
+      console.log('Current selection state:', isSelected, 'Toggling to:', !isSelected)
+      
+      // 直接处理选择状态变更
+      if (isSelected) {
+        // 取消选择
+        this.selectedWaypoints = this.selectedWaypoints.filter(w => w.id !== waypoint.id)
+        console.log('Removed waypoint from selection')
+      } else {
+        // 添加选择
+        this.selectedWaypoints.push(waypoint)
+        console.log('Added waypoint to selection')
+      }
+      
+      // 通知父组件
+      this.$emit('wp-selection-change', this.selectedWaypoints)
+      console.log('Final selection:', this.selectedWaypoints.map(w => w.id))
+      
+      // 强制触发响应式更新
+      this.$forceUpdate()
+    },
+
+    // 清除选择
+    clearSelection() {
+      this.selectedWaypoints = []
+      this.$emit('wp-selection-change', this.selectedWaypoints)
+    },
+
+    // 获取路径类型文本
+    getWaypointTypeText(type) {
+      const typeMap = {
+        0: '自由路径',
+        1: '路网路径'
+      }
+      return typeMap[type] || '未知'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import './_map-shared.scss';
+
+.right-panel-container {
+  position: relative;
+  height: 100%;
+  z-index: inherit;
+}
+
+/* === 标定页专用样式 === */
+.rp--calib {
+  .right-panel {
+    height: 100%;
+    background: #fff;
+    border-radius: 8px;
+    transition: all 0.2s ease;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+    position: relative;
+
+    &.panel-collapsed {
+      opacity: 0;
+      pointer-events: none;
+      overflow: hidden;
+    }
+
+  .panel-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 12px 16px;
+    border-bottom: 1px solid #e4e7ed;
+    background: #fafbfc;
+    flex-shrink: 0;
+
+    .panel-title {
+      h3 {
+        margin: 0;
+        font-size: 16px;
+        font-weight: 600;
+        color: #303133;
+        line-height: 1.4;
+      }
+
+      .panel-subtitle {
+        font-size: 12px;
+        color: #f56c6c;
+        margin-left: 8px;
+      }
+    }
+
+    .collapse-btn {
+      color: #909399;
+      padding: 4px;
+      
+      &:hover {
+        color: #409eff;
+        background-color: #f0f9ff;
+      }
+    }
+  }
+
+  .panel-content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+
+    .default-content {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      padding: $panel-padding;
+      overflow: hidden;
+    }
+
+    .tab-placeholder {
+      padding: var(--spacing-4);
+      text-align: center;
+      color: var(--color-text-tertiary);
+    }
+
+    .info-card {
+      @include info-card-base;
+
+      &:last-child {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        min-height: 0;
+
+        .card-content {
+          flex: 1;
+          overflow-y: auto;
+          @include custom-scrollbar;
+        }
+      }
+
+      .pose-section {
+        margin-bottom: var(--spacing-4);
+
+        &:last-child {
+          margin-bottom: 0;
+        }
+
+        .section-title {
+          font-size: var(--font-size-sm);
+          font-weight: var(--font-weight-medium);
+          color: var(--color-text-tertiary);
+          margin-bottom: var(--spacing-2);
+          padding-bottom: var(--spacing-1);
+          border-bottom: 1px solid var(--color-border-tertiary);
+        }
+
+        .pose-item {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding: var(--spacing-2) 0;
+          border-bottom: 1px solid var(--color-border-tertiary);
+
+          &:last-child {
+            border-bottom: none;
+          }
+
+          .pose-label {
+            font-size: var(--font-size-sm);
+            color: var(--color-text-secondary);
+            font-weight: var(--font-weight-medium);
+          }
+
+          .pose-value {
+            font-size: var(--font-size-sm);
+            color: var(--color-text-primary);
+            font-weight: var(--font-weight-normal);
+            text-align: right;
+          }
+        }
+      }
+
+      .calibration-table {
+        .table-header,
+        .table-row {
+          display: grid;
+          grid-template-columns: 48px 1fr 48px;
+          gap: var(--spacing-2);
+          align-items: center;
+        }
+
+        .table-header {
+          padding: var(--spacing-2) 0;
+          border-bottom: 1px solid var(--color-border-secondary);
+          font-size: var(--font-size-xs);
+          font-weight: var(--font-weight-semibold);
+          color: var(--color-text-tertiary);
+          text-align: center;
+        }
+
+        .table-row {
+          padding: var(--spacing-2) 0;
+          border-bottom: 1px solid var(--color-border-tertiary);
+          font-size: var(--font-size-sm);
+
+          &:last-child {
+            border-bottom: none;
+          }
+
+          &:hover {
+            background: var(--color-bg-secondary);
+          }
+
+          .col-id {
+            text-align: center;
+            font-weight: var(--font-weight-medium);
+            color: var(--color-primary);
+          }
+
+          .col-coord {
+            font-family: var(--font-family-mono);
+            font-size: var(--font-size-xs);
+            color: var(--color-text-secondary);
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+
+          .col-action {
+            text-align: center;
+
+            .delete-btn {
+              color: var(--color-danger);
+              
+              &:hover {
+                color: var(--color-danger-dark);
+              }
+            }
+          }
+        }
+      }
+
+      .action-buttons {
+        display: flex;
+        gap: var(--spacing-2);
+        margin-top: var(--spacing-4);
+
+        .el-button {
+          flex: 1;
+        }
+      }
+
+      .empty-state {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding: var(--spacing-6) var(--spacing-4);
+        color: var(--color-text-quaternary);
+
+        i {
+          font-size: var(--font-size-2xl);
+          margin-bottom: var(--spacing-2);
+          opacity: 0.5;
+        }
+
+        p {
+          margin: 0;
+          font-size: var(--font-size-sm);
+          opacity: 0.8;
+        }
+      }
+    }
+    
+    // 实时信息样式
+    .realtime-info-content {
+      padding: var(--spacing-4);
+      height: 100%;
+      overflow-y: auto;
+      @include custom-scrollbar;
+      
+      .info-section {
+        margin-bottom: var(--spacing-5);
+        
+        &:last-child {
+          margin-bottom: 0;
+        }
+        
+        .info-title {
+          display: flex;
+          align-items: center;
+          color: #8a8a8a;
+          font-size: var(--font-size-base);
+          font-weight: var(--font-weight-semibold);
+          border-bottom: 2px solid #B9B9FF;
+          margin-bottom: var(--spacing-3);
+          padding-bottom: var(--spacing-1);
+          
+          .title-bar {
+            height: 20px;
+            width: 5px;
+            background-color: #6565FC;
+            margin-right: var(--spacing-1);
+            border-radius: 4px 4px 0 0;
+          }
+        }
+        
+        .info-content {
+          color: #5A5A5A;
+          font-size: var(--font-size-sm);
+          margin-left: var(--spacing-2);
+          display: block;
+          margin-bottom: var(--spacing-2);
+        }
+        
+        .info-details {
+          margin-left: var(--spacing-2);
+          
+          .info-item {
+            color: #5A5A5A;
+            font-size: var(--font-size-sm);
+            display: block;
+            margin-bottom: var(--spacing-2);
+            
+            .info-label {
+              font-weight: var(--font-weight-semibold);
+            }
+            
+            .info-value {
+              font-weight: var(--font-weight-normal);
+            }
+          }
+        }
+      }
+    }
+    
+    // Tab内容区域滚动优化
+    ::v-deep .el-tabs {
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+    }
+
+    ::v-deep .el-tabs__header {
+      margin: 0;
+      padding: 0 16px;
+      background: #fff;
+      border-bottom: 1px solid #e4e7ed;
+    }
+    
+    ::v-deep .el-tabs__content {
+      flex: 1;
+      overflow: hidden;
+      padding: 0;
+    }
+    
+    ::v-deep .el-tab-pane {
+      height: 100%;
+      overflow-y: auto;
+      
+      // 自定义滚动条
+      &::-webkit-scrollbar {
+        width: 6px;
+      }
+      
+      &::-webkit-scrollbar-track {
+        background: #f1f1f1;
+        border-radius: 3px;
+      }
+      
+      &::-webkit-scrollbar-thumb {
+        background: #c1c1c1;
+        border-radius: 3px;
+        
+        &:hover {
+          background: #a8a8a8;
+        }
+      }
+    }
+  }
+
+  .resize-handle {
+    position: absolute;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    width: $resize-handle-width;
+    cursor: col-resize;
+    background: transparent;
+    z-index: 10;
+
+    &:hover {
+      background: var(--color-primary);
+      opacity: 0.3;
+    }
+
+    &:active {
+      background: var(--color-primary);
+      opacity: 0.5;
+    }
+  }
+
+  // 标定页Tab内容区域 - 保留留白(和旧样式一致)
+  .nav-tab-content {
+    height: 100%;
+    padding: var(--spacing-4);
+    overflow-y: auto;
+  }
+}
+
+/* === 导航页 info-card 样式(完全复用标定页卡片风格) === */
+.rp--nav {
+  .info-card {
+    /* 与 .rp--calib .info-card 数值完全一致 */
+    background: #fff;
+    border-radius: 8px;                        /* 原封不动复制标定页数值 */
+    box-shadow: 0 2px 8px rgba(0,0,0,0.15);    /* 原封不动复制标定页数值 */
+    overflow: hidden;
+    margin: 0 0 var(--spacing-4);
+
+    .card-header {
+      padding: var(--spacing-3) var(--spacing-4);
+      border-bottom: 1px solid var(--color-border-secondary);
+      background: #f7f9fc;                    /* 标定页 header 的浅灰底 */
+      border-radius: 8px 8px 0 0;             /* 顶部圆角与卡片一致 */
+
+      .card-title {
+        margin: 0;
+        font-size: var(--font-size-base);
+        font-weight: 600;                      /* 与标定页标题字重一致 */
+        color: var(--color-text-primary);
+        display: flex;
+        align-items: center;
+
+        /* 移除左侧竖条,与标定页保持一致 */
+        /* &::before {
+          content: '';
+          width: 4px; 
+          height: 16px;
+          background: var(--color-primary);
+          border-radius: 4px;
+          margin-right: var(--spacing-2);
+        } */
+      }
+    }
+
+    .card-content {
+      padding: 0;                              /* 由行内控制留白 */
+    }
+
+    .pose-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: var(--spacing-2) var(--spacing-4);    /* 原封不动复制标定页数值 */
+      border-bottom: 1px solid var(--color-border-tertiary); /* 原封不动复制标定页边线色 */
+
+      &:last-child { 
+        border-bottom: none; 
+      }
+
+      .pose-label {
+        font-size: var(--font-size-sm);
+        color: var(--color-text-secondary);
+        font-weight: 500;                      /* 与标定页对齐 */
+      }
+
+      .pose-value {
+        font-size: var(--font-size-sm);
+        color: var(--color-text-primary);
+        font-weight: 500;                      /* 标定页是偏"更重"的视觉 */
+        text-align: right;
+        /* 移除等宽字体,使用常规字体与标定页统一 */
+        font-family: inherit;                  /* 使用常规字体,不使用等宽字体 */
+        letter-spacing: .2px;                  /* 轻微字距,读数更稳 */
+      }
+    }
+  }
+}
+
+/* === 标定页 info-card 样式保持不变 === */
+.rp--calib .info-card {
+  /* 统一卡片外观: 若有 mixin 就用 @include */
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
+  overflow: hidden;
+
+  .card-header {
+    padding: var(--spacing-3) var(--spacing-4);
+    border-bottom: 1px solid var(--color-border-secondary);
+    background: var(--color-bg-secondary);
+  }
+
+  .card-title {
+    margin: 0;
+    font-size: var(--font-size-base);
+    font-weight: var(--font-weight-semibold);
+    color: var(--color-text-primary);
+  }
+
+  .card-content {
+    padding: 0;            // 内容行的留白用行内的 pose-item 控制
+  }
+
+  .pose-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: var(--spacing-2) var(--spacing-4);
+    border-bottom: 1px solid var(--color-border-tertiary);
+
+    &:last-child {
+      border-bottom: none;
+    }
+
+    .pose-label {
+      font-size: var(--font-size-sm);
+      color: var(--color-text-secondary);
+      font-weight: var(--font-weight-medium);
+    }
+
+    .pose-value {
+      font-size: var(--font-size-sm);
+      color: var(--color-text-primary);
+      font-weight: var(--font-weight-normal);
+      text-align: right;
+      font-family: var(--font-family-mono);
+    }
+  }
+
+  /* === Tabs 头部与分割线对齐标定页 === */
+  :deep(.el-tabs__header) {
+    margin: 0;
+    background: #fff;                                        /* 与标定页一致 */
+    border-bottom: 1px solid var(--color-border-secondary);  /* 色值同标定页 */
+  }
+
+  :deep(.el-tabs__item) {
+    font-size: var(--font-size-base);
+    color: var(--color-text-secondary);
+
+    &.is-active {
+      color: var(--color-primary);
+      font-weight: 600; /* 与标定页字重一致 */
+    }
+  }
+}
+
+/* === Tabs 容器高度控制(防止内容被再挤) === */
+.rp--nav .nav-tabs {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.rp--nav :deep(.el-tabs__content) {
+  flex: 1;
+  height: 0;
+  overflow: hidden;
+  padding: 0 !important;   // 双保险:即使有人误加全局 padding,也被这里覆盖
+}
+
+.rp--nav :deep(.el-tab-pane) {
+  height: 100%;
+  overflow: auto;
+}
+
+.expand-handle {
+  position: fixed;
+  right: 0;
+  top: 50%;
+  transform: translateY(-50%);
+  z-index: 12;
+  width: 36px;
+  height: 72px;
+  background: var(--color-bg-card);
+  border: 1px solid var(--color-border-primary);
+  border-radius: 8px 0 0 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: var(--color-text-secondary);
+  transition: all $transition-duration $animation-ease;
+  pointer-events: auto;
+
+  &:hover {
+    background: var(--color-primary);
+    color: var(--color-text-inverse);
+    border-color: var(--color-primary);
+    transform: translateY(-50%) translateX(-2px);
+    box-shadow: var(--shadow-xl);
+  }
+
+  i {
+    font-size: var(--font-size-lg);
+    font-weight: bold;
+  }
+}
+
+// 暗色主题适配
+html.dark {
+  .right-panel {
+    @include dark-theme-panel-content;
+  }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .expand-handle {
+    width: 32px;
+    height: 60px;
+  }
+}
+
+/* === 导航页专用样式(命名空间隔离) === */
+.rp--nav {
+  /* 导航页面展开按钮悬浮效果 */
+  .nav-expand-handle:hover {
+    background: var(--color-primary, #409eff) !important;
+    border-color: var(--color-primary, #409eff) !important;
+    transform: translateY(-50%) translateX(-2px) !important;
+    
+    i {
+      color: #ffffff !important;
+    }
+  }
+  
+  .nav-right-panel {
+    position: fixed;
+    right: 16px;
+    top: 100px;
+    width: 380px;
+    height: calc(100vh - 116px);
+    z-index: 1000;
+    transition: transform 0.3s ease;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    
+    /* 与标定页对齐 */
+    background: #fff;
+    border-radius: 8px;                 /* 与 .rp--calib .right-panel 一致 */
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); /* 与 .rp--calib .right-panel 一致 */
+    
+    &.is-hidden {
+      transform: translateX(calc(100% + 16px));
+    }
+    
+    .nav-panel-header {
+      position: relative;
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+    }
+    
+    .nav-panel-close-btn {
+      position: absolute;
+      top: 8px;
+      right: 8px;
+      z-index: 10;
+      padding: 4px;
+      font-size: 14px;
+      color: #909399;
+      
+      &:hover {
+        color: #409eff;
+        background: rgba(64, 158, 255, 0.1);
+      }
+    }
+    
+  }
+  
+  .nav-tabs {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    
+    :deep(.el-tabs__header) {
+      margin: 0;
+      border-bottom: 1px solid var(--color-border-secondary);
+      background: var(--color-bg-secondary);
+      flex-shrink: 0;
+    }
+    
+    :deep(.el-tabs__nav-wrap) {
+      padding: 0 var(--spacing-4);
+    }
+    
+    :deep(.el-tabs__item) {
+      padding: 0 var(--spacing-4);
+      font-size: var(--font-size-base);
+      color: var(--color-text-secondary);
+      line-height: 40px;
+      
+      &.is-active {
+        color: var(--color-primary);
+        font-weight: var(--font-weight-semibold);
+      }
+    }
+    
+    :deep(.el-tabs__content) {
+      flex: 1;
+      height: 0; // 触发flex子项高度计算
+      overflow: hidden;
+    }
+    
+    :deep(.el-tab-pane) {
+      height: 100%;
+      overflow: auto;
+      @include custom-scrollbar;
+    }
+  }
+  
+  .nav-tab-content {
+    height: 100%;
+    padding: 0;              // 关键:保持 0
+    overflow-y: auto;
+  }
+  
+  // 实时信息卡片 - 仿照标定页样式
+  .nav-info-grid {
+    @include info-card-base;
+    margin-bottom: 0;
+    
+    .nav-info-header {
+      padding: var(--spacing-3) var(--spacing-4);
+      border-bottom: 1px solid var(--color-border-secondary);
+      background: var(--color-bg-secondary);
+      
+      .nav-info-title {
+        margin: 0;
+        font-size: var(--font-size-base);
+        font-weight: var(--font-weight-semibold);
+        color: var(--color-text-primary);
+        
+        /* 移除左侧蓝色竖条 */
+        /* &::before {
+          content: '';
+          display: inline-block;
+          width: 4px;
+          height: 16px;
+          background: var(--color-primary);
+          border-radius: var(--radius-sm);
+          margin-right: var(--spacing-2);
+          vertical-align: middle;
+        } */
+      }
+    }
+    
+    .nav-info-content {
+      padding: 0;
+    }
+  }
+  
+  .nav-info-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 36px;
+    padding: 0 var(--spacing-4);
+    border-bottom: 1px solid var(--color-border-tertiary);
+    
+    &:last-child {
+      border-bottom: none;
+    }
+    
+    .label {
+      font-size: var(--font-size-sm);
+      color: var(--color-text-secondary);
+      font-weight: var(--font-weight-normal);
+    }
+    
+    .value {
+      font-size: var(--font-size-sm);
+      color: var(--color-text-primary);
+      text-align: right;
+      font-weight: var(--font-weight-medium);
+      font-family: var(--font-family-mono);
+    }
+  }
+  
+  
+  // 列表头部
+  .nav-list-header {
+    margin-bottom: 16px;
+    
+    .el-input {
+      margin-bottom: 12px;
+    }
+    
+    .nav-header-buttons {
+      display: flex;
+      gap: 8px;
+      
+      .el-button {
+        flex: 1;
+      }
+    }
+  }
+  
+  // 列表内容
+  .nav-list-content {
+    flex: 1;
+    overflow-y: auto;
+    
+    &.nav-list-scrollable {
+      max-height: calc(100vh - 400px); // 限制最大高度,确保有滚动
+      @include custom-scrollbar;
+    }
+  }
+  
+  // 目标点列表 - 参考任务卡片样式
+  .nav-waypoint-list {
+    .nav-waypoint-item {
+      padding: 12px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      margin-bottom: 8px;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      display: flex;
+      align-items: center;
+      
+      &:hover {
+        border-color: #409eff;
+        background: #f0f9ff;
+      }
+      
+      &.selected {
+        border-color: #409eff;
+        background: #f0f9ff;
+      }
+      
+      .waypoint-checkbox {
+        flex-shrink: 0;
+        margin-right: 8px; // 恢复正常边距
+        display: flex !important;
+        align-items: center !important;
+        justify-content: center !important;
+        padding: 8px !important; // 增加内边距,扩大点击区域
+        cursor: pointer !important;
+        border-radius: 4px !important;
+        transition: background-color 0.2s ease !important;
+        position: relative !important; // 确保在其他元素之上
+        z-index: 10 !important; // 提高层级
+        min-width: 32px !important; // 确保最小宽度
+        min-height: 32px !important; // 确保最小高度
+        
+        // 临时调试边框,可以看到实际点击区域(已移除)
+        // border: 1px dashed rgba(64, 158, 255, 0.3) !important;
+        
+        &:hover {
+          background-color: rgba(64, 158, 255, 0.1) !important;
+        }
+        
+        // 确保点击事件能够正确触发
+        &:active {
+          background-color: rgba(64, 158, 255, 0.2) !important;
+          transform: scale(0.98) !important;
+        }
+        
+        // 自定义checkbox样式
+        .custom-checkbox {
+          width: 16px !important;
+          height: 16px !important;
+          border: 2px solid #dcdfe6 !important;
+          border-radius: 3px !important;
+          display: flex !important;
+          align-items: center !important;
+          justify-content: center !important;
+          cursor: pointer !important;
+          transition: all 0.2s ease !important;
+          background: #fff !important;
+          position: relative !important;
+          
+          &:hover {
+            border-color: #409eff !important;
+            box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
+          }
+          
+          &:active {
+            transform: scale(0.95) !important;
+          }
+          
+          // 选中状态
+          &.checked {
+            background-color: #409eff !important;
+            border-color: #409eff !important;
+            
+            i {
+              color: #fff !important;
+              font-size: 10px !important;
+              font-weight: bold !important;
+              line-height: 1 !important;
+            }
+          }
+          
+          // 未选中状态的图标隐藏
+          &:not(.checked) i {
+            display: none !important;
+          }
+        }
+      }
+      
+      .waypoint-info {
+        flex: 1;
+        
+        .waypoint-main {
+          display: flex;
+          flex-direction: column;
+          gap: 4px;
+          
+          .waypoint-id {
+            font-weight: 500;
+            color: #333;
+            font-size: 14px;
+          }
+          
+          .waypoint-coords {
+            font-size: 12px;
+            color: #666;
+            font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
+          }
+        }
+      }
+      
+      .waypoint-actions {
+        display: flex !important;
+        gap: 4px;
+        align-items: baseline !important; // 使用baseline对齐,确保文字基线一致
+        flex-shrink: 0;
+        
+        .action-btn {
+          padding: 2px 6px !important;
+          font-size: 12px !important;
+          height: 24px !important;
+          line-height: 20px !important;
+          display: inline-flex !important;
+          align-items: center !important;
+          justify-content: center !important;
+          margin: 0 !important;
+          border: none !important;
+          background: none !important;
+          vertical-align: baseline !important;
+          
+          &.el-button--text {
+            color: #409eff !important;
+            
+            &:hover {
+              color: #66b1ff !important;
+              background: transparent !important;
+            }
+          }
+        }
+        
+        // 确保popconfirm容器不影响对齐
+        .el-popconfirm__reference {
+          display: inline !important;
+          vertical-align: baseline !important;
+          
+          .action-btn {
+            color: #409eff !important;
+            
+            &:hover {
+              color: #66b1ff !important;
+              background: transparent !important;
+            }
+          }
+        }
+        
+        // 兜底方案:直接选择所有按钮
+        .el-button {
+          padding: 2px 6px !important;
+          font-size: 12px !important;
+          height: 24px !important;
+          line-height: 20px !important;
+          display: inline-flex !important;
+          align-items: center !important;
+          justify-content: center !important;
+          margin: 0 !important;
+          vertical-align: baseline !important;
+          
+          &.el-button--text {
+            color: #409eff !important;
+            
+            &:hover {
+              color: #66b1ff !important;
+              background: transparent !important;
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  // 任务列表
+  .nav-task-list {
+    .nav-task-item {
+      padding: 12px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      margin-bottom: 8px;
+      
+      .task-info {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 8px;
+        
+        .task-name {
+          font-weight: 500;
+          color: #333;
+        }
+        
+        .task-status {
+          display: inline-block;
+          padding: 4px 12px;
+          border-radius: 16px;
+          font-size: 12px;
+          font-weight: 600;
+          text-align: center;
+          min-width: 60px;
+          line-height: 1.2;
+          border: 1px solid transparent;
+          
+          &.status-idle {
+            background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
+            color: #0369a1;
+            border-color: #bae6fd;
+            box-shadow: 0 1px 3px rgba(3, 105, 161, 0.1);
+          }
+          
+          &.status-running {
+            background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
+            color: #15803d;
+            border-color: #bbf7d0;
+            box-shadow: 0 1px 3px rgba(21, 128, 61, 0.1);
+          }
+          
+          &.status-paused {
+            background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
+            color: #d97706;
+            border-color: #fed7aa;
+            box-shadow: 0 1px 3px rgba(217, 119, 6, 0.1);
+          }
+          
+          &.status-completed {
+            background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
+            color: #15803d;
+            border-color: #bbf7d0;
+            box-shadow: 0 1px 3px rgba(21, 128, 61, 0.1);
+          }
+          
+          &.status-failed {
+            background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
+            color: #dc2626;
+            border-color: #fecaca;
+            box-shadow: 0 1px 3px rgba(220, 38, 38, 0.1);
+          }
+        }
+      }
+      
+      .task-actions {
+        display: flex;
+        gap: 4px;
+        
+        .el-button {
+          padding: 2px 6px;
+        }
+      }
+    }
+  }
+  
+  // 空状态
+  .nav-empty-state {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 40px 20px;
+    color: #999;
+    
+    i {
+      font-size: 48px;
+      margin-bottom: 12px;
+      opacity: 0.5;
+    }
+    
+    p {
+      margin: 0;
+      font-size: 14px;
+    }
+  }
+
+  // 功能设置列表
+  .settings-list {
+    padding: 0;
+    
+    .setting-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 16px;
+      border-bottom: 1px solid #f0f0f0;
+      
+      &:last-child {
+        border-bottom: none;
+      }
+      
+      .setting-info {
+        flex: 1;
+        
+        .setting-label {
+          display: block;
+          font-size: 14px;
+          font-weight: 500;
+          color: #333;
+          margin-bottom: 4px;
+        }
+        
+        .setting-desc {
+          display: block;
+          font-size: 12px;
+          color: #666;
+          line-height: 1.4;
+        }
+      }
+      
+      .el-switch {
+        margin-left: 16px;
+      }
+    }
+  }
+
+  // 目标点工具栏样式
+  .waypoint-toolbar {
+    background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
+    border: 1px solid #e2e8f0;
+    border-radius: 12px; // 与右侧卡片风格统一
+    padding: 14px; // 进一步减少内边距,给按钮更多空间
+    margin-bottom: 16px;
+    box-shadow: 0 8px 24px rgba(2, 6, 23, 0.06); // 与右侧卡片阴影统一
+    
+    // 2行3列网格布局
+    .toolbar-grid {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr); // 确保三列完全等宽
+      grid-template-rows: repeat(2, auto); // 两行自适应高度
+      gap: 12px; // 统一间距:行距和列距都是12px
+      width: 100%;
+      
+      // 响应式:窄屏时改为单列布局
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+        gap: 10px;
+      }
+    }
+    
+    // 网格按钮统一样式
+    .grid-btn {
+      width: 100% !important; // 统一宽度,填满网格单元
+      height: 44px !important; // 统一高度
+      min-width: 0 !important; // 防止内容撑开
+      max-width: 100% !important; // 防止超出网格
+      font-size: 12px !important;
+      font-weight: 600 !important;
+      padding: 8px 6px !important; // 减小水平内边距,确保文字不会被挤压
+      margin: 0 !important; // 清除所有外边距
+      border-radius: 8px !important;
+      border-width: 1px !important; // 统一边框宽度
+      display: flex !important;
+      flex-direction: column !important;
+      align-items: center !important;
+      justify-content: center !important;
+      gap: 3px !important; // 稍微减小图标和文字间距
+      text-align: center !important;
+      transition: all 0.2s ease !important;
+      box-sizing: border-box !important;
+      flex-shrink: 0 !important; // 防止收缩
+      flex-grow: 0 !important; // 防止拉伸
+      
+      // 图标样式
+      i {
+        font-size: 15px !important; // 稍微减小图标,保持平衡
+        line-height: 1 !important;
+        display: block !important; // 使用block确保完全居中
+        text-align: center !important;
+        width: 100% !important;
+        margin: 0 auto !important; // 水平居中
+      }
+      
+      // 文字样式
+      span {
+        font-size: 11px !important;
+        line-height: 1.2 !important; // 稍微增加行高,提高可读性
+        font-weight: 600 !important;
+        white-space: nowrap !important;
+        overflow: hidden !important;
+        text-overflow: ellipsis !important;
+        max-width: 100% !important;
+        text-align: center !important;
+        display: block !important; // 使用block确保完全居中
+        width: 100% !important;
+        margin: 0 auto !important; // 水平居中
+      }
+      
+      // 按钮类型样式增强
+      &.el-button--primary {
+        background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
+        border: 1px solid #2563eb !important;
+        color: white !important;
+        box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3) !important;
+        
+        &:hover:not(:disabled) {
+          background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
+          transform: translateY(-1px) !important;
+          box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4) !important;
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0) !important;
+        }
+      }
+      
+      &.el-button--danger {
+        background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
+        border: 1px solid #dc2626 !important;
+        color: white !important;
+        box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3) !important;
+        
+        &:hover:not(:disabled) {
+          background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important;
+          transform: translateY(-1px) !important;
+          box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4) !important;
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0) !important;
+        }
+      }
+      
+      &.el-button--warning {
+        background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%) !important;
+        border: 1px solid #d97706 !important;
+        color: white !important;
+        box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3) !important;
+        
+        &:hover:not(:disabled) {
+          background: linear-gradient(135deg, #d97706 0%, #b45309 100%) !important;
+          transform: translateY(-1px) !important;
+          box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4) !important;
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0) !important;
+        }
+      }
+      
+      &.el-button--success {
+        background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
+        border: 1px solid #059669 !important;
+        color: white !important;
+        box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3) !important;
+        
+        &:hover:not(:disabled) {
+          background: linear-gradient(135deg, #059669 0%, #047857 100%) !important;
+          transform: translateY(-1px) !important;
+          box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4) !important;
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0) !important;
+        }
+      }
+      
+      &.el-button--info {
+        background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
+        border: 1px solid #2563eb !important;
+        color: white !important;
+        box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3) !important;
+        
+        &:hover:not(:disabled) {
+          background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
+          transform: translateY(-1px) !important;
+          box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4) !important;
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0) !important;
+        }
+      }
+      
+      // 禁用状态
+      &.is-disabled {
+        opacity: 0.5 !important;
+        cursor: not-allowed !important;
+        transform: none !important;
+        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+        
+        &:hover {
+          transform: none !important;
+          box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+        }
+      }
+    }
+
+
+  // 快捷操作栏样式
+  .waypoint-quick-actions {
+    position: sticky;
+    bottom: 0;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    color: white;
+    padding: 12px;
+    border-radius: 8px;
+    margin-top: 12px;
+    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
+    
+    .quick-actions-info {
+      font-size: 13px;
+      margin-bottom: 8px;
+      font-weight: 500;
+    }
+    
+    .quick-actions-buttons {
+      display: flex;
+      gap: 8px;
+      
+      .el-button {
+        flex: 1;
+        border: 1px solid rgba(255, 255, 255, 0.3);
+        background: rgba(255, 255, 255, 0.1);
+        color: white;
+        
+        &:hover {
+          background: rgba(255, 255, 255, 0.2);
+          border-color: rgba(255, 255, 255, 0.5);
+        }
+        
+        &.el-button--warning {
+          background: #f56c6c;
+          border-color: #f56c6c;
+          
+          &:hover {
+            background: #f78989;
+            border-color: #f78989;
+          }
+        }
+        
+        &.el-button--success {
+          background: #67c23a;
+          border-color: #67c23a;
+          
+          &:hover {
+            background: #85ce61;
+            border-color: #85ce61;
+          }
+        }
+      }
+    }
+  }
+}
+
+.empty-hint {
+    font-size: 12px;
+    color: #999;
+    margin-top: 8px;
+  }
+}
+</style>
+

+ 190 - 0
src/views/map/maplist/components/shared/_map-shared.scss

@@ -0,0 +1,190 @@
+// 地图组件共用样式变量和混合
+
+// Z-Index层级
+$map-z-index-base: 1;
+$map-z-index-toolbar: 11;
+$map-z-index-panel: 10;
+$map-z-index-expand-btn: 12;
+
+// 尺寸规格
+$toolbar-width: 60px;
+$toolbar-btn-size: 36px;
+$toolbar-btn-size-sm: 32px;
+$panel-width-default: 360px;
+$panel-width-min: 320px;
+$panel-width-max: 420px;
+$resize-handle-width: 8px;
+
+// 间距
+$toolbar-gap: 8px;
+$toolbar-padding: 12px;
+$panel-padding: var(--spacing-4);
+$card-margin-bottom: 16px;
+
+// 圆角
+$toolbar-border-radius: var(--radius-lg);
+$panel-border-radius: var(--radius-lg);
+$btn-border-radius: 50%;
+
+// 阴影
+$toolbar-shadow: var(--shadow-lg);
+$panel-shadow: var(--shadow-xl);
+$btn-hover-shadow: var(--shadow-md);
+
+// 动画时长
+$transition-duration: var(--duration-200);
+$animation-ease: var(--ease-out);
+
+// 混合:工具栏按钮基础样式
+@mixin toolbar-btn-base {
+  width: $toolbar-btn-size !important;
+  height: $toolbar-btn-size !important;
+  min-width: $toolbar-btn-size !important;
+  min-height: $toolbar-btn-size !important;
+  border-radius: $btn-border-radius !important;
+  border: 1px solid var(--color-border-secondary);
+  background: var(--color-bg-card);
+  color: var(--color-text-secondary);
+  transition: all $transition-duration $animation-ease;
+  display: flex !important;
+  align-items: center !important;
+  justify-content: center !important;
+  padding: 0 !important;
+  margin: 0 !important;
+  flex-shrink: 0;
+
+  &:hover {
+    background: var(--color-bg-tertiary);
+    color: var(--color-text-primary);
+    border-color: var(--color-border-primary);
+    transform: translateY(-1px);
+    box-shadow: $btn-hover-shadow;
+  }
+
+  &:active {
+    transform: translateY(0);
+    box-shadow: var(--shadow-sm);
+  }
+
+  &:disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+    transform: none;
+    
+    &:hover {
+      background: var(--color-bg-card);
+      color: var(--color-text-secondary);
+      border-color: var(--color-border-secondary);
+      transform: none;
+      box-shadow: none;
+    }
+  }
+}
+
+// 混合:主要按钮样式
+@mixin toolbar-btn-primary {
+  background: var(--color-primary) !important;
+  color: var(--color-text-inverse) !important;
+  border-color: var(--color-primary) !important;
+
+  &:hover {
+    background: var(--color-primary-light) !important;
+    border-color: var(--color-primary-light) !important;
+  }
+
+  &:disabled {
+    background: var(--color-text-quaternary) !important;
+    border-color: var(--color-text-quaternary) !important;
+    color: var(--color-text-inverse) !important;
+    opacity: 0.6;
+    cursor: not-allowed;
+    transform: none;
+    box-shadow: none;
+  }
+}
+
+// 混合:卡片基础样式
+@mixin info-card-base {
+  background: var(--color-bg-card);
+  border-radius: $panel-border-radius;
+  box-shadow: var(--shadow-card);
+  margin-bottom: $card-margin-bottom;
+  overflow: hidden;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+
+  .card-header {
+    padding: var(--spacing-3) var(--spacing-4);
+    border-bottom: 1px solid var(--color-border-secondary);
+    background: var(--color-bg-secondary);
+
+    .card-title {
+      margin: 0;
+      font-size: var(--font-size-base);
+      font-weight: var(--font-weight-semibold);
+      color: var(--color-text-primary);
+    }
+  }
+
+  .card-content {
+    padding: var(--spacing-4);
+  }
+}
+
+// 混合:自定义滚动条
+@mixin custom-scrollbar {
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: var(--color-bg-tertiary);
+    border-radius: var(--radius-full);
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: var(--color-border-primary);
+    border-radius: var(--radius-full);
+    
+    &:hover {
+      background: var(--color-text-quaternary);
+    }
+  }
+}
+
+// 混合:暗色主题适配 - 注意:这些混合需要在具体选择器内部使用
+@mixin dark-theme-toolbar-content {
+  background: rgba(31, 41, 55, 0.9);
+  border-color: var(--color-border-tertiary);
+
+  .toolbar-btn {
+    background: var(--color-bg-tertiary);
+    border-color: var(--color-border-tertiary);
+
+    &:hover {
+      background: var(--color-bg-quaternary);
+      border-color: var(--color-border-secondary);
+    }
+  }
+
+  .toolbar-divider {
+    background: var(--color-border-tertiary);
+  }
+}
+
+@mixin dark-theme-panel-content {
+  .panel-header {
+    background: var(--color-bg-quaternary);
+  }
+
+  .info-card {
+    background: var(--color-bg-tertiary);
+    box-shadow: var(--shadow-card);
+
+    .card-header {
+      background: var(--color-bg-quaternary);
+    }
+  }
+}

+ 4 - 0
src/views/map/maplist/components/shared/index.js

@@ -0,0 +1,4 @@
+import MapToolbar from './MapToolbar.vue'
+import RightPanel from './RightPanel.vue'
+
+export { MapToolbar, RightPanel }

+ 1 - 1
src/views/map/maplist/edit.vue

@@ -503,7 +503,7 @@
 import OlMap from "@/components/OlMap";
 
 export default {
-	name: "Edit",
+	name: "EditPage",
 	components: {
 		OlMap
 	},

+ 8 - 2
src/views/map/maplist/index.vue

@@ -992,12 +992,18 @@ export default {
 
     // 导航
     handleNavigation(id) {
-      this.$router.push(`/map/navigation?id=${id}`)
+      this.$router.push({
+        name: 'MapNavigation',
+        params: { mapId: id }
+      })
     },
 
     // 编辑
     handleEdit(id) {
-      this.$router.push(`/map/edit?id=${id}`)
+      this.$router.push({
+        name: 'MapEdit',
+        params: { mapId: id }
+      })
     },
 
     // 表格操作方法

+ 2419 - 984
src/views/map/maplist/navigation.vue

@@ -1,984 +1,2419 @@
-<template>
-	<div class="main">
-		<el-row>
-			<el-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1" style="position: relative;">
-				<div class="main-menu">
-					<div class="img-container" :class="{ 'active': activeIndex === 0 }" @click="openDraSetting"><img
-							src="@/assets/icons/img/setting.png" class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">功能</span>
-					</div>
-					<div class="img-container" :class="{ 'active': activeIndex === 1 }" @click="openPoint"><img
-							src="@/assets/icons/img/post.png" class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">目标点</span>
-					</div>
-					<div class="img-container" :class="{ 'active': activeIndex === 2 }" @click="openTask"><img
-							src="@/assets/icons/img/task.png" class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">任务</span>
-					</div>
-					<div class="img-container" :class="{ 'active': activeIndex === 3 }" @click="initNavigation"><img
-							src="@/assets/icons/img/init.png" class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">初始化</span>
-					</div>
-					<div class="img-container" @click="restNavigation"><img src="@/assets/icons/img/restart.png"
-							class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">重启</span>
-					</div>
-					<div class="img-container" @click="offNavigation"><img src="@/assets/icons/img/off.png"
-							class="notification__image" width="22px" height="22px" />
-						<span class="notification__title">结束</span>
-					</div>
-				</div>
-				<!-- 功能设置 -->
-				<div class="drawer" v-show="settingDrawer" style="width: 200px;">
-					<div style="position: relative;">
-						<p>点云</p>
-						<el-radio-group v-model="settingParams.pointCloud" size="mini">
-							<el-radio-button :label="true">开</el-radio-button>
-							<el-radio-button :label="false">关</el-radio-button>
-						</el-radio-group>
-						<p>底图</p>
-						<el-radio-group v-model="settingParams.baseMap" size="mini">
-							<el-radio-button :label="true">开</el-radio-button>
-							<el-radio-button :label="false">关</el-radio-button>
-						</el-radio-group>
-						<p>点ID</p>
-						<el-radio-group v-model="settingParams.pointId" size="mini">
-							<el-radio-button :label="true">开</el-radio-button>
-							<el-radio-button :label="false">关</el-radio-button>
-						</el-radio-group>
-						<p>位置跟随</p>
-						<el-radio-group v-model="settingParams.follow" size="mini">
-							<el-radio-button :label="true">开</el-radio-button>
-							<el-radio-button :label="false">关</el-radio-button>
-						</el-radio-group>
-						<p>网络邻居</p>
-						<el-radio-group v-model="settingParams.network" size="mini">
-							<el-radio-button :label="true">开</el-radio-button>
-							<el-radio-button :label="false">关</el-radio-button>
-						</el-radio-group>
-					</div>
-					<div class="drawer-close" @click="closeDra('hand')"><i class="el-icon-close"></i></div>
-				</div>
-				<!-- 目标点 -->
-				<div class="drawer" v-show="pointDrawer" style="width: 450px;">
-					<div style="position: relative;">
-						<div style="width: 100%;margin-bottom: 10px;">
-							<!-- <el-tooltip class="item" effect="dark" content="将点位显示在地图上" placement="top">
-								<el-button type="primary" icon="el-icon-search" size="mini" :disabled="multiple"></el-button>
-							</el-tooltip> -->
-							<el-tooltip class="item" effect="dark" content="上移" placement="top">
-								<el-button type="primary" icon="el-icon-top" size="mini" :disabled="single" @click="moveUp"></el-button>
-							</el-tooltip>
-							<el-tooltip class="item" effect="dark" content="下移" placement="top">
-								<el-button type="primary" icon="el-icon-bottom" size="mini" :disabled="single"
-									@click="moveDown"></el-button>
-							</el-tooltip>
-							<el-popconfirm title="批量删除选中点位数据?" @confirm="removePoint">
-								<el-button type="danger" icon="el-icon-delete" size="mini" :disabled="multiple" slot="reference"
-									style="margin-left: 10px;"></el-button>
-							</el-popconfirm>
-						</div>
-						<el-table ref="multipleTable" :data="pointList" tooltip-effect="dark" style="width: 100%" max-height="200px"
-							@selection-change="handleSelectionChange" border>
-							<el-table-column type="selection" width="45" align="center">
-							</el-table-column>
-							<el-table-column label="编号" width="60" show-overflow-tooltip align="center">
-								<template slot-scope="scope">{{ scope.row.id }}</template>
-							</el-table-column>
-							<el-table-column label="x坐标" width="90" show-overflow-tooltip align="center">
-								<template slot-scope="scope">{{ scope.row.x }}</template>
-							</el-table-column>
-							<el-table-column label="y坐标" width="90" show-overflow-tooltip align="center">
-								<template slot-scope="scope">{{ scope.row.y }}</template>
-							</el-table-column>
-							<el-table-column label="操作" show-overflow-tooltip align="center">
-								<template slot-scope="scope">
-									<el-button size="mini" type="text" icon="el-icon-edit" @click="editPoint(scope.row)"
-										style="margin-right: 10px;">编辑</el-button>
-									<el-popconfirm title="删除当前点位数据?" @confirm="removePoint(scope.row)">
-										<el-button size="mini" type="text" icon="el-icon-edit" slot="reference">删除</el-button>
-									</el-popconfirm>
-								</template>
-							</el-table-column>
-						</el-table>
-						<div style="width: 100%;margin-top: 10px;">
-							<el-button type="warning" icon="el-icon-caret-right" size="mini" :disabled="single">立即前往</el-button>
-							<el-button type="success" icon="el-icon-folder-add" size="mini" :disabled="multiple"
-								@click="taskGenerateDiaShow = true">生成任务</el-button>
-							<el-button type="success" icon="el-icon-thumb" size="mini" @click="mapSelectEle('open')"
-								v-if="!pointSelectionEnabled">地图选点模式</el-button>
-							<el-button type="danger" icon="el-icon-thumb" size="mini" @click="mapSelectEle('close')"
-								v-else>关闭选点模式</el-button>
-						</div>
-					</div>
-					<div class="drawer-close" @click="closeDra('hand')"><i class="el-icon-close"></i></div>
-				</div>
-				<!-- 任务 -->
-				<div class="drawer" v-if="taskDrawer" style="width: 300px;">
-					<div style="position: relative;">
-						<el-empty description="暂无创建的任务!" v-if="taskDataList.length < 1"></el-empty>
-						<el-collapse v-else>
-							<el-collapse-item v-for="(item, index) in taskDataList" :name="index" :key="item.taskId">
-								<template slot="title"><span>任务名:{{ item.taskName }}</span>
-									<el-tag type="info" v-if="item.status == 1" size="mini" class="task-status-tag">空闲中</el-tag><el-tag
-										type="success" v-else size="mini" class="task-status-tag">执行中</el-tag>
-								</template>
-								<div class="collapse-content-div">
-									<el-button type="danger" size="mini" icon="el-icon-delete"
-										@click="removeTaskItem(item)">删除</el-button>
-									<el-button type="warning" size="mini" icon="el-icon-view">查看</el-button>
-									<el-button type="success" size="mini" icon="el-icon-caret-right" :disabled="item.status == 0"
-										@click="executeTask(item)">执行</el-button>
-								</div>
-							</el-collapse-item>
-						</el-collapse>
-					</div>
-					<div class="drawer-close" @click="closeDra('hand')" style="right: 1px;top: 1px;"><i class="el-icon-close"></i>
-					</div>
-				</div>
-			</el-col>
-			<el-col :xs="23" :sm="23" :md="23" :lg="23" :xl="23">
-				<div class="main-content">
-					<!-- 当前操作类型标记 -->
-					<div class="hand-ment-mark">
-						<el-tag type="danger" effect="dark" size="mini" v-if="nowHandMenu">{{ nowHandMenu }}</el-tag>
-					</div>
-					<OlMap ref="olmap" :width="olWidth + 'px'" :height="olHeight + 'px'" backgroundColor="#F5F5F5" :mapName="mapName"
-						:pointSwitch="settingParams.pointId" :baseLayerShow="settingParams.baseMap" :robotPoseData="laserPositionData"
-						:pointSelectionEnabled="pointSelectionEnabled" :poseInitEnable="poseInitEnable" @addNowPoint="addNowPoint"
-						:isRobotFollow="settingParams.follow" @initNavigationResult="initNavigationResult"></OlMap>
-				</div>
-			</el-col>
-		</el-row>
-		<el-dialog title="目标点编辑" :visible.sync="pointEditDiaShow" width="360px">
-			<el-row>
-				<span class="point-edit-span">x坐标(m)</span><el-input v-model="pointEditData.x" placeholder="请输入x坐标" size="mini"
-					class="point-edit-input"></el-input>
-			</el-row>
-			<span class="point-edit-span">y坐标(m)</span><el-input v-model="pointEditData.y" placeholder="请输入y坐标"
-				size="mini"></el-input>
-			<span class="point-edit-span">规划类型</span><el-select v-model="pointEditData.type" placeholder="请选择" size="mini">
-				<el-option v-for="item in planOptions" :key="item.value" :label="item.label" :value="item.value">
-				</el-option>
-			</el-select>
-			<span class="point-edit-span">添加动作</span>
-			<div v-for="(item, index) in pointEditData.actionMenuList" style="margin-bottom: 8px;" class="action-menu">
-				<el-select v-model="item.value" placeholder="请选择" size="mini" @change="changeAction(index)">
-					<el-option v-for="item in actionOptions" :key="item.value" :label="item.label" :value="item.value">
-					</el-option>
-				</el-select>
-				<el-tooltip class="item" effect="dark" content="输入等待时间(秒)" placement="top">
-					<el-input v-model="item.other" placeholder="时间(秒)" size="mini" style="width: 60px;margin-left: 5px;"
-						class="action-menu_input" v-if="'other' in item"></el-input>
-				</el-tooltip>
-				<el-button type="info" icon="el-icon-plus" circle size="mini" style="margin-left: 5px;padding: 5px;"
-					@click="appendActionMenu"></el-button>
-				<el-button type="info" icon="el-icon-minus" circle size="mini" style="margin-left: 5px;padding: 5px;"
-					@click="removeActionMenu(index)" v-if="index > 0"></el-button>
-			</div>
-			<span slot="footer" class="dialog-footer">
-				<el-button @click="pointEditDiaShow = false">取 消</el-button>
-				<el-button type="primary" @click="submitEditPoint">确 定</el-button>
-			</span>
-		</el-dialog>
-		<el-dialog title="创建任务" :visible.sync="taskGenerateDiaShow" width="400px">
-			<el-row>
-				<span class="point-edit-span">任务名称</span><el-input v-model="generateTaskParam.taskName" placeholder="请输入任务名"
-					size="mini" class="point-edit-input" style="width: 50%;"></el-input>
-				<span class="point-edit-span">执行次数</span><el-input-number v-model="generateTaskParam.count"
-					controls-position="right" :min="1" :max="100" size="mini" style="width: 50%;"></el-input-number>
-				<span class="point-edit-span">开始时间</span><el-time-picker v-model="generateTaskParam.time" :picker-options="{
-					selectableRange: '00:00:00 - 23:59:59'
-				}" placeholder="选择时间" size="mini">
-				</el-time-picker>
-				<span class="point-edit-span">执行日期</span>
-				<el-checkbox-group v-model="generateTaskParam.date" style="margin-bottom: 10px;">
-					<el-checkbox label="1">周一</el-checkbox>
-					<el-checkbox label="2">周二</el-checkbox>
-					<el-checkbox label="3">周三</el-checkbox>
-					<el-checkbox label="4">周四</el-checkbox>
-					<el-checkbox label="5">周五</el-checkbox>
-					<el-checkbox label="6">周六</el-checkbox>
-					<el-checkbox label="7">周日</el-checkbox>
-				</el-checkbox-group>
-			</el-row>
-			<span slot="footer" class="dialog-footer">
-				<el-button @click="closeTaskGenerate()">取 消</el-button>
-				<el-button type="primary" @click="submitTaskGenerate">确 定</el-button>
-			</span>
-		</el-dialog>
-		<div class="info-dra-class-all">
-			<el-drawer title="实时信息" :visible.sync="infoDrawer" :direction="'rtl'" :modal="false" :size="'100%'"
-				:wrapperClosable="false" custom-class="navigation-info-dra-class" :modal-append-to-body="false">
-				<div class="info-dra-class_content">
-					<div style="margin-bottom: 20px;">
-						<div class="info-dra_title">
-							<div
-								style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
-							</div><span>当前地图</span>
-						</div>
-						<span class="info-dra_content">{{mapName}}</span>
-					</div>
-					<div style="margin-bottom: 20px;">
-						<div class="info-dra_title">
-							<div
-								style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
-							</div><span>当前任务</span>
-						</div>
-						<span class="info-dra_content">测试任务</span>
-					</div>
-					<div style="margin-bottom: 20px;">
-						<div class="info-dra_title">
-							<div
-								style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
-							</div><span>实时信息</span>
-						</div>
-						<span class="info-dra_content info-dra_content_title">速度: <span
-								class="info-dra_content_other">0.35m/s</span></span>
-						<span class="info-dra_content info-dra_content_title">速度指令: <span
-								class="info-dra_content_other">0.22m/s</span></span>
-						<span class="info-dra_content info-dra_content_title">坐标: <span class="info-dra_content_other">(1.813,
-								-63.931,
-								0.000)</span></span>
-						<span class="info-dra_content info-dra_content_title">航向: <span
-								class="info-dra_content_other">-79.6°</span></span>
-						<span class="info-dra_content info-dra_content_title">累计里程: <span
-								class="info-dra_content_other">5965352.00m</span></span>
-						<span class="info-dra_content info-dra_content_title">配准误差: <span
-								class="info-dra_content_other">10.000</span></span>
-						<span class="info-dra_content info-dra_content_title">电量: <span
-								class="info-dra_content_other">67%</span></span>
-					</div>
-				</div>
-			</el-drawer>
-		</div>
-		<!-- 展开抽屉 -->
-		<div class="fixed-right-center" @click="showInfoDra" v-if="!infoDrawer">
-			<i class="el-icon-arrow-left"></i>
-		</div>
-		<MqttComp ref="mqtt" :topics="topics" @message-received="onMessage" />
-	</div>
-</template>
-
-<script>
-import OlMap from "@/components/OlMap";
-import MqttComp from "@/components/Mqtt/mqttComp.vue";
-export default {
-	name: "Navigation",
-	components: {
-		OlMap,
-		MqttComp
-	},
-	data() {
-		return {
-			topics:[
-				{ topic: this.$mqttPrefix+'/localization/action/init/reply', qos: 2, retain: false },
-				{ topic:this.$mqttPrefix + '/localization/pose'}
-				],
-			activeIndex: -1, // 默认为没有激活的项
-			settingDrawer: false,
-			pointDrawer: false,
-			taskDrawer: false,
-			infoDrawer: true,
-			pointEditDiaShow: false,
-			taskGenerateDiaShow: false,
-			// 是否开启地图选点
-			pointSelectionEnabled: false,
-			// 是否开启位置初始化功能
-			poseInitEnable: false,
-			// 功能设置参数
-			settingParams: {
-				pointCloud: false,
-				baseMap: true,
-				pointId: false,
-				follow: false,
-				network: false
-			},
-			// 非单个禁用
-			single: true,
-			// 非多个禁用
-			multiple: true,
-			taskDataList: [],
-			// 目标点的编辑数据
-			pointEditData: {
-				id: '',
-				x: '',
-				y: '',
-				type: '',
-				// 添加动作菜单列表 (other:追加参数,例如原定等待选项的等待时间)
-				actionMenuList: []
-			},
-			// 生成任务的参数
-			generateTaskParam: {
-				taskId: '',
-				taskName: '',
-				count: 1,
-				time: '',
-				date: []  // 1-7分别指代周一到周末
-			},
-			// 点位列表
-			pointList: [],
-			pointIds: [],
-			// 路径类型
-			planOptions: [
-				{ label: '自由路径', value: 0 },
-				{ label: '路网路径', value: 1 }
-			],
-			// 动作类型
-			actionOptions: [
-				{ label: '原地等待', value: 0 },
-				{ label: '开始录制', value: 1 },
-				{ label: '结束录制', value: 2 },
-				{ label: '添加建图轨迹', value: 3 },
-				{ label: '挂钩挂载', value: 4 },
-				{ label: '挂钩卸载', value: 5 }
-			],
-			olWidth: 0,  // 用于存储宽度的变量
-			olHeight: 0,
-			nowHandMenu: '',
-			mapName: this.$route.params.mapName || '',  // 地图名称
-			// 激光定位数据
-			laserPositionData: {
-        x: 0,
-        y: 0,
-        angle: 0
-      },
-		};
-	},
-	created() {
-
-	},
-	mounted() {
-		// const mapId = this.$route.params.mapId;	
-		this.updateOlCss();
-		window.addEventListener('resize', this.updateOlCss);
-	},
-	beforeDestroy() {
-		window.removeEventListener('resize', this.updateOlCss);
-	},
-	methods: {
-		onMessage({ topic, message }) {
-        // console.log("收到消息:", topic, message);
-				if (topic === this.$mqttPrefix + '/localization/action/init/reply') {
-					this.handleInitReply(message);
-				} else if (topic === this.$mqttPrefix + '/localization/pose') {
-					this.handleLaserPose(message);
-				}
-    },
-		handleInitReply(message) {
-			// 处理初始化回复消息
-			console.log("初始化回复:", message);
-			
-		},
-		handleLaserPose(message) {
-			try {
-        const data = message.args[0];
-        const {xyz, rpy, blh, heading} = data.pose;
-        // 激光定位实时数据
-        this.laserPositionData.x = xyz[0];
-        this.laserPositionData.y = xyz[1];
-        this.laserPositionData.angle = rpy[2];
-        // GNSS定位实时数据
-        /* this.gnssPositionData.longitude = blh[1]; // 经度
-        this.gnssPositionData.latitude = blh[0]; // 纬度
-        this.gnssPositionData.angle = heading; // 航向角
-        
-        this.gnssPositionData.status = data.rtk.star+ '/' + data.rtk.status; // RTK状态 */
-        
-      } catch (e) {
-        console.error("解析失败:", e);
-      }
-		},
-		publishMsg() {
-        
-    },
-		updateOlCss() {
-			const element = this.$el.querySelector('.main-content');
-			this.olWidth = element.offsetWidth;
-			this.olHeight = element.offsetHeight;
-		},
-		openDraSetting() {
-			this.poseInitEnable = false;
-			this.activeIndex = this.activeIndex == 0 ? -1 : 0;
-			if (this.settingDrawer) {
-				this.nowHandMenu = ''
-				this.settingDrawer = false;
-				return;
-			}
-			this.closeDra()
-			this.nowHandMenu = '功能菜单操作'
-			this.settingDrawer = true;
-		},
-		openPoint() {
-			this.poseInitEnable = false
-			this.activeIndex = this.activeIndex == 1 ? -1 : 1;
-			if (this.pointDrawer) {
-				this.pointDrawer = false;
-				this.nowHandMenu = ''
-				return;
-			}
-			this.closeDra()
-			this.nowHandMenu = '目标点操作'
-			this.pointDrawer = true;
-		},
-		openTask() {
-			this.poseInitEnable = false
-			this.activeIndex = this.activeIndex == 2 ? -1 : 2;
-			if (this.taskDrawer) {
-				this.taskDrawer = false;
-				this.nowHandMenu = ''
-				return;
-			}
-			this.closeDra()
-			this.nowHandMenu = '任务操作'
-			this.taskDrawer = true;
-		},
-		/**
-		 * 关闭左侧菜单的抽屉
-		 * type 类型(hand手动,auto自动)
-		 */
-		closeDra(type) {
-			this.settingDrawer = false;
-			this.pointDrawer = false;
-			this.taskDrawer = false;
-			if (type == 'hand') {
-				this.activeIndex = -1;
-			}
-			this.nowHandMenu = ''
-		},
-		handleSelectionChange(selection) {
-			this.pointIds = selection.map(item => item.id)
-			this.single = selection.length !== 1
-			this.multiple = !selection.length
-		},
-		// 点位编辑
-		editPoint(row) {
-			this.pointEditDiaShow = true;
-			this.pointEditData.id = row.id;
-			this.pointEditData.x = row.x;
-			this.pointEditData.y = row.y;
-			this.pointEditData.type = row.type;
-			this.pointEditData.actionMenuList = row.action
-		},
-		// 点位删除
-		removePoint(row) {
-			const idArr = [];
-			const ids = row?.id || this.pointIds;
-			if (ids) {
-				idArr.push(...(Array.isArray(ids) ? ids : [ids]));
-				idArr.forEach(id => {
-					let indexToRemove = this.pointList.findIndex(item => item?.id === id);
-					if (indexToRemove !== -1) {
-						this.pointList.splice(indexToRemove, 1);
-						if (this.pointList.length < 1) {
-							// 重置地图的id计数器
-							this.$refs.olmap.restIdNum();
-						}
-						this.$refs.olmap.removeIconHtmlById("pose-" + id);
-					}
-				});
-			}
-		},
-		// 点位上移
-		moveUp() {
-			const index = this.pointList.findIndex(point => point.id == this.pointIds[0]);
-			if (index !== -1 && index > 0) {
-				let temp = this.pointList[index];
-				this.$set(this.pointList, index, this.pointList[index - 1]);
-				this.$set(this.pointList, index - 1, temp);
-			}
-		},
-		// 点位下移
-		moveDown() {
-			const index = this.pointList.findIndex(point => point.id == this.pointIds[0]);
-			if (index !== -1 && index < this.pointList.length - 1) {
-				let temp = this.pointList[index];
-				this.$set(this.pointList, index, this.pointList[index + 1]);
-				this.$set(this.pointList, index + 1, temp);
-			}
-		},
-		// 追加动作按钮
-		appendActionMenu() {
-			this.pointEditData.actionMenuList.push({ value: 0, other: 0 })
-		},
-		// 删除追加动作按钮
-		removeActionMenu(index) {
-			this.pointEditData.actionMenuList.splice(index, 1);
-		},
-		// 修改动作下拉值
-		changeAction(index) {
-			// 判断当前修改后是否是原定等待,如果不是则删除other属性
-			let item = this.pointEditData.actionMenuList[index];
-			if (item && 'other' in item) {
-				delete item.other;  // 删除 'other' 属性
-			} else {
-				item.other = 0;
-			}
-		},
-		clearActionDia() {
-			this.pointEditData.id = '';
-			this.pointEditData.x = '';
-			this.pointEditData.y = '';
-			this.pointEditData.type = '';
-			this.pointEditData.actionMenuList = [];
-		},
-		// 提交点位修改
-		submitEditPoint() {
-			this.pointEditDiaShow = false;
-			// 模拟数据修改
-			const point = this.pointList.find(item => item.id === this.pointEditData.id);
-			if (this.pointEditData.actionMenuList)
-				if (point) {
-					// 找到对应元素,更新数据(真实情况下发请求修改,然后重新查询点位列表)
-					point.x = this.pointEditData.x;
-					point.y = this.pointEditData.y;
-					point.type = this.pointEditData.type;
-					point.action = this.pointEditData.actionMenuList;
-					this.$modal.msgSuccess("当前点位数据已修改");
-				}
-		},
-		// 生成任务
-		submitTaskGenerate() {
-			// 查询当前选择的id对应的点位对象数据
-			const orderedPoints = this.pointIds.map(id => this.pointList.find(point => point.id === id));
-			if (!this.generateTaskParam.taskName || !this.generateTaskParam.count || !this.generateTaskParam.time || this.generateTaskParam.date.length < 1) {
-				this.$message({
-					message: '请完善任务数据!',
-					type: 'warning'
-				});
-				return;
-			}
-			this.generateTaskParam.taskId = Math.floor(Math.random() * 10001);
-			let taskData = {
-				taskId: this.generateTaskParam.taskId,
-				taskName: this.generateTaskParam.taskName,
-				count: this.generateTaskParam.count,
-				time: this.generateTaskParam.time,
-				date: this.generateTaskParam.date,
-				status: 1,
-				points: orderedPoints
-			}
-			// 实际使用需要提交任务后等待后端添加完毕然后查询列表,这里临时用push
-			this.taskDataList.push(taskData)
-			this.restGenerateParam();
-			this.taskGenerateDiaShow = false;
-			this.pointIds = [];
-			this.$modal.msgSuccess("点位任务创建成功");
-		},
-		// 初始化导航
-		initNavigation() {
-			this.closeDra()
-			if (this.poseInitEnable) {
-				this.poseInitEnable = false;
-				this.nowHandMenu = ''
-			} else {
-				this.poseInitEnable = true;
-				this.nowHandMenu = '初始化导航'
-			}
-			this.pointSelectionEnabled = false;
-			this.activeIndex = this.activeIndex == 3 ? -1 : 3;
-		},
-		// 重启导航
-		restNavigation() {
-			this.$confirm('将重启当前导航, 是否继续?', '提示', {
-				confirmButtonText: '确定',
-				cancelButtonText: '取消',
-				customClass: 'el-message-box-cust',
-				type: 'warning'
-			}).then(() => {
-				this.$message({
-					type: 'success',
-					message: '导航已重启!'
-				});
-			}).catch(() => { });
-		},
-		// 关闭导航
-		offNavigation() {
-			this.$confirm('将关闭当前导航, 是否继续?', '提示', {
-				confirmButtonText: '确定',
-				cancelButtonText: '取消',
-				customClass: 'el-message-box-cust',
-				type: 'warning'
-			}).then(() => {
-				this.$message({
-					type: 'success',
-					message: '导航已关闭!'
-				});
-			}).catch(() => { });
-		},
-		// 关闭任务生成弹窗
-		closeTaskGenerate() {
-			this.taskGenerateDiaShow = false;
-			this.restGenerateParam();
-		},
-		// 重置任务创建弹窗数据
-		restGenerateParam() {
-			this.generateTaskParam = {
-				taskId: '',
-				taskName: '',
-				number: 1,
-				time: '',
-				date: []  // 1-7分别指代周一到周末
-			}
-		},
-		// 任务删除
-		removeTaskItem(data) {
-			this.$confirm('删除名为' + data.taskName + '的任务', '删除', {
-				confirmButtonText: '确定',
-				cancelButtonText: '取消',
-				customClass: 'el-message-box-cust',
-				type: 'warning'
-			}).then(() => {
-				this.$message({
-					type: 'success',
-					message: '已删除!'
-				});
-				this.taskDataList = this.taskDataList.filter(task => task.taskId !== data.taskId);
-			}).catch(() => { });
-		},
-		// 执行任务
-		executeTask(data) {
-			this.$confirm('开始执行任务' + data.taskName + '?', '执行', {
-				confirmButtonText: '确定',
-				cancelButtonText: '取消',
-				customClass: 'el-message-box-cust',
-				type: 'warning'
-			}).then(() => {
-				this.$message({
-					type: 'success',
-					message: '任务已开始执行!'
-				});
-				this.taskDataList.forEach(task => {
-					if (task.taskId === data.taskId) {
-						task.status = 0;
-					}
-				});
-			}).catch(() => { });
-		},
-		// 展开右侧实时信息
-		showInfoDra() {
-			this.infoDrawer = true;
-		},
-		test() {
-			console.log(this.set);
-		},
-		// 开启地图选点
-		mapSelectEle(type) {
-			if (type == 'open') {
-				this.pointSelectionEnabled = true;
-				this.poseInitEnable = false;
-				this.$notify({
-					title: '地图选择',
-					message: '已开启选择模式',
-					type: 'success',
-					duration: 1000
-				});
-			} else {
-				this.pointSelectionEnabled = false;
-				this.$notify.info({
-					title: '关闭选择',
-					message: '已关闭选择模式',
-					duration: 1000
-				});
-			}
-		},
-		// 将当前选择的点位数据添加到点位列表中 
-		// currentCoordinate 坐标信息 currentPlace 画布位置信息
-		addNowPoint(currentCoordinate, currentPlace) {
-			let coordData = {
-				id: currentCoordinate[0],
-				x: currentCoordinate[1].toFixed(3),
-				y: currentCoordinate[2].toFixed(3),
-				placeX: currentPlace[0].toFixed(3),
-				placeY: currentPlace[1].toFixed(3),
-				type: 0,
-				action: [{ value: 0, other: 0 }]
-			}
-			this.pointList.push(coordData);
-		},
-		/**
-		 * 位姿初始化操作绘制的回执
-		 * @param position 坐标
-		 * @param angle 角度
-		 */
-		initNavigationResult(position, angle, nid) {
-			const prefix = process.env.VUE_APP_PNS_MQTT_PROXY;
-			let num = nid.split("_")[1];// 获取点位id编号
-			this.$refs.mqtt.publish(prefix + "/localization/action/init", {
-					"timestamp" : 123456,
-					"args"      : [
-							{"nid"  : Number(num)}
-					]
-				},2,false
-			);
-			console.log(position);
-			console.log(angle);
-		}
-	}
-};
-</script>
-
-<style scoped>
-.point-edit-span {
-	display: block;
-	margin: 10px 0;
-	font-weight: bold;
-}
-
-.drawer {
-	height: 100%;
-	position: absolute;
-	top: 0;
-	left: 100%;
-	/* box-shadow: 4px 4px 12px rgba(201, 201, 201, 0.2); */
-	/* 右边和下边的阴影 */
-	border-radius: 0 0 12px 0;
-	border-left: 1px solid #F0F0F0;
-	padding: 8px 15px;
-	border-right: 1px solid #ececec;
-	border-bottom: 1px solid #ececec;
-	overflow-y: auto;
-	background-color: #fff;
-	z-index: 1000;
-}
-
-.drawer-close {
-	position: absolute;
-	right: 3px;
-	top: 3px;
-	cursor: pointer;
-}
-
-.drawer-title {
-	position: absolute;
-	top: -23px;
-	left: -8px;
-	font-size: 13px;
-	font-weight: bold;
-	color: #838383;
-}
-
-.drawer p {
-	font-size: 13px;
-	border-left: 5px #D1D1D1 solid;
-	padding-left: 5px;
-	margin: 8px 0;
-	border-radius: 3px 0 0 3px;
-}
-
-.img-container {
-	text-align: center;
-	display: flex;
-	flex-direction: column;
-	align-items: center;
-	justify-content: center;
-	/* 垂直居中子元素 */
-	border-radius: 7px;
-	background: linear-gradient(135deg, #00bcd4, #009688);
-	cursor: pointer;
-	width: 70%;
-	aspect-ratio: 1;
-	/* 设置宽高比为1,即高度和宽度相等 */
-	margin-top: 10px;
-}
-
-.img-container:hover {
-	transform: scale(1.02);
-	/* 鼠标悬停时放大 */
-	box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
-	/* 增加阴影效果 */
-	background-color: #00796b;
-	/* 改变背景颜色 */
-}
-
-.img-container:active {
-	transform: scale(0.98);
-	/* 点击时缩小 */
-	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
-	/* 点击时加深阴影 */
-	background-color: #004d40;
-	/* 点击时改变背景颜色 */
-	filter: brightness(1.1);
-	/* 点击时稍微增加亮度 */
-}
-
-.img-container img {
-	opacity: 1;
-}
-
-.img-container span {
-	font-size: 12px;
-	color: #ffffff;
-	font-weight: bold;
-}
-
-/* 激活时的样式 */
-.img-container.active {
-	background: linear-gradient(135deg, #007d8d, #004b43);
-}
-
-.explore-unit {
-	margin-left: 8px;
-}
-
-::v-deep .el-dialog__body {
-	padding: 20px 20px 0 20px;
-}
-
-::v-deep .download-map .el-dialog__body {
-	padding: 10px 20px 0 20px !important;
-}
-
-::v-deep .el-table--medium .el-table__cell {
-	padding: 6px 0;
-}
-
-::v-deep .action-menu .action-menu_input .el-input__inner {
-	padding: 0 5px;
-}
-
-.task-status-tag {
-	margin-left: 20px;
-}
-
-::v-deep .drawer .el-collapse-item__header {
-	height: 38px;
-	line-height: 38px;
-	color: #767676;
-	font-weight: bold;
-}
-
-::v-deep .drawer .el-collapse-item__content {
-	text-align: left;
-	padding-bottom: 10px;
-}
-
-::v-deep .drawer .el-collapse {
-	border: 1px solid #EBEEF5;
-	padding: 0 8px;
-	border-radius: 5px;
-}
-
-.collapse-content-div {
-	margin-top: 0;
-}
-
-::v-deep .collapse-content-div .el-button--mini {
-	padding: 4px 10px;
-}
-
-.fixed-right-center {
-	position: fixed;
-	top: 50%;
-	right: 0;
-	transform: translateY(-50%);
-	background-color: rgba(0, 0, 255, 0.6);
-	color: white;
-	border-radius: 6px 0 0 6px;
-	cursor: pointer;
-}
-
-.info-dra-class_content {
-	padding: 0 20px 20px 20px;
-}
-
-.info-dra_title {
-	display: flex;
-	/* 启用 Flexbox 布局 */
-	justify-content: flex-start;
-	/* 水平从左排列 */
-	align-items: center;
-	color: #8a8a8a;
-	font-size: 15px;
-	font-weight: bold;
-	border-bottom: 2px solid #B9B9FF;
-	margin-bottom: 10px;
-}
-
-.info-dra_content {
-	color: #5A5A5A;
-	font-size: 14px;
-	margin-left: 8px;
-	display: block;
-	margin-bottom: 8px;
-}
-
-.info-dra_content_title {
-	font-weight: bold;
-}
-
-.info-dra_content_other {
-	font-weight: 400;
-}
-
-.hand-ment-mark {
-	position: absolute;
-	bottom: 12px;
-	left: 12px;
-	z-index: 1000;
-}
-
-::v-deep .info-dra-class-all .el-drawer__wrapper {
-	width: 15%;
-	left: 85%;
-}
-
-@media (max-width: 1599px) {
-	::v-deep .info-dra-class-all .el-drawer__wrapper {
-		width: 18%;
-		left: 82%;
-	}
-}
-
-@media (max-width: 1269px) {
-	::v-deep .info-dra-class-all .el-drawer__wrapper {
-		width: 21%;
-		left: 79%;
-	}
-}
-
-@media (max-width: 1000px) {
-	::v-deep .info-dra-class-all .el-drawer__wrapper {
-		width: 24%;
-		left: 76%;
-	}
-}
-
-.notification__title {
-	font-size: 1.2rem;
-	/* 默认字体大小 */
-}
-
-.main-content {
-	width: 100%;
-	min-height: calc(100vh - 84px);
-	overflow: hidden;
-	position: relative;
-}
-
-.main {
-	width: 100%;
-	min-height: calc(100vh - 84px);
-	min-width: 1500px;
-	overflow-x: auto;
-}
-
-.main-menu {
-	display: flex;
-	flex-direction: column;
-	justify-content: center;
-	align-items: center;
-}
-</style>
-
-<style>
-.navigation-info-dra-class {
-	background-color: #ffffff;
-	box-shadow: none;
-	border-radius: 5px 0 0 5px;
-}
-
-.navigation-info-dra-class .el-drawer__header {
-	margin-bottom: 20px;
-}
-</style>
+<template>
+	<div class="navigation-container">
+		<!-- 地图舞台容器 -->
+		<div class="map-stage" ref="mapStage">
+					<!-- 当前操作类型标记 -->
+					<div class="hand-ment-mark">
+						<el-tag type="danger" effect="dark" size="mini" v-if="nowHandMenu">{{ nowHandMenu }}</el-tag>
+					</div>
+			
+			<!-- 地图组件 - 完全保持原样 -->
+					<OlMap ref="olmap" :width="olWidth + 'px'" :height="olHeight + 'px'" backgroundColor="#F5F5F5" :mapName="mapName"
+						:pointSwitch="settingParams.pointId" :baseLayerShow="settingParams.baseMap" :robotPoseData="laserPositionData"
+				:pointSelectionEnabled="selectPointMode" :poseInitEnable="initPoseMode" @addNowPoint="addNowPoint"
+				:isRobotFollow="settingParams.follow" @initNavigationResult="initNavigationResult"
+				:showDefaultControls="false"></OlMap>
+			
+			<!-- 左侧工具条浮层 -->
+			<MapToolbar 
+				class="nav-toolbar"
+				preset="nav"
+				:selectedKey="selectedKey"
+				:hasRobotPosition="true"
+				:isConnected="true"
+				:isBusy="false"
+				:isFullscreen="isFullscreen"
+				@zoom-in="onZoomIn"
+				@zoom-out="onZoomOut"
+				@center-robot="onCenterRobot"
+				@toggle-fullscreen="onToggleFullscreen"
+				@confirm-init="handleConfirmInit"
+				@confirm-reboot="handleConfirmReboot"
+				@confirm-stop="handleConfirmStop"
+			/>
+			
+			<!-- 右侧信息面板浮层 -->
+			<RightPanel
+				mode="nav"
+				panelType="nav"
+				:overlay="true"
+				:visible.sync="rightVisible"
+				:realtime-info="realtimeInfo"
+				:waypoint-list="waypoints"
+				:task-list="tasks"
+				:setting-params="settingParams"
+				@wp-select="onWpSelect"
+				@wp-send="onWpSend"
+				@wp-create="onWpCreate"
+				@wp-edit="onWpEdit"
+				@wp-remove="onWpRemove"
+				@wp-move-up="onWpMoveUp"
+				@wp-move-down="onWpMoveDown"
+				@wp-batch-remove="onWpBatchRemove"
+				@wp-goto="onWpGoto"
+				@wp-goto-single="onWpGotoSingle"
+				@wp-create-task="onWpCreateTask"
+				@wp-selection-change="onWpSelectionChange"
+				@map-select-mode-change="onMapSelectModeChange"
+				@task-view="onTaskView"
+				@task-start="onTaskStart"
+				@task-pause="onTaskPause"
+				@task-stop="onTaskStop"
+				@task-remove="onTaskRemove"
+				@setting-change="onSettingChange"
+			/>
+			
+				</div>
+		
+		<!-- 目标点编辑对话框 -->
+		<el-dialog 
+			title="目标点编辑" 
+			:visible.sync="pointEditDiaShow" 
+			width="480px" 
+			@close="clearActionDia"
+			class="waypoint-edit-dialog"
+			:close-on-click-modal="false"
+			center
+		>
+			<div class="dialog-content">
+				<el-form :model="pointEditData" label-width="90px" size="small" class="waypoint-form">
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-location-outline"></i>
+							位置信息
+						</h4>
+						<!-- 分两行布局,给输入框更多空间 -->
+						<el-form-item label="X坐标(m)">
+							<el-input v-model="pointEditData.x" placeholder="请输入X坐标值" class="coordinate-input">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="Y坐标(m)">
+							<el-input v-model="pointEditData.y" placeholder="请输入Y坐标值" class="coordinate-input">
+							</el-input>
+						</el-form-item>
+					</div>
+
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-guide"></i>
+							路径配置
+						</h4>
+						<el-form-item label="规划类型">
+							<el-select v-model="pointEditData.type" placeholder="请选择路径类型" style="width: 100%">
+				<el-option v-for="item in planOptions" :key="item.value" :label="item.label" :value="item.value">
+									<span style="float: left">{{ item.label }}</span>
+									<span style="float: right; color: #8492a6; font-size: 13px">{{ item.value === 0 ? '自由规划' : '路网约束' }}</span>
+				</el-option>
+			</el-select>
+						</el-form-item>
+					</div>
+
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-setting"></i>
+							动作配置
+							<el-button type="text" size="mini" @click="appendActionMenu" class="add-action-btn">
+								<i class="el-icon-plus"></i><span>添加动作</span>
+							</el-button>
+						</h4>
+						<div class="action-list">
+							<div v-for="(item, index) in pointEditData.actionMenuList" :key="index" class="action-item">
+								<div class="action-header">
+									<span class="action-index">{{ index + 1 }}</span>
+									<el-select v-model="item.value" placeholder="请选择动作" size="small" @change="changeAction(index)" style="flex: 1;">
+										<el-option v-for="option in actionOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
+				</el-select>
+									<el-button v-if="index > 0" type="text" size="mini" @click="removeActionMenu(index)" class="remove-btn">
+										<i class="el-icon-close"></i>
+									</el-button>
+								</div>
+								<div v-if="'other' in item" class="action-params">
+									<el-input v-model="item.other" placeholder="等待时间" size="small" style="width: 120px;">
+										<template slot="append">秒</template>
+									</el-input>
+								</div>
+							</div>
+						</div>
+					</div>
+				</el-form>
+			</div>
+			<span slot="footer" class="dialog-footer">
+				<el-button @click="pointEditDiaShow = false" size="medium">取 消</el-button>
+				<el-button type="primary" @click="submitEditPoint" size="medium">
+					<i class="el-icon-check"></i> 保存修改
+				</el-button>
+			</span>
+		</el-dialog>
+		<!-- 创建任务对话框 -->
+		<el-dialog 
+			title="创建任务" 
+			:visible.sync="taskGenerateDiaShow" 
+			width="480px" 
+			@close="closeTaskGenerate"
+			class="task-create-dialog"
+			:close-on-click-modal="false"
+			center
+		>
+			<div class="dialog-content">
+				<el-form :model="generateTaskParam" label-width="90px" size="small" class="task-form">
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-s-order"></i>
+							任务信息
+						</h4>
+						<el-form-item label="任务名称">
+							<el-input v-model="generateTaskParam.taskName" placeholder="请输入任务名称" class="task-input">
+							</el-input>
+						</el-form-item>
+						<el-form-item label="执行次数">
+							<el-input-number 
+								v-model="generateTaskParam.count"
+								controls-position="right" 
+								:min="1" 
+								:max="100" 
+								class="task-input-number"
+								style="width: 100%"
+							></el-input-number>
+						</el-form-item>
+					</div>
+					
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-time"></i>
+							执行计划
+						</h4>
+						<el-form-item label="开始时间">
+							<el-time-picker 
+								v-model="generateTaskParam.time" 
+								:picker-options="{
+					selectableRange: '00:00:00 - 23:59:59'
+								}" 
+								placeholder="选择时间"
+								class="task-time-picker"
+								style="width: 100%"
+							>
+				</el-time-picker>
+						</el-form-item>
+						<el-form-item label="执行日期">
+							<el-checkbox-group v-model="generateTaskParam.date" class="task-date-group">
+					<el-checkbox label="1">周一</el-checkbox>
+					<el-checkbox label="2">周二</el-checkbox>
+					<el-checkbox label="3">周三</el-checkbox>
+					<el-checkbox label="4">周四</el-checkbox>
+					<el-checkbox label="5">周五</el-checkbox>
+					<el-checkbox label="6">周六</el-checkbox>
+					<el-checkbox label="7">周日</el-checkbox>
+				</el-checkbox-group>
+						</el-form-item>
+					</div>
+				</el-form>
+			</div>
+			<span slot="footer" class="dialog-footer">
+				<el-button @click="closeTaskGenerate()" size="medium">取 消</el-button>
+				<el-button type="primary" @click="submitTaskGenerate" size="medium">
+					<i class="el-icon-check"></i> 创建任务
+				</el-button>
+			</span>
+		</el-dialog>
+		
+		<!-- 任务查看对话框 -->
+		<el-dialog 
+			title="任务详情" 
+			:visible.sync="taskViewDiaShow" 
+			width="480px" 
+			class="task-view-dialog"
+			:close-on-click-modal="false"
+			center
+		>
+			<div class="dialog-content">
+				<el-form :model="taskViewData" label-width="90px" size="small" class="task-view-form">
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-s-order"></i>
+							任务信息
+						</h4>
+						<el-form-item label="任务名称">
+							<span class="form-text">{{ taskViewData.taskName || '--' }}</span>
+						</el-form-item>
+						<el-form-item label="执行次数">
+							<span class="form-text">{{ taskViewData.count || '--' }}次</span>
+						</el-form-item>
+						<el-form-item label="任务状态">
+							<span class="form-text status-text" :class="getTaskStatusClass(taskViewData.status)">
+								{{ getTaskStatusText(taskViewData.status) }}
+							</span>
+						</el-form-item>
+					</div>
+					
+					<div class="form-section">
+						<h4 class="section-title">
+							<i class="el-icon-time"></i>
+							执行计划
+						</h4>
+						<el-form-item label="开始时间">
+							<span class="form-text">{{ formatTime(taskViewData.time) }}</span>
+						</el-form-item>
+						<el-form-item label="执行日期">
+							<span class="form-text">{{ formatDate(taskViewData.date) }}</span>
+						</el-form-item>
+					</div>
+
+				</el-form>
+			</div>
+			<span slot="footer" class="dialog-footer">
+				<el-button @click="taskViewDiaShow = false" size="medium">关 闭</el-button>
+			</span>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+import OlMap from "@/components/OlMap";
+import { MapToolbar, RightPanel } from "./components/shared";
+import { FullscreenOperations, RobotPositionUtils } from "@/utils/map-operations";
+
+import MqttComp from "@/components/Mqtt/mqttComp.vue";
+export default {
+	name: "NavigationPage",
+	components: {
+		OlMap,
+		MapToolbar,
+		RightPanel,
+		MqttComp
+	},
+	data() {
+		return {
+			topics:[
+				{ topic: this.$mqttPrefix+'/localization/action/init/reply', qos: 2, retain: false },
+				{ topic:this.$mqttPrefix + '/localization/pose'}
+				],
+				nowHandMenu: '',
+			mapName: this.$route.params.mapName || '',  // 地图名称
+			// 激光定位数据
+			laserPositionData: {
+        x: 0,
+        y: 0,
+        angle: 0
+      },
+			activeIndex: -1, // 默认为没有激活的项
+			settingDrawer: false,
+			pointDrawer: false,
+			taskDrawer: false,
+			pointEditDiaShow: false,
+			taskGenerateDiaShow: false,
+			taskViewDiaShow: false,
+			// 是否开启地图选点
+			pointSelectionEnabled: false,
+			// 是否开启位置初始化功能
+			poseInitEnable: false,
+			// 功能设置参数
+			settingParams: {
+				pointCloud: false,
+				baseMap: true,
+				pointId: false,
+				follow: false,
+				network: false
+			},
+			// 非单个禁用
+			single: true,
+			// 非多个禁用
+			multiple: true,
+			taskDataList: [],
+			// 目标点的编辑数据
+			pointEditData: {
+				id: '',
+				x: '',
+				y: '',
+				type: '',
+				// 添加动作菜单列表 (other:追加参数,例如原定等待选项的等待时间)
+				actionMenuList: []
+			},
+			// 生成任务的参数
+			generateTaskParam: {
+				taskId: '',
+				taskName: '',
+				count: 1,
+				time: '',
+				date: []  // 1-7分别指代周一到周末
+			},
+			
+			// 任务查看数据
+			taskViewData: {},
+			// 点位列表
+			pointList: [],
+			pointIds: [],
+			// 路径类型
+			planOptions: [
+				{ label: '自由路径', value: 0 },
+				{ label: '路网路径', value: 1 }
+			],
+			// 动作类型
+			actionOptions: [
+				{ label: '原地等待', value: 0 },
+				{ label: '开始录制', value: 1 },
+				{ label: '结束录制', value: 2 },
+				{ label: '添加建图轨迹', value: 3 },
+				{ label: '挂钩挂载', value: 4 },
+				{ label: '挂钩卸载', value: 5 }
+			],
+			olWidth: 0,  // 用于存储宽度的变量
+			olHeight: 0,
+			nowHandMenu: '',
+			
+			// 新UI相关状态
+			panelVisible: true, // 右侧面板是否可见(旧的,保留兼容)
+			rightVisible: true, // 导航页右侧面板是否可见
+			activeTab: 'info', // 当前激活的tab
+			lastTab: 'info', // 上次激活的tab
+			selectPointMode: false, // 选点模式
+			initPoseMode: false, // 初始化位姿模式
+			// Mock任务数据
+			mockTasks: [
+				{ id: 1, name: '巡检任务A', nodes: 5, status: 'idle' },
+				{ id: 2, name: '运输任务B', nodes: 3, status: 'running' },
+				{ id: 3, name: '清扫任务C', nodes: 8, status: 'paused' }
+			],
+		// 实时信息数据
+		realtimeInfo: {
+			currentMap: 'shanghai',
+			currentTask: '测试任务',
+			speed: '0.35m/s',
+			speedCommand: '0.22m/s',
+			coordinates: '(1.813, -63.931, 0.000)',
+			heading: '-79.6°',
+			totalDistance: '5965352.00m',
+			registrationError: '10.000',
+			batteryLevel: '67%'
+		},
+		
+		// 机器人位姿数据(用于OlMap组件)
+		robotPoseData: {
+			x: 1.813,
+			y: -63.931,
+			angle: 0.000
+		},
+			// 连接和状态
+			isConnected: true,
+			isBusy: false,
+			isFullscreen: false,
+			
+			// 全屏监听清理函数
+			fullscreenCleanup: null,
+
+			// 目标点相关状态
+			selectedWaypointIds: [], // 选中的目标点ID列表
+			waypointSingle: true, // 是否单个选中
+			waypointMultiple: true, // 是否多个选中
+			pointEditDiaShow: false, // 目标点编辑对话框显示状态
+			
+			// 目标点的编辑数据
+			pointEditData: {
+				id: '',
+				x: '',
+				y: '',
+				type: '',
+				// 添加动作菜单列表 (other:追加参数,例如原定等待选项的等待时间)
+				actionMenuList: []
+			},
+			
+			// 路径类型选项
+			planOptions: [
+				{ label: '自由路径', value: 0 },
+				{ label: '路网路径', value: 1 }
+			],
+			
+			// 动作类型选项
+			actionOptions: [
+				{ label: '原地等待', value: 0 },
+				{ label: '开始录制', value: 1 },
+				{ label: '结束录制', value: 2 },
+				{ label: '添加建图轨迹', value: 3 },
+				{ label: '挂钩挂载', value: 4 },
+				{ label: '挂钩卸载', value: 5 }
+			],
+			
+			// === 导航页专用数据 ===
+			waypoints: [],
+			tasks: [
+				{ 
+					taskId: 1, 
+					taskName: '巡检任务Alpha', 
+					status: 'idle',
+					count: 3,
+					time: new Date('2024-01-01 09:00:00'),
+					date: ['1', '3', '5'],
+					points: [
+						{ id: 101, name: '目标点1', x: '1.234', y: '2.345' },
+						{ id: 102, name: '目标点2', x: '3.456', y: '4.567' }
+					]
+				},
+				{ 
+					taskId: 2, 
+					taskName: '运输任务Beta', 
+					status: 'running',
+					count: 1,
+					time: new Date('2024-01-01 14:30:00'),
+					date: ['2', '4'],
+					points: [
+						{ id: 103, name: '目标点3', x: '5.678', y: '6.789' }
+					]
+				},
+				{ 
+					taskId: 3, 
+					taskName: '清扫任务Gamma', 
+					status: 'paused',
+					count: 5,
+					time: new Date('2024-01-01 16:00:00'),
+					date: ['1', '2', '3', '4', '5'],
+					points: [
+						{ id: 104, name: '目标点4', x: '7.890', y: '8.901' },
+						{ id: 105, name: '目标点5', x: '9.012', y: '0.123' },
+						{ id: 106, name: '目标点6', x: '1.345', y: '2.456' }
+					]
+				}
+			]
+		};
+	},
+	computed: {
+		// 当前选中的工具key
+		selectedKey() {
+			if (this.initPoseMode) return 'init-pose';
+			return '';
+		},
+		
+		// 机器人位置
+		robotPosition() {
+			// 直接使用robotPoseData,与标定页面保持一致
+			if (this.robotPoseData && (this.robotPoseData.x !== 0 || this.robotPoseData.y !== 0)) {
+				return [this.robotPoseData.x, this.robotPoseData.y];
+			}
+			return null;
+		},
+		
+		// 是否有有效的机器人位置
+		hasValidRobotPosition() {
+			return !!this.robotPosition;
+		},
+		
+		// 地图是否就绪
+		isMapReady() {
+			return !!this.getMapInstance();
+		}
+	},
+	created() {
+
+	},
+	mounted() {
+		// const mapId = this.$route.params.mapId;	
+		this.updateOlCss();
+		window.addEventListener('resize', this.updateOlCss);
+		
+		// 地图初始化(无需额外操作,直接使用getMapInstance方法获取地图实例)
+		
+		// 设置全屏状态监听
+		this.fullscreenCleanup = FullscreenOperations.addFullscreenListener((isFullscreen) => {
+			this.isFullscreen = isFullscreen;
+			// 全屏状态改变后,重新计算地图尺寸
+			this.$nextTick(() => {
+				this.updateOlCss();
+				// 触发地图重新计算尺寸
+				const map = this.getMapInstance();
+				if (map) {
+					map.updateSize();
+				}
+			});
+		});
+	},
+	beforeDestroy() {
+		window.removeEventListener('resize', this.updateOlCss);
+		
+		// 清理全屏监听
+		if (this.fullscreenCleanup) {
+			this.fullscreenCleanup();
+		}
+	},
+	methods: {
+		onMessage({ topic, message }) {
+        // console.log("收到消息:", topic, message);
+				if (topic === this.$mqttPrefix + '/localization/action/init/reply') {
+					this.handleInitReply(message);
+				} else if (topic === this.$mqttPrefix + '/localization/pose') {
+					this.handleLaserPose(message);
+				}
+    },
+		handleInitReply(message) {
+			// 处理初始化回复消息
+			console.log("初始化回复:", message);
+			
+		},
+		handleLaserPose(message) {
+			try {
+        const data = message.args[0];
+        const {xyz, rpy, blh, heading} = data.pose;
+        // 激光定位实时数据
+        this.laserPositionData.x = xyz[0];
+        this.laserPositionData.y = xyz[1];
+        this.laserPositionData.angle = rpy[2];
+        // GNSS定位实时数据
+        /* this.gnssPositionData.longitude = blh[1]; // 经度
+        this.gnssPositionData.latitude = blh[0]; // 纬度
+        this.gnssPositionData.angle = heading; // 航向角
+        
+        this.gnssPositionData.status = data.rtk.star+ '/' + data.rtk.status; // RTK状态 */
+        
+      } catch (e) {
+        console.error("解析失败:", e);
+      }
+		},
+		publishMsg() {
+        
+    },
+		updateOlCss() {
+			const element = this.$el.querySelector('.map-stage');
+			this.olWidth = element.offsetWidth;
+			this.olHeight = element.offsetHeight;
+		},
+		
+		// 地图API适配器
+		getMapInstance() {
+			return this.$refs.olmap && this.$refs.olmap.map ? this.$refs.olmap.map : null;
+		},
+		
+		openDraSetting() {
+			this.poseInitEnable = false;
+			this.activeIndex = this.activeIndex == 0 ? -1 : 0;
+			if (this.settingDrawer) {
+				this.nowHandMenu = ''
+				this.settingDrawer = false;
+				return;
+			}
+			this.closeDra()
+			this.nowHandMenu = '功能菜单操作'
+			this.settingDrawer = true;
+		},
+		openPoint() {
+			this.poseInitEnable = false
+			this.activeIndex = this.activeIndex == 1 ? -1 : 1;
+			if (this.pointDrawer) {
+				this.pointDrawer = false;
+				this.nowHandMenu = ''
+				return;
+			}
+			this.closeDra()
+			this.nowHandMenu = '目标点操作'
+			this.pointDrawer = true;
+		},
+		openTask() {
+			this.poseInitEnable = false
+			this.activeIndex = this.activeIndex == 2 ? -1 : 2;
+			if (this.taskDrawer) {
+				this.taskDrawer = false;
+				this.nowHandMenu = ''
+				return;
+			}
+			this.closeDra()
+			this.nowHandMenu = '任务操作'
+			this.taskDrawer = true;
+		},
+		/**
+		 * 关闭左侧菜单的抽屉
+		 * type 类型(hand手动,auto自动)
+		 */
+		closeDra(type) {
+			this.settingDrawer = false;
+			this.pointDrawer = false;
+			this.taskDrawer = false;
+			if (type == 'hand') {
+				this.activeIndex = -1;
+			}
+			this.nowHandMenu = ''
+		},
+		handleSelectionChange(selection) {
+			this.pointIds = selection.map(item => item.id)
+			this.single = selection.length !== 1
+			this.multiple = !selection.length
+		},
+		// 点位编辑
+		editPoint(row) {
+			this.pointEditDiaShow = true;
+			this.pointEditData.id = row.id;
+			this.pointEditData.x = row.x;
+			this.pointEditData.y = row.y;
+			this.pointEditData.type = row.type;
+			this.pointEditData.actionMenuList = row.action
+		},
+		// 点位删除
+		removePoint(row) {
+			const idArr = [];
+			const ids = row?.id || this.pointIds;
+			if (ids) {
+				idArr.push(...(Array.isArray(ids) ? ids : [ids]));
+				idArr.forEach(id => {
+					let indexToRemove = this.pointList.findIndex(item => item?.id === id);
+					if (indexToRemove !== -1) {
+						this.pointList.splice(indexToRemove, 1);
+						if (this.pointList.length < 1) {
+							// 重置地图的id计数器
+							this.$refs.olmap.restIdNum();
+						}
+						this.$refs.olmap.removeIconHtmlById("pose-" + id);
+					}
+				});
+			}
+		},
+		// 点位上移
+		moveUp() {
+			const index = this.pointList.findIndex(point => point.id == this.pointIds[0]);
+			if (index !== -1 && index > 0) {
+				let temp = this.pointList[index];
+				this.$set(this.pointList, index, this.pointList[index - 1]);
+				this.$set(this.pointList, index - 1, temp);
+			}
+		},
+		// 点位下移
+		moveDown() {
+			const index = this.pointList.findIndex(point => point.id == this.pointIds[0]);
+			if (index !== -1 && index < this.pointList.length - 1) {
+				let temp = this.pointList[index];
+				this.$set(this.pointList, index, this.pointList[index + 1]);
+				this.$set(this.pointList, index + 1, temp);
+			}
+		},
+		// 追加动作按钮
+		appendActionMenu() {
+			this.pointEditData.actionMenuList.push({ value: 0, other: 0 })
+		},
+		// 删除追加动作按钮
+		removeActionMenu(index) {
+			this.pointEditData.actionMenuList.splice(index, 1);
+		},
+		// 修改动作下拉值
+		changeAction(index) {
+			// 判断当前修改后是否是原定等待,如果不是则删除other属性
+			let item = this.pointEditData.actionMenuList[index];
+			if (item && 'other' in item) {
+				delete item.other;  // 删除 'other' 属性
+			} else {
+				item.other = 0;
+			}
+		},
+		clearActionDia() {
+			this.pointEditData.id = '';
+			this.pointEditData.x = '';
+			this.pointEditData.y = '';
+			this.pointEditData.type = '';
+			this.pointEditData.actionMenuList = [];
+		},
+		// 提交点位修改
+		submitEditPoint() {
+			this.pointEditDiaShow = false;
+			// 模拟数据修改
+			const point = this.pointList.find(item => item.id === this.pointEditData.id);
+			if (this.pointEditData.actionMenuList)
+				if (point) {
+					// 找到对应元素,更新数据(真实情况下发请求修改,然后重新查询点位列表)
+					point.x = this.pointEditData.x;
+					point.y = this.pointEditData.y;
+					point.type = this.pointEditData.type;
+					point.action = this.pointEditData.actionMenuList;
+					this.$modal.msgSuccess("当前点位数据已修改");
+				}
+		},
+		// 生成任务
+		submitTaskGenerate() {
+			// 查询当前选择的id对应的点位对象数据
+			const orderedPoints = this.selectedWaypointIds.map(id => this.waypoints.find(point => point.id === id));
+			if (!this.generateTaskParam.taskName || !this.generateTaskParam.count || !this.generateTaskParam.time || this.generateTaskParam.date.length < 1) {
+				this.$message({
+					message: '请完善任务数据!',
+					type: 'warning'
+				});
+				return;
+			}
+			this.generateTaskParam.taskId = Math.floor(Math.random() * 10001);
+			let taskData = {
+				taskId: this.generateTaskParam.taskId,
+				taskName: this.generateTaskParam.taskName,
+				count: this.generateTaskParam.count,
+				time: this.generateTaskParam.time,
+				date: this.generateTaskParam.date,
+				status: 'idle',
+				points: orderedPoints
+			}
+			// 实际使用需要提交任务后等待后端添加完毕然后查询列表,这里临时用push
+			this.tasks.push(taskData);
+			this.restGenerateParam();
+			this.taskGenerateDiaShow = false;
+			this.selectedWaypointIds = [];
+			this.$message.success("点位任务创建成功");
+		},
+		// 初始化导航
+		initNavigation() {
+			this.closeDra()
+			if (this.poseInitEnable) {
+				this.poseInitEnable = false;
+				this.nowHandMenu = ''
+			} else {
+				this.poseInitEnable = true;
+				this.nowHandMenu = '初始化导航'
+			}
+			this.pointSelectionEnabled = false;
+			this.activeIndex = this.activeIndex == 3 ? -1 : 3;
+		},
+		// 重启导航
+		restNavigation() {
+			this.$confirm('将重启当前导航, 是否继续?', '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				customClass: 'el-message-box-cust',
+				type: 'warning'
+			}).then(() => {
+				this.$message({
+					type: 'success',
+					message: '导航已重启!'
+				});
+			}).catch(() => { });
+		},
+		// 关闭导航
+		offNavigation() {
+			this.$confirm('将关闭当前导航, 是否继续?', '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				customClass: 'el-message-box-cust',
+				type: 'warning'
+			}).then(() => {
+				this.$message({
+					type: 'success',
+					message: '导航已关闭!'
+				});
+			}).catch(() => { });
+		},
+		// 关闭任务生成弹窗
+		closeTaskGenerate() {
+			this.taskGenerateDiaShow = false;
+			this.restGenerateParam();
+		},
+		// 重置任务创建弹窗数据
+		restGenerateParam() {
+			this.generateTaskParam = {
+				taskId: '',
+				taskName: '',
+				number: 1,
+				time: '',
+				date: []  // 1-7分别指代周一到周末
+			}
+		},
+		// 任务删除
+		removeTaskItem(data) {
+			this.$confirm('删除名为' + data.taskName + '的任务', '删除', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				customClass: 'el-message-box-cust',
+				type: 'warning'
+			}).then(() => {
+				this.$message({
+					type: 'success',
+					message: '已删除!'
+				});
+				this.taskDataList = this.taskDataList.filter(task => task.taskId !== data.taskId);
+			}).catch(() => { });
+		},
+		// 执行任务
+		executeTask(data) {
+			this.$confirm('开始执行任务' + data.taskName + '?', '执行', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				customClass: 'el-message-box-cust',
+				type: 'warning'
+			}).then(() => {
+				this.$message({
+					type: 'success',
+					message: '任务已开始执行!'
+				});
+				this.taskDataList.forEach(task => {
+					if (task.taskId === data.taskId) {
+						task.status = 0;
+					}
+				});
+			}).catch(() => { });
+		},
+		test() {
+			console.log(this.set);
+		},
+		// 开启地图选点
+		mapSelectEle(type) {
+			if (type == 'open') {
+				this.pointSelectionEnabled = true;
+				this.poseInitEnable = false;
+				this.$notify({
+					title: '地图选择',
+					message: '已开启选择模式',
+					type: 'success',
+					duration: 1000
+				});
+			} else {
+				this.pointSelectionEnabled = false;
+				this.$notify.info({
+					title: '关闭选择',
+					message: '已关闭选择模式',
+					duration: 1000
+				});
+			}
+		},
+		// 将当前选择的点位数据添加到点位列表中 
+		// currentCoordinate 坐标信息 currentPlace 画布位置信息
+		addNowPoint(currentCoordinate, currentPlace) {
+			let coordData = {
+				id: currentCoordinate[0],
+				name: `目标点${currentCoordinate[0]}`,
+				x: currentCoordinate[1].toFixed(3),
+				y: currentCoordinate[2].toFixed(3),
+				placeX: currentPlace[0].toFixed(3),
+				placeY: currentPlace[1].toFixed(3),
+				type: 0,
+				action: [{ value: 0, other: 0 }]
+			}
+			this.waypoints.push(coordData);
+			this.$message.success(`已添加目标点: (${coordData.x}, ${coordData.y})`);
+		},
+		/**
+		 * 位姿初始化操作绘制的回执
+		 * @param position 坐标
+		 * @param angle 角度
+		 */
+		initNavigationResult(position, angle, nid) {
+			const prefix = process.env.VUE_APP_PNS_MQTT_PROXY;
+			let num = nid.split("_")[1];// 获取点位id编号
+			this.$refs.mqtt.publish(prefix + "/localization/action/init", {
+					"timestamp" : 123456,
+					"args"      : [
+							{"nid"  : Number(num)}
+					]
+				},2,false
+			);
+			console.log(position);
+			console.log(angle);
+		},
+
+		// === 新UI相关方法 ===
+		
+		
+		// Tab切换事件
+		onTabChange(tabKey) {
+			this.activeTab = tabKey;
+			this.lastTab = tabKey;
+			
+			// 根据Tab自动调整模式
+			if (tabKey === 'points' && this.selectPointMode) {
+				// 保持选点模式
+			} else if (tabKey !== 'points') {
+				// 切换到其他Tab时退出选点模式
+				this.selectPointMode = false;
+				this.nowHandMenu = '';
+			}
+		},
+		
+		// 切换选点模式
+		toggleSelectPointMode() {
+			this.selectPointMode = !this.selectPointMode;
+			this.initPoseMode = false;
+			this.nowHandMenu = this.selectPointMode ? '选点模式' : '';
+			
+			if (this.selectPointMode) {
+				this.$message.success('已进入选点模式');
+			} else {
+				this.$message.info('已退出选点模式');
+			}
+		},
+		
+		// 清空所有点位
+		clearAllPoints() {
+			this.$confirm('确定要清空所有点位吗?', '确认清空', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning'
+			}).then(() => {
+				this.pointList = [];
+				if (this.$refs.olmap && this.$refs.olmap.restIdNum) {
+					this.$refs.olmap.restIdNum();
+				}
+				this.$message.success('已清空所有点位');
+			}).catch(() => {});
+		},
+		
+		// 地图缩放
+		handleZoomIn() {
+			try {
+				const map = this.getMapInstance();
+				if (map) {
+					// OpenLayers API
+					const view = map.getView();
+					const currentZoom = view.getZoom();
+					view.animate({
+						zoom: currentZoom + 1,
+						duration: 250
+					});
+				} else if (this.$refs.olmap && this.$refs.olmap.zoomIn) {
+					// 备用方法
+					this.$refs.olmap.zoomIn();
+				}
+			} catch (error) {
+				console.warn('地图放大失败:', error);
+				this.$message.warning('地图放大失败');
+			}
+		},
+		
+		handleZoomOut() {
+			try {
+				const map = this.getMapInstance();
+				if (map) {
+					// OpenLayers API
+					const view = map.getView();
+					const currentZoom = view.getZoom();
+					view.animate({
+						zoom: Math.max(currentZoom - 1, 1),
+						duration: 250
+					});
+				} else if (this.$refs.olmap && this.$refs.olmap.zoomOut) {
+					// 备用方法
+					this.$refs.olmap.zoomOut();
+				}
+			} catch (error) {
+				console.warn('地图缩小失败:', error);
+				this.$message.warning('地图缩小失败');
+			}
+		},
+		
+		// 居中到机器人
+		handleCenterToRobot() {
+			try {
+				const map = this.getMapInstance();
+				if (map) {
+					// OpenLayers API
+					const view = map.getView();
+					
+					// 与标定页面保持一致的实现
+					let centerPoint = [this.robotPoseData.x, this.robotPoseData.y];
+					if (this.robotPoseData.x === 0 && this.robotPoseData.y === 0) {
+						// 使用当前地图中心点作为默认位置
+						centerPoint = view.getCenter();
+						console.log('使用地图中心点作为居中位置:', centerPoint);
+					} else {
+						console.log('使用机器人位置作为居中位置:', centerPoint);
+					}
+					
+					view.animate({
+						center: centerPoint,
+						zoom: Math.max(view.getZoom(), 15),
+						duration: 500
+					});
+					this.$message.success('已居中到机器人位置');
+				} else if (this.$refs.olmap && this.$refs.olmap.centerToRobot) {
+					// 备用方法
+					this.$refs.olmap.centerToRobot();
+					this.$message.success('已居中到机器人位置');
+				} else {
+					console.warn('无法获取地图实例');
+					this.$message.warning('地图未就绪,无法居中');
+				}
+			} catch (error) {
+				console.error('定位机器人失败:', error);
+				console.log('调试信息:', {
+					robotPoseData: this.robotPoseData,
+					robotPosition: this.robotPosition,
+					mapReady: !!this.getMapInstance()
+				});
+				this.$message.warning('定位机器人失败: ' + error.message);
+			}
+		},
+		
+		// 切换全屏
+		handleToggleFullscreen() {
+			const mapContainer = this.$el.querySelector('.map-stage');
+			if (!mapContainer) {
+				this.$message.error('无法找到地图容器');
+				return;
+			}
+			
+			if (FullscreenOperations.toggleFullscreen(mapContainer)) {
+				// 全屏切换成功,状态会通过监听器自动更新
+			} else {
+				this.$message.error('浏览器不支持全屏功能');
+			}
+		},
+		
+		// 确认初始化
+		handleConfirmInit() {
+			this.initPoseMode = true;
+			this.selectPointMode = false;
+			this.nowHandMenu = '初始化导航';
+			this.$message.success('已进入位姿初始化模式');
+		},
+		
+		// 确认重启
+		handleConfirmReboot() {
+			this.isBusy = true;
+			this.$message.success('重启指令已发送');
+			// 模拟重启过程
+			setTimeout(() => {
+				this.isBusy = false;
+				this.$message.info('系统重启完成');
+			}, 3000);
+		},
+		
+		// 确认停止
+		handleConfirmStop() {
+			this.selectPointMode = false;
+			this.initPoseMode = false;
+			this.nowHandMenu = '';
+			this.$message.warning('已执行急停操作');
+		},
+		
+		
+		// 任务相关方法
+		showCreateTaskDialog() {
+			this.$message.info('创建任务功能待接入');
+		},
+		
+		startTask(task) {
+			task.status = 'running';
+			this.$message.success(`任务 "${task.name}" 已开始执行`);
+		},
+		
+		pauseTask(task) {
+			task.status = 'paused';
+			this.$message.warning(`任务 "${task.name}" 已暂停`);
+		},
+		
+		resumeTask(task) {
+			task.status = 'running';
+			this.$message.success(`任务 "${task.name}" 已继续执行`);
+		},
+		
+		cancelTask(task) {
+			this.$confirm(`确定要取消任务 "${task.name}" 吗?`, '确认取消', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning'
+			}).then(() => {
+				task.status = 'idle';
+				this.$message.info(`任务 "${task.name}" 已取消`);
+			}).catch(() => {});
+		},
+		
+		// 切换初始化模式
+		toggleInitPoseMode() {
+			this.initPoseMode = !this.initPoseMode;
+			this.selectPointMode = false;
+			this.nowHandMenu = this.initPoseMode ? '初始化导航' : '';
+			
+			if (this.initPoseMode) {
+				this.$message.success('已进入位姿初始化模式');
+			} else {
+				this.$message.info('已退出位姿初始化模式');
+			}
+		},
+		
+		// RightPanel 事件处理方法
+		onRestart() {
+			this.handleConfirmReboot();
+		},
+		
+		onStop() {
+			this.handleConfirmStop();
+		},
+		
+		onInit() {
+			this.handleConfirmInit();
+		},
+		
+		// MapToolbar 方法别名
+		onZoomIn() {
+			this.handleZoomIn();
+		},
+		
+		onZoomOut() {
+			this.handleZoomOut();
+		},
+		
+		onCenterRobot() {
+			this.handleCenterToRobot();
+		},
+		
+		onToggleFullscreen() {
+			this.handleToggleFullscreen();
+		},
+		
+		// 辅助方法
+		getTaskStatusText(status) {
+			const statusMap = {
+				'idle': '空闲',
+				'running': '执行中',
+				'paused': '暂停'
+			};
+			return statusMap[status] || '未知';
+		},
+		
+		// === 导航页RightPanel事件处理 ===
+		
+		// 目标点事件
+		onWpSelect(waypoint) {
+			console.log('选择目标点:', waypoint);
+			this.$message.success(`已选择目标点: ${waypoint.name}`);
+		},
+		
+		onWpSend(waypoint) {
+			console.log('发送目标点:', waypoint);
+			this.$message.success(`已发送目标点: ${waypoint.name}`);
+		},
+		
+		onWpCreate() {
+			console.log('创建目标点');
+			this.$message.info('创建目标点功能待实现');
+		},
+		
+		onWpEdit(waypoint) {
+			console.log('编辑目标点:', waypoint);
+			this.pointEditDiaShow = true;
+			this.pointEditData.id = waypoint.id;
+			this.pointEditData.x = waypoint.x;
+			this.pointEditData.y = waypoint.y;
+			this.pointEditData.type = waypoint.type;
+			this.pointEditData.actionMenuList = waypoint.action ? [...waypoint.action] : [{ value: 0, other: 0 }];
+		},
+		
+		onWpRemove(waypoint) {
+			console.log('删除目标点:', waypoint);
+			// 从waypoints数组中删除目标点
+			this.waypoints = this.waypoints.filter(wp => wp.id !== waypoint.id);
+			// 如果删除的是选中的目标点,也要从选中列表中移除
+			this.selectedWaypointIds = this.selectedWaypointIds.filter(id => id !== waypoint.id);
+			this.$message.success(`已删除目标点: ${waypoint.name || '目标点'}`);
+		},
+		
+
+		// 新增的目标点操作方法
+		onWpMoveUp() {
+			if (this.selectedWaypointIds.length !== 1) return;
+			
+			const selectedId = this.selectedWaypointIds[0];
+			const index = this.waypoints.findIndex(wp => wp.id === selectedId);
+			
+			if (index > 0) {
+				// 交换位置
+				const temp = this.waypoints[index];
+				this.$set(this.waypoints, index, this.waypoints[index - 1]);
+				this.$set(this.waypoints, index - 1, temp);
+				this.$message.success('目标点已上移');
+			}
+		},
+
+		onWpMoveDown() {
+			if (this.selectedWaypointIds.length !== 1) return;
+			
+			const selectedId = this.selectedWaypointIds[0];
+			const index = this.waypoints.findIndex(wp => wp.id === selectedId);
+			
+			if (index < this.waypoints.length - 1) {
+				// 交换位置
+				const temp = this.waypoints[index];
+				this.$set(this.waypoints, index, this.waypoints[index + 1]);
+				this.$set(this.waypoints, index + 1, temp);
+				this.$message.success('目标点已下移');
+			}
+		},
+
+		onWpBatchRemove() {
+			if (this.selectedWaypointIds.length === 0) return;
+			
+			this.$confirm(`确定要删除选中的 ${this.selectedWaypointIds.length} 个目标点吗?`, '批量删除', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning'
+			}).then(() => {
+				// 删除选中的目标点
+				this.waypoints = this.waypoints.filter(wp => !this.selectedWaypointIds.includes(wp.id));
+				this.selectedWaypointIds = [];
+				this.$message.success('目标点删除成功');
+			}).catch(() => {});
+		},
+
+		onWpGoto() {
+			if (this.selectedWaypointIds.length !== 1) return;
+			
+			const selectedWaypoint = this.waypoints.find(wp => wp.id === this.selectedWaypointIds[0]);
+			if (selectedWaypoint) {
+				this.$message.success(`正在前往目标点: ${selectedWaypoint.name || '目标点' + selectedWaypoint.id} (${selectedWaypoint.x}, ${selectedWaypoint.y})`);
+				// 这里可以添加实际的导航逻辑
+			}
+		},
+
+		onWpGotoSingle(waypoint) {
+			this.$message.success(`正在前往目标点: ${waypoint.name || '目标点' + waypoint.id} (${waypoint.x}, ${waypoint.y})`);
+			// 这里可以添加实际的导航逻辑
+		},
+
+		onWpCreateTask() {
+			if (this.selectedWaypointIds.length === 0) return;
+			
+			const selectedWaypoints = this.waypoints.filter(wp => this.selectedWaypointIds.includes(wp.id));
+			console.log(`准备使用 ${selectedWaypoints.length} 个目标点创建任务`, selectedWaypoints);
+			
+			// 打开任务创建对话框
+			this.taskGenerateDiaShow = true;
+		},
+
+		onWpSelectionChange(selection) {
+			this.selectedWaypointIds = selection.map(wp => wp.id);
+			this.waypointSingle = selection.length !== 1;
+			this.waypointMultiple = selection.length === 0;
+			console.log('目标点选择变更:', this.selectedWaypointIds);
+		},
+
+		onMapSelectModeChange(isActive) {
+			this.selectPointMode = isActive;
+			this.initPoseMode = false; // 确保互斥
+			
+			if (isActive) {
+				this.$message.success('已开启地图选点模式,点击地图添加目标点');
+			} else {
+				this.$message.info('已关闭地图选点模式');
+			}
+		},
+
+		// === 目标点编辑相关方法 ===
+		
+		// 追加动作按钮
+		appendActionMenu() {
+			this.pointEditData.actionMenuList.push({ value: 0, other: 0 });
+		},
+		
+		// 删除追加动作按钮
+		removeActionMenu(index) {
+			this.pointEditData.actionMenuList.splice(index, 1);
+		},
+		
+		// 修改动作下拉值
+		changeAction(index) {
+			// 判断当前修改后是否是原定等待,如果不是则删除other属性
+			let item = this.pointEditData.actionMenuList[index];
+			if (item.value === 0) {
+				// 原地等待需要等待时间参数
+				if (!('other' in item)) {
+					item.other = 0;
+				}
+			} else {
+				// 其他动作不需要等待时间参数
+				if ('other' in item) {
+					delete item.other;
+				}
+			}
+		},
+		
+		// 提交点位修改
+		submitEditPoint() {
+			this.pointEditDiaShow = false;
+			// 查找要修改的目标点
+			const waypoint = this.waypoints.find(item => item.id === this.pointEditData.id);
+			if (waypoint) {
+				// 更新数据
+				waypoint.x = this.pointEditData.x;
+				waypoint.y = this.pointEditData.y;
+				waypoint.type = this.pointEditData.type;
+				waypoint.action = [...this.pointEditData.actionMenuList];
+				this.$message.success("目标点数据已修改");
+			}
+		},
+
+		// 清空编辑对话框数据
+		clearActionDia() {
+			this.pointEditData.id = '';
+			this.pointEditData.x = '';
+			this.pointEditData.y = '';
+			this.pointEditData.type = '';
+			this.pointEditData.actionMenuList = [];
+		},
+		
+		// 任务事件
+		onTaskView(task) {
+			console.log('查看任务详情:', task);
+			this.taskViewData = { ...task };
+			this.taskViewDiaShow = true;
+		},
+		
+		onTaskStart(task) {
+			console.log('开始任务:', task);
+			this.$message.success(`任务 ${task.taskName} 已开始`);
+		},
+		
+		onTaskPause(task) {
+			console.log('暂停任务:', task);
+			this.$message.warning(`任务 ${task.taskName} 已暂停`);
+		},
+		
+		onTaskStop(task) {
+			console.log('停止任务:', task);
+			this.$message.error(`任务 ${task.taskName} 已停止`);
+		},
+		
+		onTaskRemove(task) {
+			console.log('删除任务:', task);
+			this.$message.warning(`任务 ${task.taskName} 已删除`);
+		},
+		
+		// 格式化方法
+		getTaskStatusText(status) {
+			const statusMap = {
+				0: '运行中',
+				1: '空闲',
+				'idle': '空闲',
+				'running': '运行中',
+				'paused': '暂停',
+				'completed': '已完成',
+				'error': '失败'
+			}
+			return statusMap[status] || '未知'
+		},
+		
+		getTaskStatusClass(status) {
+			const statusClassMap = {
+				0: 'status-running',
+				1: 'status-idle',
+				'idle': 'status-idle',
+				'running': 'status-running',
+				'paused': 'status-paused',
+				'completed': 'status-completed',
+				'error': 'status-error'
+			}
+			return statusClassMap[status] || 'status-unknown'
+		},
+		
+		formatTime(time) {
+			if (!time) return '--'
+			if (typeof time === 'string') return time
+			if (time instanceof Date) {
+				return time.toLocaleTimeString('zh-CN', { 
+					hour12: false,
+					hour: '2-digit',
+					minute: '2-digit'
+				})
+			}
+			return '--'
+		},
+		
+		formatDate(dateArray) {
+			if (!dateArray || !Array.isArray(dateArray) || dateArray.length === 0) return '--'
+			
+			const dayNames = {
+				'1': '周一',
+				'2': '周二', 
+				'3': '周三',
+				'4': '周四',
+				'5': '周五',
+				'6': '周六',
+				'7': '周日'
+			}
+			
+			return dateArray.map(day => dayNames[day] || day).join(', ')
+		},
+		
+
+		// 功能设置变更处理
+		onSettingChange(setting) {
+			console.log('功能设置变更:', setting);
+			this.settingParams[setting.key] = setting.value;
+			
+			// 根据设置项类型执行相应操作
+			switch(setting.key) {
+				case 'pointCloud':
+					this.$message.info(`点云显示已${setting.value ? '开启' : '关闭'}`);
+					// 这里可以调用地图组件的点云显示/隐藏方法
+					break;
+				case 'baseMap':
+					this.$message.info(`底图显示已${setting.value ? '开启' : '关闭'}`);
+					// 这里可以调用地图组件的底图显示/隐藏方法
+					break;
+				case 'pointId':
+					this.$message.info(`点ID显示已${setting.value ? '开启' : '关闭'}`);
+					// 这里可以调用地图组件的点ID显示/隐藏方法
+					break;
+				case 'follow':
+					this.$message.info(`位置跟随已${setting.value ? '开启' : '关闭'}`);
+					// 这里可以调用地图组件的跟随模式开启/关闭方法
+					break;
+				case 'network':
+					this.$message.info(`网络邻居显示已${setting.value ? '开启' : '关闭'}`);
+					// 这里可以调用相关的网络邻居显示/隐藏方法
+					break;
+			}
+		},
+		
+	},
+	
+	watch: {
+		// 监听面板可见性变化,触发地图刷新
+		panelVisible() {
+			this.$nextTick(() => {
+				this.updateOlCss();
+			});
+		},
+		
+		// 监听选点模式变化
+		selectPointMode(newVal) {
+			if (newVal) {
+				this.initPoseMode = false; // 确保互斥
+			}
+		},
+		
+		// 监听初始化模式变化
+		initPoseMode(newVal) {
+			if (newVal) {
+				this.selectPointMode = false; // 确保互斥
+			}
+		},
+		
+		// 监听实时信息变化,同步机器人位姿数据
+		'realtimeInfo.coordinates': {
+			handler(newCoordinates) {
+				if (newCoordinates) {
+					const position = RobotPositionUtils.parseCoordinates(newCoordinates);
+					if (position) {
+						this.robotPoseData.x = position.x;
+						this.robotPoseData.y = position.y;
+						// 角度从heading字段解析,这里先保持不变
+						// this.robotPoseData.angle = parseFloat(this.realtimeInfo.heading.replace('°', '')) || 0;
+					}
+				}
+			},
+			immediate: true
+		}
+	}
+};
+</script>
+
+<style scoped>
+.point-edit-span {
+	display: block;
+	margin: 10px 0;
+	font-weight: bold;
+}
+
+.drawer {
+	height: 100%;
+	position: absolute;
+	top: 0;
+	left: 100%;
+	/* box-shadow: 4px 4px 12px rgba(201, 201, 201, 0.2); */
+	/* 右边和下边的阴影 */
+	border-radius: 0 0 12px 0;
+	border-left: 1px solid #F0F0F0;
+	padding: 8px 15px;
+	border-right: 1px solid #ececec;
+	border-bottom: 1px solid #ececec;
+	overflow-y: auto;
+	background-color: #fff;
+	z-index: 1000;
+}
+
+.drawer-close {
+	position: absolute;
+	right: 3px;
+	top: 3px;
+	cursor: pointer;
+}
+
+.drawer-title {
+	position: absolute;
+	top: -23px;
+	left: -8px;
+	font-size: 13px;
+	font-weight: bold;
+	color: #838383;
+}
+
+.drawer p {
+	font-size: 13px;
+	border-left: 5px #D1D1D1 solid;
+	padding-left: 5px;
+	margin: 8px 0;
+	border-radius: 3px 0 0 3px;
+}
+
+.img-container {
+	text-align: center;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	/* 垂直居中子元素 */
+	border-radius: 7px;
+	background: linear-gradient(135deg, #00bcd4, #009688);
+	cursor: pointer;
+	width: 70%;
+	aspect-ratio: 1;
+	/* 设置宽高比为1,即高度和宽度相等 */
+	margin-top: 10px;
+}
+
+.img-container:hover {
+	transform: scale(1.02);
+	/* 鼠标悬停时放大 */
+	box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
+	/* 增加阴影效果 */
+	background-color: #00796b;
+	/* 改变背景颜色 */
+}
+
+.img-container:active {
+	transform: scale(0.98);
+	/* 点击时缩小 */
+	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
+	/* 点击时加深阴影 */
+	background-color: #004d40;
+	/* 点击时改变背景颜色 */
+	filter: brightness(1.1);
+	/* 点击时稍微增加亮度 */
+}
+
+.img-container img {
+	opacity: 1;
+}
+
+.img-container span {
+	font-size: 12px;
+	color: #ffffff;
+	font-weight: bold;
+}
+
+/* 激活时的样式 */
+.img-container.active {
+	background: linear-gradient(135deg, #007d8d, #004b43);
+}
+
+.explore-unit {
+	margin-left: 8px;
+}
+
+::v-deep .el-dialog__body {
+	padding: 20px 20px 0 20px;
+}
+
+::v-deep .download-map .el-dialog__body {
+	padding: 10px 20px 0 20px !important;
+}
+
+::v-deep .el-table--medium .el-table__cell {
+	padding: 6px 0;
+}
+
+::v-deep .action-menu .action-menu_input .el-input__inner {
+	padding: 0 5px;
+}
+
+.task-status-tag {
+	margin-left: 20px;
+}
+
+::v-deep .drawer .el-collapse-item__header {
+	height: 38px;
+	line-height: 38px;
+	color: #767676;
+	font-weight: bold;
+}
+
+::v-deep .drawer .el-collapse-item__content {
+	text-align: left;
+	padding-bottom: 10px;
+}
+
+::v-deep .drawer .el-collapse {
+	border: 1px solid #EBEEF5;
+	padding: 0 8px;
+	border-radius: 5px;
+}
+
+.collapse-content-div {
+	margin-top: 0;
+}
+
+::v-deep .collapse-content-div .el-button--mini {
+	padding: 4px 10px;
+}
+
+
+.hand-ment-mark {
+	position: absolute;
+	bottom: 12px;
+	left: 12px;
+	z-index: 1000;
+}
+
+
+.notification__title {
+	font-size: 1.2rem;
+	/* 默认字体大小 */
+}
+
+.navigation-container {
+	width: 100%;
+	min-height: calc(100vh - 84px);
+	overflow: hidden;
+	position: relative;
+	background: var(--color-bg-secondary);
+
+	.map-stage {
+		position: relative;
+	width: 100%;
+		height: calc(100vh - 84px);
+		min-height: 600px;
+		overflow: hidden;
+		background: var(--color-bg-secondary);
+	}
+}
+
+/* 新UI浮层样式 - 重新设计为浮动面板 */
+.nav-toolbar {
+	position: absolute;
+	left: 16px;
+	top: 96px;
+	z-index: 50;
+}
+
+
+
+
+.main-menu {
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+}
+
+/* 目标点编辑对话框样式 */
+::v-deep .waypoint-edit-dialog {
+	/* 修复问题1:紫色标题栏圆角对齐 */
+	.el-dialog {
+		border-radius: 12px !important;
+		overflow: hidden !important; /* 确保子元素不会超出圆角 */
+		margin-top: 0 !important; /* 移除默认的上边距 */
+		margin-bottom: 0 !important; /* 移除默认的下边距 */
+		
+		/* 确保对话框垂直居中 */
+		position: fixed !important;
+		top: 50% !important;
+		left: 50% !important;
+		transform: translate(-50%, -50%) !important;
+	}
+	
+	.el-dialog__header {
+		background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+	color: white;
+		padding: 20px 24px 16px;
+		margin: 0;
+		border-radius: 12px 12px 0 0 !important; /* 只有上方圆角 */
+		
+		.el-dialog__title {
+			color: white;
+			font-weight: 600;
+			font-size: 16px;
+		}
+		
+		.el-dialog__close {
+			color: white;
+			font-size: 18px;
+			
+			&:hover {
+				color: #f0f0f0;
+			}
+		}
+	}
+	
+	.el-dialog__body {
+		padding: 24px;
+		background: #f8fafc;
+		margin: 0 !important; /* 确保没有额外边距 */
+	}
+	
+	.el-dialog__footer {
+		padding: 16px 24px 24px;
+		background: #f8fafc;
+		border-top: 1px solid #e2e8f0;
+		border-radius: 0 0 12px 12px !important; /* 只有下方圆角 */
+		margin: 0 !important; /* 确保没有额外边距 */
+	}
+}
+
+.dialog-content {
+	.form-section {
+		background: white;
+		border-radius: 10px; /* 稍微增加圆角,与整体设计更协调 */
+		padding: 24px; /* 增加内边距,让内容更宽松 */
+		margin-bottom: 20px; /* 增加卡片间距 */
+		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); /* 稍微增强阴影 */
+		border: 1px solid #f1f5f9; /* 添加淡边框 */
+		
+		&:last-child {
+			margin-bottom: 0;
+		}
+		
+		.section-title {
+	display: flex;
+	align-items: center;
+			margin: 0 0 20px 0; /* 增加标题与内容的间距 */
+			font-size: 15px; /* 稍微增加字体大小 */
+			font-weight: 600;
+			color: #2d3748;
+			border-bottom: 2px solid #e2e8f0;
+			padding-bottom: 10px; /* 增加下内边距 */
+			
+			i {
+				margin-right: 10px; /* 增加图标与文字的间距 */
+				color: #667eea;
+				font-size: 18px; /* 稍微增加图标大小 */
+			}
+			
+			/* 添加动作按钮样式优化 */
+			.add-action-btn {
+				margin-left: 12px !important;
+				display: inline-flex !important;
+				align-items: center !important;
+				padding: 4px 8px !important;
+				
+				i {
+					margin-right: 4px !important; /* 减少图标与文字的间距 */
+					font-size: 12px !important;
+					color: #667eea !important;
+					display: inline-block !important;
+					vertical-align: middle !important;
+				}
+				
+				span {
+					font-size: 12px !important;
+					color: #667eea !important;
+					line-height: 1 !important;
+					vertical-align: middle !important;
+				}
+				
+				&:hover {
+					i, span {
+						color: #409eff !important;
+					}
+				}
+			}
+		}
+	}
+	
+	.waypoint-form {
+		.el-form-item {
+			margin-bottom: 18px; /* 适中的表单项间距 */
+			display: flex !important; /* 使用flex布局 */
+			align-items: center !important; /* 标签和输入框水平对齐 */
+			
+			&:last-child {
+				margin-bottom: 0;
+			}
+			
+			/* 确保输入框容器占用剩余空间 */
+			.el-form-item__content {
+				flex: 1 !important;
+				margin-left: 0 !important; /* 移除默认左边距 */
+			}
+		}
+		
+		/* 坐标输入框特殊样式 */
+		.coordinate-input {
+			margin-bottom: 4px; /* 坐标输入框之间的间距稍小 */
+		}
+		
+		.el-form-item__label {
+			font-weight: 600 !important; /* 增加字体粗细,更突出 */
+			color: #2d3748 !important; /* 更深的颜色,更清晰 */
+			padding-right: 12px !important; /* 适当的间距 */
+			min-width: 100px !important; /* 稍微增加宽度,适应新的标签 */
+			font-size: 14px !important; /* 统一字体大小 */
+			line-height: 44px !important; /* 与输入框高度保持一致,实现垂直居中 */
+			height: 44px !important; /* 设置标签高度与输入框一致 */
+			display: flex !important; /* 使用flex布局 */
+			align-items: center !important; /* 垂直居中对齐 */
+			margin-bottom: 0 !important; /* 移除默认下边距 */
+		}
+		
+		/* 优化坐标输入框样式 - 分行布局 */
+		.coordinate-input {
+			.el-input__inner {
+				border-radius: 8px !important; /* 稍微增加圆角 */
+				border: 1px solid #e2e8f0 !important;
+				height: 44px !important; /* 增加输入框高度,更宽松 */
+				font-size: 15px !important; /* 增加字体大小,更易读 */
+				padding: 0 16px !important; /* 增加左右内边距 */
+				background: #ffffff !important;
+				transition: all 0.2s ease !important;
+				
+				&:focus {
+					border-color: #667eea !important;
+					box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
+					background: #fafbff !important;
+				}
+				
+				&:hover {
+					border-color: #cbd5e0 !important;
+				}
+			}
+		}
+		
+		/* 通用输入框样式 */
+		.el-input {
+			.el-input__inner {
+				border-radius: 6px;
+				border: 1px solid #e2e8f0;
+				height: 40px !important;
+				font-size: 14px !important;
+				padding: 0 12px !important;
+				
+				&:focus {
+					border-color: #667eea;
+					box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
+				}
+			}
+		}
+		
+		.el-select {
+			.el-input__inner {
+				border-radius: 6px;
+				height: 40px !important; /* 与输入框保持一致的高度 */
+				font-size: 14px !important;
+			}
+		}
+	}
+	
+	.action-list {
+		.action-item {
+			background: #f7fafc;
+			border: 1px solid #e2e8f0;
+			border-radius: 8px;
+			padding: 12px;
+			margin-bottom: 12px;
+			transition: all 0.2s ease;
+			
+			&:hover {
+				border-color: #cbd5e0;
+				box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+			}
+			
+			&:last-child {
+				margin-bottom: 0;
+			}
+			
+			.action-header {
+	display: flex;
+	align-items: center;
+				gap: 12px;
+				margin-bottom: 8px;
+				
+				.action-index {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 24px;
+					height: 24px;
+					background: #667eea;
+					color: white;
+					border-radius: 50%;
+					font-size: 12px;
+					font-weight: 600;
+					flex-shrink: 0;
+				}
+				
+				.remove-btn {
+					color: #e53e3e;
+					padding: 4px;
+					
+					&:hover {
+						background: #fed7d7;
+						color: #c53030;
+					}
+				}
+			}
+			
+			.action-params {
+				padding-left: 36px;
+				margin-top: 12px; /* 增加与上方的间距 */
+				display: flex !important; /* 使用flex布局 */
+				align-items: center !important; /* 垂直居中对齐 */
+				flex-wrap: nowrap !important; /* 防止换行 */
+				
+				/* 修复问题3:优化等待时间输入框样式 */
+				.el-input {
+					display: inline-flex !important; /* 改为inline-flex,防止换行 */
+					width: 160px !important; /* 稍微增加宽度,给"秒"单位更多空间 */
+					align-items: center !important; /* 确保垂直居中 */
+					
+					.el-input__inner {
+						background: white;
+						height: 36px !important; /* 适中的高度 */
+						font-size: 14px !important;
+						border-radius: 6px !important;
+						border: 1px solid #e2e8f0 !important;
+						padding: 0 12px !important;
+						flex: 1 !important; /* 输入框占用主要空间 */
+						
+						&:focus {
+							border-color: #667eea;
+							box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
+						}
+					}
+					
+					/* 修复问题3:优化"秒"单位的append样式 */
+					.el-input-group__append {
+						background: #f8fafc !important;
+						border-color: #e2e8f0 !important;
+						color: #4a5568 !important;
+						font-weight: 500 !important;
+						padding: 0 12px !important; /* 调整内边距 */
+						border-radius: 0 6px 6px 0 !important;
+						font-size: 14px !important;
+						min-width: 40px !important; /* 增加最小宽度 */
+						height: 36px !important; /* 明确设置高度 */
+						display: flex !important;
+						align-items: center !important;
+						justify-content: center !important;
+						border-left: none !important; /* 移除左边框,与输入框无缝连接 */
+						white-space: nowrap !important; /* 防止文字换行 */
+						flex-shrink: 0 !important; /* 防止收缩 */
+					}
+				}
+			}
+		}
+	}
+}
+
+::v-deep .dialog-footer {
+	text-align: right;
+	
+	.el-button {
+		padding: 10px 20px;
+		border-radius: 6px;
+		font-weight: 500;
+		
+		&.el-button--primary {
+			background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+			border: none;
+			
+			&:hover {
+				opacity: 0.9;
+			}
+		}
+	}
+}
+
+/* 创建任务对话框样式 */
+::v-deep .task-create-dialog {
+	/* 修复问题1:紫色标题栏圆角对齐 */
+	.el-dialog {
+		border-radius: 12px !important;
+		overflow: hidden !important; /* 确保子元素不会超出圆角 */
+		margin-top: 0 !important; /* 移除默认的上边距 */
+		margin-bottom: 0 !important; /* 移除默认的下边距 */
+		
+		/* 确保对话框垂直居中 */
+		position: fixed !important;
+		top: 50% !important;
+		left: 50% !important;
+		transform: translate(-50%, -50%) !important;
+	}
+	
+	.el-dialog__header {
+		background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+		color: white;
+		padding: 20px 24px 16px;
+		margin: 0;
+		border-radius: 12px 12px 0 0 !important; /* 只有上方圆角 */
+		
+		.el-dialog__title {
+			color: white;
+			font-weight: 600;
+			font-size: 16px;
+		}
+		
+		.el-dialog__close {
+			color: white;
+			font-size: 18px;
+			
+			&:hover {
+				color: #f0f0f0;
+			}
+		}
+	}
+	
+	.el-dialog__body {
+		padding: 24px;
+		background: #fafbfc;
+	}
+	
+	.el-dialog__footer {
+		background: white;
+		padding: 16px 24px;
+		border-radius: 0 0 12px 12px !important; /* 只有下方圆角 */
+		border-top: 1px solid #e2e8f0;
+		text-align: right;
+		
+		.el-button {
+			padding: 10px 20px;
+			font-weight: 500;
+			border-radius: 6px;
+			
+			&:not(.el-button--primary) {
+				color: #64748b;
+				border-color: #cbd5e1;
+				background: white;
+				
+				&:hover {
+					color: #475569;
+					border-color: #94a3b8;
+					background: #f8fafc;
+				}
+			}
+			
+			&.el-button--primary {
+				background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+				border: none;
+				
+				&:hover {
+					background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
+				}
+			}
+		}
+	}
+}
+
+.task-form {
+	.el-form-item {
+		margin-bottom: 18px; /* 适中的表单项间距 */
+		display: flex !important; /* 使用flex布局 */
+		align-items: center !important; /* 标签和输入框水平对齐 */
+		
+		.el-form-item__label {
+			color: #374151;
+			font-weight: 500;
+			line-height: 44px !important; /* 与输入框高度保持一致,实现垂直居中 */
+			height: 44px !important; /* 设置标签高度与输入框一致 */
+			display: flex !important; /* 使用flex布局 */
+			align-items: center !important; /* 垂直居中对齐 */
+			margin-bottom: 0 !important; /* 移除默认下边距 */
+		}
+		
+		.el-form-item__content {
+			flex: 1 !important;
+			margin-left: 0 !important; /* 移除默认左边距 */
+		}
+	}
+}
+
+.task-input {
+	.el-input__inner {
+		background: white;
+		height: 44px !important; /* 统一输入框高度 */
+		font-size: 14px !important;
+		border-radius: 8px !important; /* 现代化圆角 */
+		border: 1px solid #e2e8f0 !important;
+		padding: 0 16px !important; /* 增加内边距 */
+		transition: all 0.2s ease !important;
+		
+		&:focus {
+			border-color: #667eea !important;
+			box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
+			background: white !important;
+		}
+		
+		&::placeholder {
+			color: #9ca3af !important;
+			font-size: 14px !important;
+		}
+	}
+}
+
+.task-input-number {
+	width: 100% !important;
+	display: block !important; /* 确保占满整行 */
+	
+	.el-input-number__decrease,
+	.el-input-number__increase {
+		background: #f8fafc !important;
+		border-color: #e2e8f0 !important;
+		color: #667eea !important;
+		width: 32px !important; /* 固定按钮宽度 */
+		height: 22px !important; /* 调整按钮高度,让上下按钮都能显示 */
+		line-height: 20px !important; /* 调整行高 */
+		
+		&:hover {
+			background: #667eea !important;
+			color: white !important;
+		}
+	}
+	
+	.el-input-number__increase {
+		border-radius: 0 8px 0 0 !important; /* 上按钮圆角 */
+	}
+	
+	.el-input-number__decrease {
+		border-radius: 0 0 8px 0 !important; /* 下按钮圆角 */
+	}
+	
+	.el-input {
+		width: 100% !important; /* 确保input容器占满宽度 */
+	}
+	
+	.el-input__inner {
+		background: white !important;
+		height: 44px !important;
+		font-size: 14px !important;
+		border-radius: 8px !important;
+		border: 1px solid #e2e8f0 !important;
+		padding: 0 68px 0 16px !important; /* 右侧留出按钮空间 */
+		text-align: left !important;
+		width: 100% !important; /* 确保输入框占满宽度 */
+		
+		&:focus {
+			border-color: #667eea !important;
+			box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
+		}
+	}
+}
+
+.task-time-picker {
+	width: 100% !important;
+	display: block !important; /* 确保占满整行 */
+	
+	.el-input {
+		width: 100% !important; /* 确保input容器占满宽度 */
+	}
+	
+	.el-input__inner {
+		background: white !important;
+		height: 44px !important;
+		font-size: 14px !important;
+		border-radius: 8px !important;
+		border: 1px solid #e2e8f0 !important;
+		padding: 0 80px 0 16px !important; /* 大幅增加右侧内边距,从60px到80px */
+		width: 100% !important; /* 确保输入框占满宽度 */
+		box-sizing: border-box !important; /* 确保padding计算正确 */
+		text-overflow: ellipsis !important; /* 文字溢出处理 */
+		overflow: hidden !important;
+		white-space: nowrap !important;
+		
+		&:focus {
+			border-color: #667eea !important;
+			box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
+		}
+		
+		&::placeholder {
+			color: #9ca3af !important;
+		}
+	}
+	
+	.el-input__suffix {
+		right: 24px !important; /* 进一步增加右侧距离 */
+		width: 40px !important; /* 增加图标区域宽度 */
+		text-align: center !important;
+		display: flex !important;
+		align-items: center !important;
+		justify-content: center !important;
+		height: 44px !important; /* 确保高度与输入框一致 */
+		
+		.el-input__icon {
+			color: #9ca3af !important;
+			font-size: 16px !important;
+			margin: 0 !important; /* 移除任何默认边距 */
+		}
+	}
+}
+
+.task-date-group {
+	display: flex !important;
+	flex-wrap: wrap !important;
+	gap: 8px 16px !important;
+	
+	.el-checkbox {
+		margin-right: 0 !important;
+		margin-bottom: 8px !important;
+		
+		.el-checkbox__label {
+			color: #374151 !important;
+			font-weight: 500 !important;
+			font-size: 14px !important;
+			padding-left: 8px !important;
+		}
+		
+		.el-checkbox__input.is-checked {
+			.el-checkbox__inner {
+				background-color: #667eea !important;
+				border-color: #667eea !important;
+			}
+		}
+		
+		.el-checkbox__inner {
+			border-color: #d1d5db !important;
+			
+			&:hover {
+				border-color: #667eea !important;
+			}
+		}
+	}
+}
+
+/* 任务查看对话框样式 */
+::v-deep .task-view-dialog {
+	.el-dialog {
+		border-radius: 12px !important;
+		overflow: hidden !important;
+		margin-top: 0 !important;
+		margin-bottom: 0 !important;
+		
+		position: fixed !important;
+		top: 50% !important;
+		left: 50% !important;
+		transform: translate(-50%, -50%) !important;
+	}
+	
+	.el-dialog__header {
+		background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+		color: white;
+		padding: 20px 24px 16px;
+		margin: 0;
+		border-radius: 12px 12px 0 0 !important;
+		
+		.el-dialog__title {
+			color: white;
+			font-weight: 600;
+			font-size: 16px;
+		}
+		
+		.el-dialog__close {
+			color: white;
+			font-size: 18px;
+			
+			&:hover {
+				color: #f0f0f0;
+			}
+		}
+	}
+	
+	.el-dialog__body {
+		padding: 24px;
+		background: #fafbfc;
+	}
+	
+	.el-dialog__footer {
+		background: white;
+		padding: 16px 24px;
+		border-radius: 0 0 12px 12px !important;
+		border-top: 1px solid #e2e8f0;
+		text-align: right;
+		
+		.el-button {
+			padding: 10px 20px;
+			font-weight: 500;
+			border-radius: 6px;
+			color: #64748b;
+			border-color: #cbd5e1;
+			background: white;
+			
+			&:hover {
+				color: #475569;
+				border-color: #94a3b8;
+				background: #f8fafc;
+			}
+		}
+	}
+}
+
+.task-view-form {
+	.el-form-item {
+		margin-bottom: 20px;
+		display: flex !important;
+		align-items: center !important;
+		min-height: 32px;
+		
+		&:last-child {
+			margin-bottom: 20px;
+		}
+		
+		.el-form-item__label {
+			color: #374151;
+			font-weight: 500;
+			line-height: 1 !important;
+			display: flex !important;
+			align-items: center !important;
+			margin-bottom: 0 !important;
+			height: auto !important;
+			padding: 0 !important;
+		}
+		
+		.el-form-item__content {
+			flex: 1 !important;
+			margin-left: 0 !important;
+			display: flex !important;
+			align-items: center !important;
+		}
+	}
+	
+	.form-text {
+		color: #606266;
+		font-size: 14px;
+		line-height: 1;
+		display: flex;
+		align-items: center;
+		
+		&.status-text {
+			display: inline-flex;
+			align-items: center;
+			justify-content: center;
+			padding: 6px 12px;
+			border-radius: 16px;
+			font-size: 12px;
+			font-weight: 600;
+			text-align: center;
+			min-width: 60px;
+			line-height: 1;
+			border: 1px solid transparent;
+			margin: 0;
+			
+			&.status-idle {
+				background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
+				color: #0369a1;
+				border-color: #bae6fd;
+				box-shadow: 0 1px 3px rgba(3, 105, 161, 0.1);
+			}
+			
+			&.status-running {
+				background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
+				color: #15803d;
+				border-color: #bbf7d0;
+				box-shadow: 0 1px 3px rgba(21, 128, 61, 0.1);
+			}
+			
+			&.status-paused {
+				background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
+				color: #d97706;
+				border-color: #fed7aa;
+				box-shadow: 0 1px 3px rgba(217, 119, 6, 0.1);
+			}
+			
+			&.status-completed {
+				background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
+				color: #15803d;
+				border-color: #bbf7d0;
+				box-shadow: 0 1px 3px rgba(21, 128, 61, 0.1);
+			}
+			
+			&.status-error {
+				background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
+				color: #dc2626;
+				border-color: #fecaca;
+				box-shadow: 0 1px 3px rgba(220, 38, 38, 0.1);
+			}
+		}
+	}
+	
+}
+</style>