ソースを参照

更新 /map 路由对应的页面 AMap.vue

reghao 1 日 前
コミット
2e91699a25
2 ファイル変更120 行追加168 行削除
  1. 16 3
      src/router/index.js
  2. 104 165
      src/views/map/AMap.vue

+ 16 - 3
src/router/index.js

@@ -4,7 +4,6 @@ import Vue from 'vue'
 import DiskRouter from './disk'
 import UserRouter from './user'
 import BlogRouter from './blog'
-import MapRouter from './map'
 import AiRouter from './ai'
 import BackgroundDevopsRouter from './background_devops'
 import BackgroundAccountRouter from './background_account'
@@ -24,7 +23,6 @@ const Home = () => import('views/home/Home')
 const TimelineIndex = () => import('views/home/Timeline')
 const RegionIndex = () => import('views/home/Region')
 const VideoTag = () => import('views/home/VideoTag')
-const ShortVideoIndex = () => import('views/home/ShortVideo')
 const VideoPage = () => import('views/home/VideoPage')
 const AudioIndex = () => import('views/home/Audio')
 const AudioPage = () => import('views/home/AudioPage')
@@ -33,6 +31,10 @@ const PlaylistIndex = () => import('views/home/PlaylistIndex')
 const PlaylistView = () => import('views/home/PlaylistView')
 const SearchIndex = () => import('views/home/SearchIndex')
 
+const ShortVideoIndex = () => import('views/home/ShortVideo')
+const AMap = () => import('views/map/AMap')
+const OpenLayersMap = () => import('views/map/OpenLayersMap')
+
 const Index = () => import('views/Index')
 const Login = () => import('views/Login')
 const Register = () => import('views/Register')
