Explorar el Código

离线地图功能开发

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 hace 1 año
padre
commit
a3c7c6627c

+ 5 - 1
.gitignore

@@ -6,4 +6,8 @@ dist_electron
 dist.zip
 dist.rar
 yarn.lock
-components.d.ts
+components.d.ts
+public/static/kMapTiles/**/*
+*.rar
+*.zip
+*.7z

+ 2 - 0
components.d.ts

@@ -57,6 +57,7 @@ declare module '@vue/runtime-core' {
     HorizontalBarChart: typeof import('./src/components/chart/bar/horizontal-bar-chart.vue')['default']
     HoverBarChart: typeof import('./src/components/chart/bar/hover-bar-chart.vue')['default']
     ImgLineChart: typeof import('./src/components/chart/line/img-line-chart.vue')['default']
+    KMap: typeof import('./src/components/kMap/index.vue')['default']
     ListBarChart: typeof import('./src/components/chart/bar/list-bar-chart.vue')['default']
     ListBarChart2: typeof import('./src/components/chart/bar/list-bar-chart2.vue')['default']
     MarkerLineChart: typeof import('./src/components/chart/line/marker-line-chart.vue')['default']
@@ -78,6 +79,7 @@ declare module '@vue/runtime-core' {
     PercentPieChart: typeof import('./src/components/chart/pie/percent-pie-chart.vue')['default']
     RadarChart: typeof import('./src/components/chart/radar/radar-chart.vue')['default']
     RadarPieChart: typeof import('./src/components/chart/pie/radar-pie-chart.vue')['default']
+    RightMenu: typeof import('./src/components/kMap/rightMenu.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     ScatterLineChart: typeof import('./src/components/chart/combination/scatter-line-chart.vue')['default']

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1697 - 83
package-lock.json


+ 6 - 0
package.json

@@ -11,6 +11,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "^2.0.10",
     "@stomp/stompjs": "^6.1.2",
+    "@vitejs/plugin-vue": "^4.4.0",
     "@vue/runtime-core": "^3.2.33",
     "@vue/shared": "^3.2.33",
     "axios": "^0.21.1",
@@ -29,6 +30,9 @@
     "screenfull": "^6.0.0",
     "sql-formatter": "^2.3.3",
     "stompjs": "^2.3.3",
+    "vite": "^4.4.11",
+    "vite-plugin-style-import": "^2.0.0",
+    "vite-plugin-windicss": "^1.9.1",
     "vue": "^3.2.6",
     "vue-cropperjs": "^5.0.0",
     "vue-loader-v16": "^16.0.0-beta.5.4",
@@ -42,12 +46,14 @@
     "@typescript-eslint/parser": "^5.20.0",
     "@vitejs/plugin-vue": "^1.2.2",
     "@vue/compiler-sfc": "^3.0.5",
+    "cesium": "^1.110.0",
     "sass": "^1.34.1",
     "sass-loader": "^12.0.0",
     "script-loader": "^0.7.2",
     "typescript": "^4.6.3",
     "unplugin-vue-components": "^0.22.9",
     "vite": "^2.3.4",
+    "vite-plugin-cesium": "^1.2.22",
     "vite-plugin-style-import": "^0.10.1",
     "vite-plugin-windicss": "^1.8.8",
     "vue-tsc": "^0.2.2",

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 10503 - 0
public/static/geoJson/sx.json


BIN
public/static/glb/wp.glb


BIN
public/static/glb/wt.glb


BIN
public/static/img/markIcon.png


+ 6 - 5
src/App.vue

@@ -5,14 +5,15 @@
 <script lang="ts" setup>
 // import dotList from './data.json'
 const res = {
+  token: "",
   data: {
     chineseName: "管理员",
     enabled: 0,
-    id: '715588739656581120',
-    identity: 'admin',
-    userName: 'admin',
-  }
-}
+    id: "715588739656581120",
+    identity: "admin",
+    userName: "admin",
+  },
+};
 sessionStorage.setItem("ms_username", res.data.userName);
 sessionStorage.setItem("ms_chinesename", res.data.chineseName);
 sessionStorage.setItem("ms_id", res.data.id);

+ 1 - 1
src/api/config.js

@@ -1,6 +1,6 @@
 const config = {
     // baseURL: 'http://10.81.3.155:9002',
-    baseURL: 'http://localhost:9002',
+    baseURL: 'http://192.168.2.13:9002',
     socketURL: 'ws://10.81.3.155:9002'
 }
 

+ 573 - 0
src/components/kMap/index.vue

@@ -0,0 +1,573 @@
+<template>
+  <div class="kMapBox">
+    <div id="kMap"></div>
+    <div class="tipBox" v-if="cameraHeight">
+      <span class="tipItem">视角高度≈{{ cameraHeight.toFixed(2) }}</span>
+      <span class="tipItem">视角经度≈{{ cameraLongitude.toFixed(2) }}</span>
+      <span class="tipItem">视角纬度≈{{ cameraLatitude.toFixed(2) }}</span>
+    </div>
+    <RightMenu
+      :rightMenuPosition="rightMenuPosition"
+      :rightMenuShow="rightMenuShow"
+      :clickModel="clickModel"
+      @cliclMenu="clickMenuItem"
+      @closeRightmenu="
+        () => {
+          rightMenuShow = false;
+        }
+      "
+    />
+  </div>
+</template>
+
+<script>
+import * as Cesium from "cesium";
+import axios from "axios";
+import request from "@/api/axios.js";
+import RightMenu from "./rightMenu.vue";
+export default {
+  props: {
+    ids: {
+      type: Array,
+      default: () => [],
+    },
+    parentId: {
+      type: String,
+      default: () => "",
+    },
+  },
+
+  components: {
+    RightMenu,
+  },
+
+  data() {
+    return {
+      mapViewer: null,
+      tilsUrl: "./static/kMapTiles/{z}/{x}/{y}.jpg",
+      labelEntities: [],
+      // 本地化语言配置
+      localSet: {
+        // 地址搜索栏
+        ".cesium-viewer-geocoderContainer form>.cesium-geocoder-input": {
+          placeholder: "在此输入地址或坐标...",
+        },
+        ".cesium-sceneModePicker-wrapper.cesium-toolbar-button button:nth-child(3)":
+          {
+            title: "2D化平面",
+          },
+        ".cesium-sceneModePicker-wrapper.cesium-toolbar-button button:last-child":
+          {
+            title: "哥伦布视图",
+          },
+      },
+      showEntities: true,
+      isFirstLoad: true,
+      cameraHeight: 0,
+      cameraLatitude: 0,
+      cameraLongitude: 0,
+      wpList: [],
+      wtList: [],
+      mapModelType: "3d",
+      substationId: "",
+      searchId: [],
+      rightMenuShow: false,
+      rightMenuPosition: {
+        x: 0,
+        y: 0,
+      },
+      clickModel: {},
+    };
+  },
+
+  created() {
+    this.substationId = this.parentId;
+    Cesium.Ion.defaultAccessToken =
+      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwNGVhZmJlNi03Mzg2LTRhZDQtYTBjYi1hNDk0MjM1NWYzZGEiLCJpZCI6MTcyNDQ1LCJpYXQiOjE2OTc1OTg3Nzd9.tJdKhFXx4JXjcKxUDvJffwwo2tMvIDIGEuwsYXbeeW0";
+  },
+
+  mounted() {
+    this.initKMap();
+    axios({
+      method: "get",
+      baseURL: "ping",
+      url: "",
+    })
+      .then(() => {})
+      .catch(() => {
+        this.initGetLocalTiles();
+      })
+      .finally(() => {
+        this.$nextTick(() => {
+          this.initCurrentOptions();
+          this.getGeoJson();
+          this.getWpList();
+          this.$emit("mapDone", true);
+        });
+      });
+  },
+
+  methods: {
+    // 手动将地球工具栏英文内容本地化
+    localToZhCn() {
+      for (let className in this.localSet) {
+        const dom = document.querySelector(className);
+        if (dom) {
+          for (let domOption in this.localSet[className]) {
+            dom.setAttribute(domOption, this.localSet[className][domOption]);
+          }
+        }
+      }
+    },
+
+    initKMap() {
+      this.mapViewer = new Cesium.Viewer("kMap", {
+        infoBox: false,
+        animation: false, // 是否显示动画控件
+        homeButton: false, // 是否显示 home 键
+        geocoder: false, // 是否显示地名查找控件
+        baseLayerPicker: false, // 是否显示图层选择控件
+        timeline: false, // 是否显示时间线控件
+        fullscreenButton: false, // 是否全屏显示
+        infoBox: false, // 是否显示点击要素之后显示的信息
+        sceneModePicker: true, // 是否显示投影方式控件  三维/二维
+        navigationInstructionsInitiallyVisible: false,
+        navigationHelpButton: false, // 是否显示帮助信息控件
+        orderIndependentTranslucency: false,
+        shouldAnimate: true,
+        scene3DOnly: false, // 每个几何实例将只能以3D渲染以节省GPU内存
+        selectionIndicator: false, // 取消点击有绿框
+        baseLayerPicker: false, //是否显示图层选择控件
+      });
+
+      // 视角移动结束钩子
+      this.mapViewer.scene.camera.moveEnd.addEventListener(() => {
+        this.getCameraInfo();
+      });
+
+      // 视角发生改变钩子
+      this.mapViewer.scene.camera.changed.addEventListener(() => {
+        this.rightMenuShow = false;
+        this.getCameraInfo();
+      });
+
+      // 注册场景点击事件
+      const handler = new Cesium.ScreenSpaceEventHandler(
+        this.mapViewer.scene.canvas
+      );
+
+      // 左键事件
+      handler.setInputAction(() => {
+        this.rightMenuShow = false;
+        return false;
+      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+
+      // 右键事件
+      handler.setInputAction((e) => {
+        const pick = this.mapViewer.scene.pick(e.position);
+        if (pick && pick.id) {
+          const clickModel = this.mapViewer.entities.getById(pick.id.id) || {};
+          if (clickModel?.modelType === "wt") {
+            this.clickModel = clickModel;
+            this.rightMenuPosition = e.position;
+            this.rightMenuShow = true;
+          }
+        }
+        return false;
+      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+
+      // 滚轮事件监听
+      handler.setInputAction(() => {
+        this.rightMenuShow = false;
+        this.getCameraInfo();
+      }, Cesium.ScreenSpaceEventType.WHEEL);
+    },
+
+    initGetLocalTiles() {
+      const imageryProvider = new Cesium.TileMapServiceImageryProvider({
+        url: this.tilsUrl, // 本地瓦片的路径
+        maximumLevel: 18, // 最大级别
+        minimumLevel: 0, // 最小级别
+        fileExtension: "jpg", // 图像文件扩展名
+        flipXY: true, // 如果你的瓦片Y轴方向与通常的瓦片格式相反,设置为true
+      });
+      this.mapViewer.imageryLayers.addImageryProvider(imageryProvider);
+    },
+
+    initCurrentOptions() {
+      // document.querySelector(".cesium-viewer-bottom").remove();
+      this.mapViewer._cesiumWidget._creditContainer.style.display = "none";
+
+      // 创建自定义还原按钮
+      var homeButton = document.createElement("button");
+      homeButton.textContent = "复位";
+      homeButton.className = "cesium-button";
+      homeButton.style.height = "36px";
+
+      // 将按钮添加到Cesium Viewer的界面中
+      var toolbar = document.querySelector(".cesium-viewer-toolbar");
+      toolbar.appendChild(homeButton);
+
+      // 在按钮点击时执行自定义还原视图操作
+      homeButton.addEventListener("click", () => {
+        // 这里可以编写代码以实现自定义的还原视图操作
+        // 例如,重置摄像机位置和缩放级别
+        this.mapViewer.camera.flyTo({
+          destination: Cesium.Cartesian3.fromDegrees(
+            112.48699,
+            37.94036,
+            1100000
+          ),
+        });
+      });
+
+      var entitiesButton = document.createElement("button");
+      entitiesButton.textContent = `${
+        this.showEntities ? "隐藏" : "显示"
+      }区域标记`;
+      entitiesButton.className = "cesium-button cesiumResetBtn";
+      entitiesButton.style.height = "36px";
+
+      toolbar.appendChild(entitiesButton);
+
+      // 在按钮点击时执行自定义还原视图操作
+      entitiesButton.addEventListener("click", () => {
+        this.showEntities = !this.showEntities;
+        entitiesButton.textContent = `${
+          this.showEntities ? "隐藏" : "显示"
+        }区域标记`;
+        this.getGeoJson();
+        this.showEntities && this.getWpList();
+      });
+
+      const select = document.createElement("select");
+
+      const optionsArray = [
+        { innerHTML: "3D模型", value: "3d" },
+        { innerHTML: "2D平面", value: "2d" },
+        { innerHTML: "2D图标", value: "icon" },
+      ];
+
+      optionsArray.forEach((ele) => {
+        const optionsItem = document.createElement("option");
+        optionsItem.innerHTML = ele.innerHTML;
+        optionsItem.setAttribute("value", ele.value);
+        select.appendChild(optionsItem);
+      });
+
+      toolbar.appendChild(select);
+
+      select.addEventListener("change", (select) => {
+        this.mapModelType = select.target.value;
+        this.showEntities && this.getWpList();
+      });
+
+      this.localToZhCn();
+    },
+
+    getGeoJson() {
+      if (this.showEntities) {
+        const strokeColor = new Cesium.Color.fromCssColorString("yellow");
+        const fillColor = new Cesium.Color.fromCssColorString(
+          "rgba(228,141,43,0.3)"
+        );
+        Cesium.Math.setRandomNumberSeed(0);
+        var promise = this.mapViewer.dataSources.add(
+          Cesium.GeoJsonDataSource.load("./static/geoJson/sx.json", {
+            stroke: strokeColor,
+            // fill: Cesium.Color.TRANSPARENT,
+            fill: fillColor,
+            clampToGround: false,
+            strokeWidth: 5.0,
+            markerSymbol: "?",
+          })
+        );
+        promise.then((dataSource) => {
+          const entities = dataSource.entities.values;
+          if (this.labelEntities.length === 0) {
+            for (let i = 0; i < entities.length; i++) {
+              const entity = entities[i];
+              const name = entity.name;
+              const location = entity.properties._centroid._value;
+              const labelEntity = this.mapViewer.entities.add({
+                modelType: "geo",
+                position: Cesium.Cartesian3.fromDegrees(
+                  location[0],
+                  location[1]
+                ),
+                label: {
+                  text: name,
+                  font: "14px Helvetica",
+                  fillColor: Cesium.Color.WHITE,
+                  showBackground: false,
+                  backgroundColor: Cesium.Color.fromCssColorString(
+                    "rgba(52,79,209,1.0)"
+                  ),
+                  backgroundPadding: new Cesium.Cartesian2(3, 3),
+                  scale: 0.9,
+                  style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+                  outlineColor: Cesium.Color.BLACK,
+                  outlineWidth: 2,
+                  verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+                },
+              });
+              this.labelEntities.push(labelEntity);
+            }
+          }
+        });
+        if (this.isFirstLoad) {
+          this.isFirstLoad = false;
+          this.mapViewer.flyTo(promise);
+        }
+      } else {
+        this.mapViewer.entities.removeAll();
+        this.mapViewer.dataSources.removeAll();
+        this.labelEntities = [];
+      }
+    },
+
+    getCameraInfo() {
+      const camera = this.mapViewer.camera;
+      this.cameraHeight = camera.positionCartographic.height;
+      this.cameraLatitude = camera.positionCartographic.latitude;
+      this.cameraLongitude = camera.positionCartographic.longitude;
+    },
+
+    async getWpList() {
+      if (this.ids?.length) {
+        this.wtList.forEach((ele) => {
+          this.addWt(ele, "wt");
+        });
+        this.switchEntities(["wt"], this.substationId);
+      } else {
+        if (!this.wpList?.length) {
+          const { data } = await request.get("/base/station");
+          this.wpList = data || [];
+          data.forEach((ele) => {
+            this.addWt(ele, "wp");
+          });
+        } else {
+          this.wpList.forEach((ele) => {
+            this.addWt(ele, "wp");
+          });
+        }
+        this.switchEntities(["wp"], this.substationId);
+      }
+    },
+
+    addWt(resItem, modelType = "wp") {
+      const hpRoll = new Cesium.HeadingPitchRoll(
+        modelType === "wt" ? 45 : 20,
+        0.0,
+        0.0
+      );
+      const origin = Cesium.Cartesian3.fromDegrees(106.0231304, 37.73323706, 0);
+      const position = Cesium.Cartesian3.fromDegrees(
+        Number(resItem.longitude),
+        Number(resItem.latitude),
+        0
+      );
+      const orientation = Cesium.Transforms.headingPitchRollQuaternion(
+        position,
+        hpRoll
+      );
+
+      const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
+        origin,
+        hpRoll
+      );
+
+      // const id = `${modelType}_${resItem.id}`;
+      const minimumPixelSize = modelType === "wt" ? 50 : 40;
+      const maximumSize = modelType === "wt" ? 40 : 40;
+      const maximumScale = modelType === "wt" ? 80 : 70;
+      const substationId = this.substationId || "";
+      const fittingId = resItem.fittingId;
+      const processId = resItem.processId;
+      const currentName = resItem.name;
+      const mapModelType = this.mapModelType;
+
+      const modelItem = {
+        // 模型id
+        // id,
+        modelType,
+        substationId,
+        fittingId,
+        processId,
+        currentName,
+        mapModelType,
+        // 模型位置
+        position,
+        // 模型方向
+        orientation,
+        // 添加描述
+        description: resItem.name,
+        label: {
+          // 文字内容
+          text: resItem.aname,
+          // 文本大小与字体
+          font: "14px Helvetica",
+          // 文字填充颜色
+          fillColor: Cesium.Color.WHITE,
+          // 是否显示背景
+          showBackground: false,
+          //背景墙的颜色
+          backgroundColor: Cesium.Color.fromCssColorString(
+            "rgba(52,79,209,1.0)"
+          ),
+          // 背景宽度
+          backgroundPadding: new Cesium.Cartesian2(3, 3),
+          // 文字与背景墙的总大小
+          scale: 1.2,
+          // 文本轮廓
+          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+          // 外边界颜色
+          outlineColor: Cesium.Color.fromCssColorString("#000"),
+          // 外边界宽度
+          outlineWidth: 4,
+          // 文本出现的位置
+          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+          // 文本的偏移方向
+          pixelOffset: new Cesium.Cartesian2(0, 25),
+          eyeOffset: new Cesium.Cartesian3(0, 0, -250),
+        },
+      };
+
+      if (mapModelType === "3d") {
+        // 模型资源
+        modelItem.model = {
+          // 模型路径
+          uri: `./static/glb/${modelType}.glb`,
+          // 模型最小刻度
+          minimumPixelSize,
+          // 模型最大刻度
+          maximumSize,
+          // 设置模型最大放大大小
+          maximumScale,
+          // 模型是否可见
+          show: true,
+          // 模型轮廓颜色
+          silhouetteColor: Cesium.Color.WHITE,
+          // 模型颜色  ,这里可以设置颜色的变化
+          color: Cesium.Color.WHITE,
+          // 仅用于调试,显示魔仙绘制时的线框
+          debugWireframe: false,
+          // 仅用于调试。显示模型绘制时的边界球。
+          debugShowBoundingVolume: false,
+          scale: 1,
+          // 是否运行模型中的动画效果
+          runAnimations: true,
+          clampAnimations: true, // 是否保持最后一针的动画
+          // 模型贴地
+          // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+        };
+      } else if (mapModelType === "2d") {
+        const semiMinorAxis = modelType === "wt" ? 350 : 1200;
+        const semiMajorAxis = modelType === "wt" ? 350 : 1200;
+        const extrudedHeight = modelType === "wt" ? 5.0 : 200;
+        const materialColor = modelType === "wt" ? "#f25656" : "#1890ff";
+        modelItem.ellipse = {
+          semiMinorAxis, // 椭圆的短半轴
+          semiMajorAxis, // 椭圆的长半轴
+          extrudedHeight, // 拉伸高度
+          material: Cesium.Color.fromCssColorString(materialColor), // 椭圆颜色
+          outline: true, //是否显示边框
+          outlineColor: Cesium.Color.fromCssColorString("#000"), //边框颜色
+          rotation: Cesium.Math.toRadians(45), //旋转角度,从正北方向开始顺时针旋转
+        };
+      } else if (mapModelType === "icon") {
+        modelItem.billboard = {
+          image: "./static/img/markIcon.png",
+          width: 19,
+          height: 31,
+        };
+      }
+
+      this.mapViewer.entities.add(modelItem);
+    },
+
+    switchEntities(modelTypeList = [], substationId = "") {
+      let entities = [];
+      modelTypeList?.forEach((type) => {
+        this.mapViewer.entities.values.forEach((ele, index) => {
+          if (
+            ele.modelType === type &&
+            ele.mapModelType === this.mapModelType &&
+            (substationId ? substationId === ele.substationId : true)
+          ) {
+            if (this.searchId?.length) {
+              const someRes = this.searchId.some((fittingId) => {
+                return ele.fittingId === fittingId;
+              });
+              someRes && entities.push(ele);
+            } else {
+              entities.push(ele);
+            }
+          }
+
+          if (ele.modelType === "geo") {
+            entities.push(ele);
+          }
+        });
+      });
+
+      this.mapViewer.entities.removeAll();
+      entities.forEach((ele) => {
+        this.mapViewer.entities.add(ele);
+      });
+    },
+
+    clickMenuItem(params) {
+      this.$emit("rightClick", params);
+    },
+  },
+
+  watch: {
+    ids(value) {
+      request
+        .get("/base/location", {
+          params: {
+            ids: value.join(","),
+          },
+        })
+        .then((res) => {
+          this.searchId = value || [];
+          this.wtList = res.data || [];
+          this.getWpList();
+        });
+    },
+    parentId(value) {
+      this.substationId = value || "";
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.kMapBox,
+.kMapBox #kMap {
+  width: 100%;
+  height: 100%;
+}
+
+.kMapBox {
+  position: relative;
+  .tipBox {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    font-size: 12px;
+    padding: 4px;
+    background: rgba(0, 0, 0, 0.5);
+    color: #fff;
+    width: 100%;
+
+    .tipItem {
+      margin-left: 4px;
+
+      &:first-child {
+        margin-left: 1px;
+      }
+    }
+  }
+}
+</style>

+ 138 - 0
src/components/kMap/rightMenu.vue

@@ -0,0 +1,138 @@
+<template>
+  <div
+    class="kMapRightMenuBox"
+    :style="`left:${(MenuPosition.x + 4).toFixed(1)}px;
+    top:${(MenuPosition.y + 4).toFixed(1)}px;`"
+    v-if="menuShow"
+  >
+    <div class="menuItem title sp" v-if="model.currentName">
+      {{ model.currentName }}
+    </div>
+    <div class="menuItem content" @click="clickMenuItem(0, 'fittingId')">
+      功率曲线拟合
+    </div>
+    <div class="menuItem content" @click="clickMenuItem(1, 'processId')">
+      对分偏差分析
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    rightMenuPosition: {
+      type: Object,
+      default: () => {
+        return { x: 0, y: 0 };
+      },
+    },
+
+    rightMenuShow: {
+      type: Boolean,
+      default: () => false,
+    },
+
+    clickModel: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+
+  data() {
+    return {
+      menuShow: false,
+      MenuPosition: { x: 0, y: 0 },
+      preventStop: false,
+      model: {},
+    };
+  },
+
+  methods: {
+    stopEvent() {
+      this.$nextTick(() => {
+        if (!this.preventStop) {
+          const kMapRightMenuBox = document.querySelector(".kMapRightMenuBox");
+          kMapRightMenuBox.addEventListener("contextmenu", (event) => {
+            event.preventDefault && event.preventDefault();
+            this.preventStop = true;
+            return false;
+          });
+        }
+      });
+    },
+
+    clickMenuItem(menuIndex, key) {
+      if (this?.model?.[key]) {
+        this.$emit("closeRightmenu");
+        this.$emit("cliclMenu", {
+          menuIndex,
+          current: this.model,
+        });
+      }
+    },
+  },
+
+  watch: {
+    rightMenuShow(bool) {
+      this.menuShow = bool;
+      bool && this.stopEvent();
+    },
+    rightMenuPosition(menuPosition) {
+      this.MenuPosition = menuPosition;
+    },
+    clickModel(model) {
+      this.model = model;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.kMapRightMenuBox {
+  position: absolute;
+  left: 0;
+  top: 0;
+  border-radius: 0px 8px 8px 8px;
+  background: rgb(249, 249, 249);
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  padding: 4px 0;
+  overflow: hidden;
+
+  .menuItem {
+    font-size: 13px;
+    padding: 4px 8px;
+    width: 100%;
+    white-space: nowrap;
+
+    &.title {
+      color: #999;
+    }
+
+    &.sp {
+      border-bottom: 1px solid #999;
+    }
+
+    &.content {
+      cursor: pointer;
+      user-select: none;
+      transition: 0.1s;
+    }
+
+    &.content:hover {
+      background: #1890ff;
+      color: #fff;
+      transition: 0.1s;
+    }
+  }
+
+  *.show {
+    border: 1px solid rgb(229, 229, 229);
+    height: 200px;
+  }
+}
+</style>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1294 - 938
src/pages/dataAnalysis/posAnalysis/index.vue


+ 10 - 8
vite.config.js

@@ -10,6 +10,7 @@ import {
 import {
     resolve
 } from 'path';
+import cesium from 'vite-plugin-cesium';
 const pathResolve = (dir) => {
     return resolve(__dirname, '.', dir);
 };
@@ -37,20 +38,21 @@ export default defineConfig({
             resolvers: [ElementPlusResolver()],
         }),
         WindiCSS(),
-        vue()
+        vue(),
+        cesium()
     ],
     server: {
         host: '0.0.0.0',
         open: false, //自动打开 
         base: "./ ", //生产环境路径
-        proxy: { // 本地开发环境通过代理实现跨域,生产环境使用 nginx 转发
+        proxy: { 
+            // 本地开发环境通过代理实现跨域,生产环境使用 nginx 转发
             // // 正则表达式写法
-            // '^/sharding': {
-            //     // target: 'http://10.155.32.14:8082/sharding',
-            //     target: 'http://192.168.10.8:9002',
-            //     changeOrigin: true, //开启代理
-            //     rewrite: (path) => path.replace(/^\/sharding/, '')
-            // },
+            '^/ping': {
+                target: 'https://www.baidu.com',
+                changeOrigin: true, //开启代理
+                rewrite: (path) => path.replace(/^\/ping/, '')
+            },
             // '^/adapter': {
             //     // target: 'http://10.155.32.14:8082/sharding',
             //     target: 'http://192.168.10.8:9002',

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3678 - 3246
yarn.lock