Browse Source

feat: 多地图切换

tangning 3 tháng trước cách đây
mục cha
commit
b82cdb75d7

+ 1 - 0
package.json

@@ -21,6 +21,7 @@
     "http": "^0.0.1-security",
     "js-base64": "^3.7.5",
     "leaflet": "^1.9.4",
+    "leaflet.chinatmsproviders": "^3.0.6",
     "mime": "^3.0.0",
     "mitt": "^3.0.1",
     "province-city-china": "^8.5.8",

+ 8 - 0
src/store/case.ts

@@ -307,6 +307,14 @@ export const getTipsList = (key) =>
     }
   });
 
+  export const getGaoDeGaoDeList = (key) =>
+    axios.get('/v3/geocode/geo', {
+      params: {
+        address: key,
+        key: '2ae5a7713612a8d5a65cfd54c989c969',
+      }
+    });
+  
 export const getTipsNames = (name) =>
   axios.get(getTipsName, { params: { name } });
 

+ 1 - 1
src/util/index.ts

@@ -379,7 +379,7 @@ export const getDomMatrix = (dom: HTMLElement) => {
 export const windowOpen = (param) => {
   if(param.url) {
     // iframe发送消息到 父页面
-    let data = JSON.stringify({type:"link", data:param.url, library: param.library, title: param.title||'', icon: param.icon ||''});
+    let data = JSON.stringify({type:"link", data:param.url, library: param.library, title: param.title||'', icon: param.icon ||'', edit: param.edit ||0, sceneType: param.sceneType ||''});
       window.parent.postMessage(data, '*');
   } else if(param.type) {//按钮事件
     // iframe发送消息到 父页面

+ 1 - 0
src/view/aiList/index.vue

@@ -47,6 +47,7 @@ const handleItem = (item) => {
   windowOpen({
     url: `${url.swkkUrl}?m=${item.num}&ai=floorplan`,
     title: item.title,
+    sceneType: 'obj',
   })
 };
 const getList = async () => {

+ 154 - 0
src/view/case/draw/leaflet.ChineseTmsProviders.js

@@ -0,0 +1,154 @@
+// this L.CRS.Baidu from https://github.com/muyao1987/leaflet-tileLayer-baidugaode/blob/master/src/tileLayer.baidu.js
+
+if (L.Proj) {
+    L.CRS.Baidu = new L.Proj.CRS('EPSG:900913', '+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs', {
+        resolutions: function () {
+            var level = 19
+            var res = [];
+            res[0] = Math.pow(2, 18);
+            for (var i = 1; i < level; i++) {
+                res[i] = Math.pow(2, (18 - i))
+            }
+            return res;
+        }(),
+        origin: [0, 0],
+        bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244])
+    });
+}
+
+L.TileLayer.ChinaProvider = L.TileLayer.extend({
+
+    initialize: function(type, options) { // (type, Object)
+        var providers = L.TileLayer.ChinaProvider.providers;
+
+        options = options || {}
+
+        var parts = type.split('.');
+
+        var providerName = parts[0];
+        var mapName = parts[1];
+        var mapType = parts[2];
+
+        var url = providers[providerName][mapName][mapType];
+        options.subdomains = providers[providerName].Subdomains;
+        options.key = options.key || providers[providerName].key;
+
+        if ('tms' in providers[providerName]) {
+            options.tms = providers[providerName]['tms']
+        }
+
+        L.TileLayer.prototype.initialize.call(this, url, options);
+    },
+
+    getTileUrl: function (coords) {
+		var data = {
+			s: this._getSubdomain(coords),
+			x: coords.x,
+			y: coords.y,
+			z: this._getZoomForUrl(),
+		};
+		if (this._map && !this._map.options.crs.infinite) {
+			var invertedY = this._globalTileRange.max.y - coords.y;
+			if (this.options.tms) {
+				data['y'] = invertedY;
+			}
+			data['-y'] = invertedY;
+		}
+
+        data.sx = data.x >> 4
+        data.sy = (( 1 << data.z) - data.y) >> 4
+
+		return L.Util.template(this._url, L.Util.extend(data, this.options));
+	},
+});
+
+L.TileLayer.ChinaProvider.providers = {
+    TianDiTu: {
+        Normal: {
+            Map: "//t{s}.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk={key}",
+            Annotion: "//t{s}.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk={key}"
+        },
+        Satellite: {
+            Map: "//t{s}.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk={key}",
+            Annotion: "//t{s}.tianditu.gov.cn/DataServer?T=cia_w&X={x}&Y={y}&L={z}&tk={key}"
+        },
+        Terrain: {
+            Map: "//t{s}.tianditu.gov.cn/DataServer?T=ter_w&X={x}&Y={y}&L={z}&tk={key}",
+            Annotion: "//t{s}.tianditu.gov.cn/DataServer?T=cta_w&X={x}&Y={y}&L={z}&tk={key}"
+        },
+        Subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+        key: "174705aebfe31b79b3587279e211cb9a"
+    },
+
+    GaoDe: {
+        Normal: {
+            Map: '//webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
+        },
+        Satellite: {
+            Map: '//webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
+            Annotion: '//webst0{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}'
+        },
+        Subdomains: ["1", "2", "3", "4"]
+    },
+
+    Google: {
+        Normal: {
+            Map: "//www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}"
+        },
+        Satellite: {
+            Map: "//www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}",
+            Annotion: "//www.google.cn/maps/vt?lyrs=y@189&gl=cn&x={x}&y={y}&z={z}"
+        },
+        Subdomains: []
+    },
+
+    Geoq: {
+        Normal: {
+            Map: "//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
+            PurplishBlue: "//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
+            Gray: "//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}",
+            Warm: "//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer/tile/{z}/{y}/{x}",
+        },
+        Theme: {
+            Hydro: "//thematic.geoq.cn/arcgis/rest/services/ThematicMaps/WorldHydroMap/MapServer/tile/{z}/{y}/{x}"
+        },
+        Subdomains: []
+    },
+
+    OSM: {
+        Normal: {
+            Map: "//{s}.tile.osm.org/{z}/{x}/{y}.png",
+        },
+        Subdomains: ['a', 'b', 'c']
+    },
+
+    Baidu: {
+        Normal: {
+            Map: '//online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1'
+        },
+        Satellite: {
+            Map: '//shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46',
+            Annotion: '//online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=sl&v=020'
+        },
+        Subdomains: '0123456789',
+        tms: true
+    },
+
+    Tencent: {
+        Normal: {
+            Map: "//rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={-y}&type=vector&styleid=3",
+        },
+        Satellite: {
+            Map: "//p{s}.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{-y}.jpg",
+        },
+        Terrain: {
+            Map: "//p{s}.map.gtimg.com/demTiles/{z}/{sx}/{sy}/{x}_{-y}.jpg"
+        },
+        Subdomains: '0123',
+    }
+
+};
+
+L.tileLayer.chinaProvider = function(type, options) {
+    return new L.TileLayer.ChinaProvider(type, options);
+};

+ 320 - 0
src/view/case/draw/selectMapleaftImages.vue

@@ -0,0 +1,320 @@
+<template>
+  <div class="search-layout">
+    <el-input
+      v-model="keyword"
+      placeholder="输入名称搜索"
+      style="width: 350px"
+      clearable
+      @change="onSearch"
+    >
+      <!-- <template #append>
+        <el-button :icon="Search" />
+      </template> -->
+    </el-input>
+    <div class="rrr">
+      <div class="search-result" v-show="keyword">
+        <div
+          class="search-list"
+          v-for="(item, index) in keywordList"
+          @click="hanleItem(item.name)"
+        >
+          {{ item.name }}
+        </div>
+      </div>
+      <!-- <div class="search-sh" v-show="keyword">
+        <el-button style="width: 100%" @click="showSearch = !showSearch">
+          {{ showSearch ? "收起" : "展开" }}搜索结果
+        </el-button>
+      </div> -->
+    </div>
+  </div>
+  <div class="def-select-map-layout">
+    <div class="def-select-map" id="mapEl" ref="mapEl"></div>
+  </div>
+
+  <div class="def-map-info" v-if="searchInfo">
+    <p><span>纬度</span>{{ searchInfo.lat }}</p>
+    <p><span>经度</span>{{ searchInfo.lng }}</p>
+    <!-- <p><span>缩放级别</span>{{ info.zoom }}</p> -->
+  </div>
+</template>
+
+<script setup lang="ts">
+import AMapLoader from "@amap/amap-jsapi-loader";
+import { Search } from "@element-plus/icons-vue";
+import { wgs84_to_gcj02 } from "./map";
+import { getTipsList, getGaoDeGaoDeList, getTipsNames, getCaseInfo } from "@/store/case";
+import { ref, watchEffect, onMounted, computed } from "vue";
+import { QuiskExpose } from "@/helper/mount";
+import { debounce } from "@/util";
+import html2canvas from "html2canvas";
+import L from "leaflet";
+import "leaflet.chinatmsproviders";
+import "leaflet/dist/leaflet.css";
+import { router } from "@/router";
+export type MapImage = { blob: Blob | null; search: MapInfo | null };
+type MapInfo = {
+  lat: number;
+  lng: number;
+  zoom: number;
+  text: string;
+  address: string;
+  id: string;
+};
+// const layer = L.tileLayer('http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}')
+// const layer = L.tileLayer("http://a.map.jms.gd/tile/osm/{z}/{x}/{y}.png");
+// const layer = L.tileLayer('http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x={x}&y={y}&z={z}&token=YOUR_API_KEY')
+var normalMap = L.tileLayer.chinaProvider("Google.Normal.Map", {
+  maxZoom: 18,
+  minZoom: 5,
+});
+var Gaode = L.tileLayer.chinaProvider("GaoDe.Normal.Map", {
+  maxZoom: 18,
+  minZoom: 5,
+});
+var baseLayers = {
+  '谷歌地图': normalMap,
+  '高德地图': Gaode,
+};
+
+let map: any = {};
+let clickMarker;
+const keyword = ref("");
+const showSearch = ref(true);
+const info = ref<MapInfo>();
+const caseInfoData = ref<any>(null);
+const searchInfo = ref<MapInfo>();
+const mapEl = ref<HTMLDivElement>();
+const keywordList = ref([]);
+watchEffect(() => {
+  if (keyword.value) {
+    showSearch.value = true;
+  }
+});
+const caseId = computed(() => {
+  const caseId = router.currentRoute.value.params.caseId;
+  if (caseId) {
+    return Number(caseId);
+  }
+});
+onMounted(async () => {
+  caseInfoData.value = {};
+  let center = [22.61, 113.05];
+  if (caseInfoData.value?.latAndLong) {
+    center = caseInfoData.value.latAndLong.split(",");
+  }
+  console.log("caseInfoData", caseInfoData.value.latAndLong, center);
+
+  // 'map'为HTML节点id
+  map = L.map(mapEl.value, {
+    center: center, //中心坐标
+    zoom: 14, //缩放级别
+    zoomControl: true, //缩放组件
+    attributionControl: false, //去掉右下角logol
+    layers: [Gaode], //图层
+    // center: [51.505, -0.09],
+    // zoom: 13
+  });
+  L.control.layers(baseLayers, null).addTo(map);
+  map.on("click", function (e) {
+    // 获取点击位置的经纬度坐标
+    var latitude = e.latlng.lat;
+    var longitude = e.latlng.lng;
+    console.log("click", e, [longitude, latitude]);
+
+    searchInfo.value = {
+      text: "",
+      lat: latitude,
+      lng: longitude,
+      zoom: 0,
+    };
+    clickMarker && clickMarker.remove();
+    clickMarker = null;
+    // 在地图上添加标记
+    clickMarker = L.marker([latitude, longitude], {
+      position: [latitude, longitude],
+      title: "点击位置",
+    });
+    clickMarker.addTo(map);
+    map.panTo([latitude, longitude]);
+    // map.add(clickMarker);
+  });
+});
+
+const resultEl = ref<HTMLDivElement>();
+const searchAMap = ref<any>();
+
+watchEffect(async (onCleanup) => {
+  if (!mapEl.value || !resultEl.value) {
+    return;
+  }
+  //绑定地图移动与缩放事件
+  map.on("moveend", () => {
+    info.value = getMapInfo();
+  });
+  map.on("zoomend", () => {
+    info.value = getMapInfo();
+  });
+  searchAMap.value = placeSearch;
+
+  onCleanup(() => {
+    searchAMap.value = null;
+    map.destroy();
+  });
+});
+const getMapInfo = (): MapInfo => {
+  var zoom = map.getZoom(); //获取当前地图级别
+  var center = map.getCenter();
+  return {
+    text: "",
+    zoom,
+    lat: center.lat,
+    lng: center.lng,
+  };
+};
+const onSearch = (val) => {
+  getGaoDeGaoDeList(val).then((res) => {
+    console.log("getTipsList", res);
+    keywordList.value = res.data;
+  });
+  console.log("onSearch", val, "keyword.value", keyword.value);
+};
+const hanleItem = (name) => {
+  // keyword.value = item.name;
+  getTipsNames(name).then((ress) => {
+    let res = ress.data;
+    // longlat = wgs84_to_gcj02(Number(res.lng),Number(res.lat))
+    keyword.value = "";
+    searchInfo.value = {
+      ...res,
+      // lng: longlat[0],
+      // lat: longlat[1],
+      text: res.name,
+    };
+    clickMarker && clickMarker.remove();
+    // let icon = L.icon({
+    //   iconUrl: require('./icon.svg'),
+    //   iconSize: [25, 30],
+    //   iconAnchor: [12, 30]
+    // });
+    clickMarker = null;
+
+    // 在地图上添加标记
+    clickMarker = L.marker([res.lat, res.lng], {
+      position: [res.lat, res.lng],
+      title: "点击位置",
+      // icon,
+    });
+    clickMarker.addTo(map);
+    map.panTo([res.lat, res.lng]);
+  });
+  // onSearch(item.name);
+};
+var dataURLtoBlob = function (dataurl) {
+  var arr = dataurl.split(","),
+    mime = arr[0].match(/:(.*?);/)[1],
+    bstr = atob(arr[1]),
+    n = bstr.length,
+    u8arr = new Uint8Array(n);
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n);
+  }
+  return new Blob([u8arr], { type: mime });
+};
+const search = debounce((keyword: string) => {
+  searchAMap.value.search(keyword);
+}, 1000);
+watchEffect(() => {
+  searchAMap.value && search(keyword.value);
+});
+
+defineExpose<QuiskExpose>({
+  submit() {
+    return new Promise<MapImage>((resolve) => {
+      console.log("searchInfo", searchInfo.value, mapEl.value);
+      if (mapEl.value) {
+        const canvas = mapEl.value.querySelector("canvas") as HTMLCanvasElement;
+        console.log(canvas, "canvas");
+        canvas &&
+          canvas.toBlob((blob) => resolve({ blob, search: searchInfo.value! })); // || resolve({ search: searchInfo.value! });
+        if (!canvas) {
+          //div内容生成图片
+          html2canvas(mapEl.value, {
+            useCORS: true, // 添加这个选项以解决跨域问题
+          }).then((canvas) => {
+            let imgUrl = canvas.toDataURL("image/png");
+            let blob = dataURLtoBlob(imgUrl);
+            resolve({ blob, search: searchInfo.value! });
+          });
+        }
+      } else {
+        resolve({ blob: null, search: null });
+      }
+    });
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+.search-layout {
+  display: inline-block;
+  position: relative;
+  margin-bottom: 15px;
+  z-index: 2;
+}
+
+.rrr {
+  position: absolute;
+  left: 0;
+  right: 0;
+  z-index: 1;
+}
+
+.search-sh,
+.search-result {
+  overflow: hidden;
+
+  &.show {
+    max-height: 450px;
+    overflow-y: auto;
+  }
+  .search-list {
+    background: #fff;
+    padding-left: 10px;
+    line-height: 36px;
+  }
+}
+
+.def-map-info {
+  margin-top: 10px;
+  p {
+    font-size: 14px;
+    color: rgba(0, 0, 0, 0.85);
+    display: inline;
+    &:not(:last-child)::after {
+      content: ",";
+      margin-right: 6px;
+    }
+  }
+
+  span::after {
+    content: ":";
+  }
+}
+
+.def-select-map-layout {
+  --scale: 1.5;
+  width: 100%;
+  padding-top: calc((390 / 540) * 100%);
+  position: relative;
+  z-index: 1;
+}
+
+.def-select-map {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 2 - 1
src/view/case/quisk.ts

@@ -8,7 +8,8 @@ import EditEshapeTable, {
 } from "./draw/editEshapeTable.vue";
 import SceneList from "./sceneList.vue";
 import SelectFuseImage, { FuseImage } from "./draw/selectFuseImage.vue";
-import SelectMapImage, { MapImage } from "./draw/selectMapImages.vue";
+// import SelectMapImage, { MapImage } from "./draw/selectMapImages.vue";
+import SelectMapImage, { MapImage } from "./draw/selectMapleaftImages.vue";
 import { quiskMountFactory } from "@/helper/mount";
 import { nextTick } from "vue";
 import { ui18n } from '@/i18n'

+ 1 - 1
src/view/layout/top/index.vue

@@ -117,7 +117,7 @@ const searchAMapAddress = async () => {
 const handleSee = () => {
   let url = getUrlSrc({ type: 99 }, caseId.value);
   console.log("handleSee", url, title.value);
-  windowOpen({ url, title: title.value});
+  windowOpen({ url, title: title.value, sceneType: 'fuse',});
 };
 const logout = async () => {
   if (await confirm("确定要退出登录吗?")) {

+ 3 - 6
src/view/vrmodel/index.vue

@@ -106,15 +106,12 @@ async function geiList() {
 }
 function handlegotoEdit(record) {
   let url = getUrlSrc(record, caseId.value)
-  console.log("handlegotoEdit", url, record);
-    // record.type == 2 || record.type == 5
-    //   ? `/mega/index.html?m=${record.num}`
-    //   : `/epg.html?m=${record.num}`;
-      // windowOpen({url: url.replace("spg", "epg"),title:record.name || ui18n.t('common.edit'), icon: 'scene' });
+  let sceneType = record.isLaser ? 'cloud' : 'obj'
+  windowOpen({url: url.replace("spg", "epg"),title:record.name || ui18n.t('common.edit'), icon: 'scene', sceneType, edit: 1 });
 }
 function handleAdddyrh(record) {
   let url = getUrlSrc({ type: 100 }, caseId.value)
-  windowOpen({url, title: title.value || ui18n.t('sceneHome.dyrh')});
+  windowOpen({url, title: title.value || ui18n.t('sceneHome.dyrh'),sceneType: 'fuse', edit: 1 });
 }
 async function handlegotoelT(record) {
   isEdit.value = true;

+ 4 - 4
vite.config.ts

@@ -51,12 +51,12 @@ export default defineConfig({
     host: "0.0.0.0",
     proxy: {
       "/api": {
-        target: dev ? "http://192.168.0.108:8808" : "mix3d.4dkankan.com",
+        target: dev ? "http://192.168.0.25" : "mix3d.4dkankan.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(new RegExp(`^/api`), ""),
       },
       "/fusion": {
-        target: dev ? "http://192.168.0.108:8808" : "mix3d.4dkankan.com",
+        target: dev ? "http://192.168.0.25" : "mix3d.4dkankan.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(new RegExp(`^/api`), "/fusion"),
       },
@@ -92,9 +92,9 @@ export default defineConfig({
         changeOrigin: true,
         rewrite: (path) => path.replace(new RegExp(`^/laser`), "/laser"),
       },
-      "/fdkk": {
+      "/v3": {
         target: dev
-          ? "https://uat-laser.4dkankan.com/uat"
+          ? "https://restapi.amap.com"
           : "https://laser.4dkankan.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(new RegExp(`^/swss`), ""),

+ 5 - 0
yarn.lock

@@ -1921,6 +1921,11 @@ kolorist@^1.8.0:
   resolved "https://mirrors.cloud.tencent.com/npm/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c"
   integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==
 
+leaflet.chinatmsproviders@^3.0.6:
+  version "3.0.6"
+  resolved "https://registry.npmmirror.com/leaflet.chinatmsproviders/-/leaflet.chinatmsproviders-3.0.6.tgz#38f9742a589918211c093d02677a36ee5297514b"
+  integrity sha512-B4UPSn2MT//RkFoyrVjwqQyfKuf4tSmMjJDKQ6nqwCCGgirYKRWHafSH9JmA88WoG5pkuMXBcKQhY32FobxU/g==
+
 leaflet@^1.9.4:
   version "1.9.4"
   resolved "https://mirrors.cloud.tencent.com/npm/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d"