@@ -47,7 +49,6 @@ export const constantRoutes = [
   DiskRouter,
   UserRouter,
   BlogRouter,
-  MapRouter,
   AiRouter,
   {
     path: '/',
@@ -137,6 +138,18 @@ export const constantRoutes = [
     component: ShortVideoIndex,
     meta: { needAuth: false }
   },
+  {
+    path: '/map',
+    name: 'AMap',
+    component: AMap,
+    meta: { title: 'Map', needAuth: false }
+  },
+  {
+    path: '/map1',
+    name: 'OpenLayersMap',
+    component: OpenLayersMap,
+    meta: { title: 'OL Map', needAuth: false }
+  },
   {
     path: '/bg',
     name: 'BackgroundIndex',

+ 104 - 165
src/views/map/AMap.vue

@@ -1,11 +1,14 @@
 <template>
-  <el-container class="map-sub-container">
-    <el-header height="50px" class="operation-header">
-      <div class="left-tip">
+  <div class="map-full-container">
+    <div id="container" class="amap-instance" />
+
+    <div class="map-overlay-controls">
+      <div class="control-group tip-group">
         <i class="el-icon-info" />
         <span>点击地图触发操作</span>
       </div>
-      <div class="right-actions">
+
+      <div class="control-group button-group">
         <el-button
           :type="enableAddPath ? 'success' : 'primary'"
           size="small"
@@ -17,15 +20,11 @@
         <el-button type="info" size="small" icon="el-icon-guide" @click="onPathNavigator">
           路径巡航
         </el-button>
-        <el-button type="danger" size="small" plain icon="el-icon-delete" @click="clearCircle">
-          清除
+        <el-button type="danger" size="small" icon="el-icon-delete" @click="clearCircle">
+          清除
         </el-button>
       </div>
-    </el-header>
-
-    <el-main class="map-main-wrapper">
-      <div id="container" class="amap-instance" />
-    </el-main>
+    </div>
 
     <el-dialog
       :visible.sync="showPositionDialog"
@@ -71,31 +70,29 @@
         </div>
       </div>
     </el-dialog>
-  </el-container>
+  </div>
 </template>
 
 <script>
 import AMapLoader from '@amap/amap-jsapi-loader'
-import {addGeoPosition, addMyPosition, addPath, getGeoPoint} from '@/api/map'
+import { addGeoPosition, addMyPosition, addPath, getGeoPoint } from '@/api/map'
 
 export default {
   name: 'AMap',
   data() {
     return {
       amap: null,
-      map: null, // 高德地图实例
-      AMap: null, // AMap 构造函数引用
-      zoom: 16,
+      map: null,
+      AMap: null,
+      zoom: 12, // 比例尺 10 公里
+      center: [104.068071, 30.576432],
       path: [],
       mapCircle: null,
       circleEditor: null,
       showPositionDialog: false,
       showInput: false,
-      radius: 1000,
-      positionForm: {
-        lng: null,
-        lat: null
-      },
+      radius: 1000, // 半径 1 a 公里
+      positionForm: { lng: null, lat: null },
       pointArr: [],
       mapKeys: {
         securityJsCode: '983d6ee43bab3edf3693e91508f94aa9',
@@ -104,7 +101,6 @@ export default {
       addPathText: '添加路径',
       enableAddPath: false,
       pathPointList: [],
-      // 新增预览相关的覆盖物数组
       previewMarkers: [],
       previewPolyline: null
     }
@@ -112,11 +108,10 @@ export default {
   mounted() {
     this.initAMap()
   },
-  unmounted() {
-    this.map?.destroy()
-  },
-  created() {
-    document.title = '地图'
+  beforeDestroy() {
+    if (this.map) {
+      this.map.destroy()
+    }
   },
   methods: {
     initAMap() {
@@ -138,7 +133,9 @@ export default {
         this.map = new AMap.Map('container', {
           viewMode: '2D',
           zoom: this.zoom,
-          center: [104.065753, 30.657462]
+          center: this.center,
+          features: ['bg', 'point', 'road'],
+          mapStyle: 'amap://styles/light'
         })
 
         this.map.on('click', (e) => {
@@ -146,11 +143,9 @@ export default {
           const lat = e.lnglat.getLat()
 
           if (this.enableAddPath) {
-            // 1. 记录点数据
             const point = { lng: lng, lat: lat }
             this.pathPointList.push(point)
 
-            // 2. 添加预览 Marker
             const marker = new AMap.Marker({
               position: e.lnglat,
               map: this.map,
@@ -161,7 +156,6 @@ export default {
             })
             this.previewMarkers.push(marker)
 
-            // 3. 更新预览折线 Polyline
             const pathArr = this.pathPointList.map(item => [item.lng, item.lat])
             if (this.previewPolyline) {
               this.previewPolyline.setPath(pathArr)
@@ -175,12 +169,12 @@ export default {
                 map: this.map
               })
             }
-            this.$message.info('已添加第 ' + this.pathPointList.length + ' 个预览点')
           } else {
             this.pointArr = [lng, lat]
             this.positionForm.lng = lng
             this.positionForm.lat = lat
             this.showPositionDialog = true
+            this.showInput = false // 重置输入状态
           }
         })
       }).catch((e) => {
@@ -188,44 +182,32 @@ export default {
       })
     },
 
-    // 修改 addPath 逻辑,包含清除预览的逻辑
     addPath() {
       if (!this.enableAddPath) {
-        // 进入添加模式
         this.enableAddPath = true
         this.addPathText = '完成添加'
-        this.clearPreviewOverlays() // 开启前清空旧预览
+        this.clearPreviewOverlays()
         this.pathPointList = []
       } else {
-        // 结束添加模式并提交
         if (this.pathPointList.length < 2) {
-          this.$message.warning('请至少在地图上点击两个点以形成路径')
+          this.$message.warning('请至少点击两个点')
           return
         }
-
         this.enableAddPath = false
         this.addPathText = '添加路径'
-
         addPath(this.pathPointList).then(resp => {
           if (resp.code === 0) {
             this.$message.success('路径保存成功')
-            // 将当前添加成功的路径加入本地 path 列表
-            const pathTrail = {
-              path: this.pathPointList.map(p => [p.lng, p.lat])
-            }
-            this.path.push(pathTrail)
           }
         }).finally(() => {
-          // 清除预览效果
           this.clearPreviewOverlays()
           this.pathPointList = []
         })
       }
     },
 
-    // 清除预览 Marker 和 Polyline 的私有方法
     clearPreviewOverlays() {
-      if (this.previewMarkers && this.previewMarkers.length > 0) {
+      if (this.previewMarkers.length > 0) {
         this.map.remove(this.previewMarkers)
         this.previewMarkers = []
       }
@@ -236,28 +218,21 @@ export default {
     },
 
     drawCircle(pointArr, radius) {
-      var center = new this.AMap.LngLat(pointArr[0], pointArr[1])
-      var circle = new this.AMap.Circle({
+      const center = new this.AMap.LngLat(pointArr[0], pointArr[1])
+      const circle = new this.AMap.Circle({
         center: center,
         radius: radius,
-        borderWeight: 3,
         strokeColor: '#ff3333',
-        strokeOpacity: 1,
-        strokeWeight: 1,
-        fillOpacity: 0.4,
-        strokeStyle: 'line',
-        strokeDasharray: [10, 10],
         fillColor: '#1791fc',
+        fillOpacity: 0.4,
         zIndex: 50
       })
-
       this.map.add(circle)
       this.map.setFitView([circle])
       this.mapCircle = circle
-
       const that = this
       this.map.plugin(['AMap.CircleEditor'], function() {
-        var circleEditor = new that.AMap.CircleEditor(that.map, circle)
+        const circleEditor = new that.AMap.CircleEditor(that.map, circle)
         circleEditor.open()
         that.circleEditor = circleEditor
       })
@@ -266,29 +241,17 @@ export default {
     onPathNavigator() {
       getGeoPoint().then(resp => {
         if (resp.code === 0) {
-          const pathList = resp.data
-          if (pathList.length === 0) {
-            this.$message.warning('暂无路径数据')
-            return
-          }
-          this.path = pathList
-          // eslint-disable-next-line no-undef
+          this.path = resp.data
+          if (this.path.length === 0) return this.$message.warning('暂无路径')
           AMapUI.load(['ui/misc/PathSimplifier'], (PathSimplifier) => {
-            if (!PathSimplifier.supportCanvas) {
-              alert('当前环境不支持 Canvas!')
-              return
-            }
-            var pathSimplifierIns = new PathSimplifier({
+            const pathSimplifierIns = new PathSimplifier({
               map: this.map,
               zIndex: 100,
               data: this.path,
               getPath: (pathData) => pathData.path
             })
-            var pathNavigator = pathSimplifierIns.createPathNavigator(0, {
-              loop: false,
-              speed: 3600
-            })
-            pathNavigator.start()
+            const navg = pathSimplifierIns.createPathNavigator(0, { loop: false, speed: 3600 })
+            navg.start()
           })
         }
       })
@@ -297,142 +260,118 @@ export default {
     onSavePosition() {
       this.showPositionDialog = false
       addGeoPosition(this.positionForm).then(resp => {
-        if (resp.code === 0) {
-          this.$message.success('坐标保存成功')
-        }
+        if (resp.code === 0) this.$message.success('保存成功')
       })
     },
 
     onSaveMyPosition() {
       this.showPositionDialog = false
       addMyPosition(this.positionForm).then(resp => {
-        if (resp.code === 0) {
-          this.$message.success('设置成功')
-        }
-      }).catch(error => {
-        this.$notify({ message: error.message, type: 'warning', duration: 1000 })
+        if (resp.code === 0) this.$message.success('设置成功')
       })
     },
 
-    onDrawCircle() {
-      this.showInput = true
-    },
+    onDrawCircle() { this.showInput = true },
 
     handleNumChange() {
-      if (this.radius < 10) {
-        this.$message.error('半径至少应大于 10m')
-        return
-      }
+      if (this.radius < 10) return this.$message.error('半径过小')
       this.showInput = false
       this.showPositionDialog = false
       this.drawCircle(this.pointArr, this.radius)
     },
 
     clearCircle() {
-      if (this.mapCircle !== null) {
-        this.map.remove(this.mapCircle)
-        this.mapCircle = null
-      }
-      if (this.circleEditor !== null) {
-        this.circleEditor.close()
-        this.circleEditor = null
-      }
-      this.$message.info('已清除地图图形')
-    }
+      if (this.mapCircle) this.map.remove(this.mapCircle)
+      if (this.circleEditor) this.circleEditor.close()
+      this.mapCircle = null
+      this.circleEditor = null
+      this.$message.info('已清除图形')
+    },
+    goBack() { this.$router.back() }
   }
 }
 </script>
 
 <style scoped lang="scss">
-// 保持原有样式不变
-.map-sub-container {
-  height: 100%;
-  background-color: #fff;
-  border-radius: 8px;
+/* 核心:撑满全屏 */
+.map-full-container {
+  width: 100%;
+  height: 100vh; /* 撑满视口高度 */
+  position: relative;
   overflow: hidden;
-  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.05);
+  margin: 0;
+  padding: 0;
 }
 
-.operation-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  background-color: #fcfcfc;
-  border-bottom: 1px solid #ebeef5;
-  padding: 0 15px !important;
+.amap-instance {
+  width: 100%;
+  height: 100%; /* 继承父级高度 */
+}
 
-  .left-tip {
+/* 悬浮控件样式优化 */
+.map-overlay-controls {
+  position: absolute;
+  top: 20px;
+  right: 20px;
+  z-index: 100;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  gap: 12px;
+
+  .tip-group {
+    background: rgba(255, 255, 255, 0.9);
+    padding: 8px 16px;
+    border-radius: 50px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
     color: #f56c6c;
     font-size: 13px;
+    backdrop-filter: blur(8px);
+    border: 1px solid rgba(255, 255, 255, 0.5);
     display: flex;
     align-items: center;
-    i { margin-right: 5px; }
+    i { margin-right: 6px; }
   }
 
-  .right-actions {
+  .button-group {
+    background: rgba(255, 255, 255, 0.85);
+    padding: 10px;
+    border-radius: 12px;
+    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
+    backdrop-filter: blur(10px);
     display: flex;
-    gap: 10px;
+    flex-direction: column;
+    gap: 8px;
+    border: 1px solid rgba(255, 255, 255, 0.6);
+
+    .el-button {
+      margin: 0 !important;
+      width: 120px;
+      font-weight: 500;
+      border-radius: 8px;
+    }
   }
 }
 
-.map-main-wrapper {
-  padding: 0 !important;
-  position: relative;
-}
-
-.amap-instance {
-  width: 100%;
-  height: calc(100vh - 180px);
-}
-
+/* 弹窗及其他样式 */
 ::v-deep .custom-map-dialog {
-  border-radius: 12px;
-  .el-dialog__header {
-    padding: 20px;
-    border-bottom: 1px solid #f2f6fc;
-  }
-  .el-dialog__body {
-    padding: 10px 25px 30px;
-  }
-}
-
-.dialog-title {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  gap: 8px;
-  font-weight: bold;
-  color: #303133;
+  border-radius: 16px;
+  overflow: hidden;
+  .el-dialog__header { padding: 20px; background: #fbfcfd; }
 }
 
 .coord-display {
   background: #f0f7ff;
-  padding: 15px;
-  border-radius: 8px;
+  padding: 20px;
+  border-radius: 12px;
   text-align: center;
-  .label { font-size: 12px; color: #79bbff; margin-bottom: 5px; }
-  .value { font-family: 'Courier New', Courier, monospace; font-weight: bold; color: #409EFF; font-size: 16px; }
+  .value { font-family: 'Monaco', monospace; font-size: 18px; color: #409EFF; }
 }
 
 .action-grid {
   display: flex;
   flex-direction: column;
-  gap: 10px;
-  .el-button {
-    margin-left: 0 !important;
-    justify-content: flex-start;
-  }
-}
-
-.radius-setter {
-  .input-tip { font-size: 13px; color: #909399; margin-bottom: 10px; }
-}
-
-.el-button {
-  transition: all 0.2s ease;
-  &:hover {
-    transform: translateY(-1px);
-    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-  }
+  gap: 12px;
+  .el-button { margin: 0 !important; text-align: left; padding: 12px 20px; }
 }
 </style>