浏览代码

江门本地修改

tangning 6 月之前
父节点
当前提交
3ba3a0dc98

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "element-plus": "^2.3.8",
     "html2canvas": "^1.4.1",
     "js-base64": "^3.7.5",
+    "leaflet": "^1.9.4",
     "mime": "^3.0.0",
     "mitt": "^3.0.1",
     "province-city-china": "^8.5.8",

二进制
public/marker-icon-2x.png


二进制
public/marker-icon.png


+ 5 - 1
src/request/urls.ts

@@ -255,6 +255,10 @@ export const getDictFileList = "/service/manage/dict/getByKey/media-library";
 export const delDictFileList = "/service/manage/dictFile/del/media-library";
 export const getListFileList = "/service/manage/dictFile/pageList/media-library";
 export const caseaddOrUpdate = '/service/manage/case/addOrUpdate';
-
+//地图相关
+// export const getTips = "http://map.jms.gd//s/api/gettips";
+// export const getTipsName = "http://map.jms.gd/s/api/gettips_name";
+export const getTips = "/s/api/gettips";
+export const getTipsName = "/s/api/gettips_name";
 
 

+ 11 - 0
src/store/case.ts

@@ -35,6 +35,8 @@ import {
   sceneListHasAi,
   caseaddOrUpdate,
   isdyrh,
+  getTips,
+  getTipsName
 } from "@/request";
 import { router } from "@/router";
 import { ModelScene, QuoteScene, Scene, SceneType } from "./scene";
@@ -251,6 +253,15 @@ export const getCaseImgTagData = (caseId: number) =>
 export const getSceneListHasAi = (caseId: number) =>
   axios.get(sceneListHasAi, { params: { caseId } });
 
+export const getTipsList = (key) =>
+  axios.get(getTips, { params: { 
+    basic: 'y',
+    key,
+    location: '113.05,22.61',
+   } });
+
+export const getTipsNames = (name) =>
+  axios.get(getTipsName, { params: { name } });
 
 export const submitMergePhotos = (data) => axios.post(ffmpegMergeImage, { ...data })
 

文件差异内容过多而无法显示
+ 1 - 0
src/view/case/draw/icon.svg


+ 118 - 0
src/view/case/draw/map.js

@@ -0,0 +1,118 @@
+//wgs84_to_gcj02.js文件
+ 
+//地标 转 国测 常量
+var x_PI = (3.14159265358979324 * 3000.0) / 180.0;
+var PI = 3.1415926535897932384626;
+var a = 6378245.0; //卫星椭球坐标投影到平面地图坐标系的投影因子。  
+var ee = 0.00669342162296594323; //椭球的偏心率。
+ 
+ 
+//判断是否在国内,在中国国内的经纬度才需要做偏移
+function out_of_china(lng, lat) {
+    return (
+        lng < 72.004 ||
+        lng > 137.8347 ||
+        (lat < 0.8293 || lat > 55.8271 || false)
+    );
+}
+ 
+//转化经度
+function transformlng(lng, lat) {
+    var ret =
+        300.0 +
+        lng +
+        2.0 * lat +
+        0.1 * lng * lng +
+        0.1 * lng * lat +
+        0.1 * Math.sqrt(Math.abs(lng));
+    ret +=
+        ((20.0 * Math.sin(6.0 * lng * PI) +
+            20.0 * Math.sin(2.0 * lng * PI)) *
+            2.0) /
+        3.0;
+    ret +=
+        ((20.0 * Math.sin(lng * PI) +
+            40.0 * Math.sin((lng / 3.0) * PI)) *
+            2.0) /
+        3.0;
+    ret +=
+        ((150.0 * Math.sin((lng / 12.0) * PI) +
+            300.0 * Math.sin((lng / 30.0) * PI)) *
+            2.0) /
+        3.0;
+    return ret;
+}
+ 
+//转化纬度
+function transformlat(lng, lat) {
+    var ret =
+        -100.0 +
+        2.0 * lng +
+        3.0 * lat +
+        0.2 * lat * lat +
+        0.1 * lng * lat +
+        0.2 * Math.sqrt(Math.abs(lng));
+    ret +=
+        ((20.0 * Math.sin(6.0 * lng * PI) +
+            20.0 * Math.sin(2.0 * lng * PI)) *
+            2.0) /
+        3.0;
+    ret +=
+        ((20.0 * Math.sin(lat * PI) +
+            40.0 * Math.sin((lat / 3.0) * PI)) *
+            2.0) /
+        3.0;
+    ret +=
+        ((160.0 * Math.sin((lat / 12.0) * PI) +
+            320 * Math.sin((lat * PI) / 30.0)) *
+            2.0) /
+        3.0;
+    return ret;
+}
+ 
+//wgs84 to gcj02   地球坐标系 转 火星坐标系
+export function wgs84_to_gcj02(lng, lat) {
+    if (out_of_china(lng, lat)) {
+        return [lng, lat];
+    } else {
+        var dlat = transformlat(lng - 105.0, lat - 35.0);
+        var dlng = transformlng(lng - 105.0, lat - 35.0);
+        var radlat = (lat / 180.0) * PI;
+        var magic = Math.sin(radlat);
+        magic = 1 - ee * magic * magic;
+        var sqrtmagic = Math.sqrt(magic);
+        dlat =
+            (dlat * 180.0) /
+            (((a * (1 - ee)) / (magic * sqrtmagic)) * PI);
+        dlng =
+            (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI);
+        var mglat = lat + dlat;
+        var mglng = lng + dlng;
+ 
+        return [mglng, mglat];
+    }
+}
+ 
+ 
+//gcj02 to wgs84  火星坐标系 转 地球坐标系
+export function gcj02_to_wgs84(lng, lat) {
+    if (out_of_china(lng, lat)) {
+        return [lng, lat]
+    }
+    else {
+        var dlat = transformlat(lng - 105.0, lat - 35.0);
+        var dlng = transformlng(lng - 105.0, lat - 35.0);
+        var radlat = lat / 180.0 * PI;
+        var magic = Math.sin(radlat);
+        magic = 1 - ee * magic * magic;
+        var sqrtmagic = Math.sqrt(magic);
+        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
+        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
+        mglat = lat + dlat;
+        mglng = lng + dlng;
+        return [lng * 2 - mglng, lat * 2 - mglat]
+    }
+}
+ 
+ 
+ 

+ 255 - 0
src/view/case/draw/selectMapImage copy.vue

@@ -0,0 +1,255 @@
+<template>
+  <div class="search-layout">
+    <el-input v-model="keyword" placeholder="输入名称搜索" style="width: 350px" clearable>
+      <template #append>
+        <el-button :icon="Search" />
+      </template>
+    </el-input>
+    <div class="rrr">
+      <div class="search-result" v-show="keyword && showSearch" ref="resultEl"></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" ref="mapEl"></div>
+  </div>
+
+  <div class="def-map-info" v-if="info">
+    <p><span>纬度</span>{{ info.lat }}</p>
+    <p><span>经度</span>{{ info.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 { ref, watchEffect, onMounted  } from "vue";
+import { QuiskExpose } from "@/helper/mount";
+import { debounce } from "@/util";
+import html2canvas from "html2canvas"
+import L from 'leaflet'
+import 'leaflet/dist/leaflet.css'
+export type MapImage = { blob: Blob | null; search: MapInfo | null };
+type MapInfo = { lat: number; lng: number; zoom: number; text: string };
+
+const keyword = ref("");
+const showSearch = ref(true);
+const info = ref<MapInfo>();
+const searchInfo = ref<MapInfo>();
+
+watchEffect(() => {
+  if (keyword.value) {
+    showSearch.value = true;
+  }
+});
+
+const mapEl = ref<HTMLDivElement>();
+const resultEl = ref<HTMLDivElement>();
+const searchAMap = ref<any>();
+
+watchEffect(async (onCleanup) => {
+  if (!mapEl.value || !resultEl.value) {
+    return;
+  }
+  const AMap = await AMapLoader.load({
+    plugins: ["AMap.PlaceSearch", "AMap.Event"],
+    key: "e661b00bdf2c44cccf71ef6070ef41b8",
+    version: "2.0",
+  });
+
+  const map = new AMap.Map(mapEl.value, {
+    WebGLParams: {
+      preserveDrawingBuffer: true,
+    },
+    resizeEnable: true,
+  });
+  const placeSearch = new AMap.PlaceSearch({
+    pageSize: 5,
+    showCover: false,
+    pageIndex: 1,
+    map: map,
+    panel: resultEl.value,
+    autoFitView: true,
+  });
+  const setSearch = (data) => {
+    console.log('setSearch', data);
+    let city = data.cityname == data.adname? data.cityname : (data.cityname + data.adname);
+    searchInfo.value = {
+      text: data.pname + city + data.address,
+      lat: data.location.lat,
+      lng: data.location.lng,
+      zoom: 0,
+    };
+  };
+
+  placeSearch.on("listElementClick", (e) => {
+    setSearch(e.data);
+    showSearch.value = false;
+  });
+  let clickMarker;
+
+  map.on("click", function (e) {
+    // 获取点击位置的经纬度坐标
+    var latitude = e.lnglat.lat;
+    var longitude = e.lnglat.lng;
+
+    searchInfo.value = {
+      text: "",
+      lat: latitude,
+      lng: longitude,
+      zoom: 0,
+    };
+    clickMarker && map.remove(clickMarker);
+    clickMarker = null;
+    // 在地图上添加标记
+    clickMarker = new AMap.Marker({
+      position: [longitude, latitude],
+      title: "点击位置",
+    });
+
+    map.add(clickMarker);
+  });
+  placeSearch.on("complete", function (result) {
+    setTimeout(() => {
+      const markers = map.getAllOverlays("marker");
+      for (const marker of markers) {
+        marker.on("click", () => {
+          clickMarker && map.remove(clickMarker);
+          clickMarker = null;
+          setSearch(marker._data);
+        });
+      }
+    }, 500);
+  });
+
+  const getMapInfo = (): MapInfo => {
+    var zoom = map.getZoom(); //获取当前地图级别
+    var center = map.getCenter();
+    return {
+      text: "",
+      zoom,
+      lat: center.lat,
+      lng: center.lng,
+    };
+  };
+  //绑定地图移动与缩放事件
+  map.on("moveend", () => {
+    info.value = getMapInfo();
+  });
+  map.on("zoomend", () => {
+    info.value = getMapInfo();
+  });
+  searchAMap.value = placeSearch;
+
+  onCleanup(() => {
+    searchAMap.value = null;
+    map.destroy();
+  });
+});
+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;
+  }
+}
+
+.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>

+ 159 - 87
src/view/case/draw/selectMapImage.vue

@@ -1,100 +1,84 @@
 <template>
   <div class="search-layout">
-    <el-input v-model="keyword" placeholder="输入名称搜索" style="width: 350px" clearable>
-      <template #append>
+    <el-input v-model="keyword" placeholder="输入名称搜索" style="width: 350px" clearable @change="onSearch">
+      <!-- <template #append>
         <el-button :icon="Search" />
-      </template>
+      </template> -->
     </el-input>
     <div class="rrr">
-      <div class="search-result" v-show="keyword && showSearch" ref="resultEl"></div>
-      <div class="search-sh" v-show="keyword">
+      <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>
   <div class="def-select-map-layout">
-    <div class="def-select-map" ref="mapEl"></div>
+    <div class="def-select-map" id="mapEl" ref="mapEl"></div>
   </div>
 
-  <div class="def-map-info" v-if="info">
-    <p><span>纬度</span>{{ info.lat }}</p>
-    <p><span>经度</span>{{ info.lng }}</p>
-    <p><span>缩放级别</span>{{ info.zoom }}</p>
+  <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 { ref, watchEffect } from "vue";
+import { wgs84_to_gcj02 } from "./map"
+import { getTipsList, getTipsNames, } from "@/store/case";
+import { ref, watchEffect, onMounted  } from "vue";
 import { QuiskExpose } from "@/helper/mount";
 import { debounce } from "@/util";
 import html2canvas from "html2canvas"
+import L from 'leaflet'
+import 'leaflet/dist/leaflet.css'
 export type MapImage = { blob: Blob | null; search: MapInfo | null };
-type MapInfo = { lat: number; lng: number; zoom: number; text: string };
+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')
 
+
+let map: any = {}
+let clickMarker;
 const keyword = ref("");
 const showSearch = ref(true);
 const info = ref<MapInfo>();
 const searchInfo = ref<MapInfo>();
-
+const mapEl = ref<HTMLDivElement>();
+const keywordList = ref([]);
 watchEffect(() => {
   if (keyword.value) {
     showSearch.value = true;
   }
 });
 
-const mapEl = ref<HTMLDivElement>();
-const resultEl = ref<HTMLDivElement>();
-const searchAMap = ref<any>();
-
-watchEffect(async (onCleanup) => {
-  if (!mapEl.value || !resultEl.value) {
-    return;
-  }
-  const AMap = await AMapLoader.load({
-    plugins: ["AMap.PlaceSearch", "AMap.Event"],
-    key: "e661b00bdf2c44cccf71ef6070ef41b8",
-    version: "2.0",
-  });
-
-  const map = new AMap.Map(mapEl.value, {
-    WebGLParams: {
-      preserveDrawingBuffer: true,
-    },
-    resizeEnable: true,
-  });
-  const placeSearch = new AMap.PlaceSearch({
-    pageSize: 5,
-    showCover: false,
-    pageIndex: 1,
-    map: map,
-    panel: resultEl.value,
-    autoFitView: true,
-  });
-  const setSearch = (data) => {
-    console.log('setSearch', data);
-    let city = data.cityname == data.adname? data.cityname : (data.cityname + data.adname);
-    searchInfo.value = {
-      text: data.pname + city + data.address,
-      lat: data.location.lat,
-      lng: data.location.lng,
-      zoom: 0,
-    };
-  };
-
-  placeSearch.on("listElementClick", (e) => {
-    setSearch(e.data);
-    showSearch.value = false;
-  });
-  let clickMarker;
+onMounted(() => {
+  // 'map'为HTML节点id
+  map = L.map(mapEl.value, {
+    center: [22.61, 113.05],//中心坐标
+    zoom: 10,//缩放级别
+    zoomControl: true, //缩放组件
+    attributionControl: false, //去掉右下角logol
+    layers: [layer],//图层
+    // center: [51.505, -0.09],
+    // zoom: 13
+  })
+  
 
   map.on("click", function (e) {
     // 获取点击位置的经纬度坐标
-    var latitude = e.lnglat.lat;
-    var longitude = e.lnglat.lng;
+    var latitude = e.latlng.lat;
+    var longitude = e.latlng.lng;
+    console.log('click', e, [longitude, latitude]);
 
     searchInfo.value = {
       text: "",
@@ -102,39 +86,73 @@ watchEffect(async (onCleanup) => {
       lng: longitude,
       zoom: 0,
     };
-    clickMarker && map.remove(clickMarker);
+    clickMarker && clickMarker.remove();
     clickMarker = null;
     // 在地图上添加标记
-    clickMarker = new AMap.Marker({
-      position: [longitude, latitude],
+    clickMarker = L.marker([latitude, longitude],{
+      position: [latitude, longitude],
       title: "点击位置",
     });
-
-    map.add(clickMarker);
-  });
-  placeSearch.on("complete", function (result) {
-    setTimeout(() => {
-      const markers = map.getAllOverlays("marker");
-      for (const marker of markers) {
-        marker.on("click", () => {
-          clickMarker && map.remove(clickMarker);
-          clickMarker = null;
-          setSearch(marker._data);
-        });
-      }
-    }, 500);
+    clickMarker.addTo(map);
+    map.panTo([latitude, longitude])
+    // map.add(clickMarker);
   });
+})
 
-  const getMapInfo = (): MapInfo => {
-    var zoom = map.getZoom(); //获取当前地图级别
-    var center = map.getCenter();
-    return {
-      text: "",
-      zoom,
-      lat: center.lat,
-      lng: center.lng,
-    };
-  };
+const resultEl = ref<HTMLDivElement>();
+const searchAMap = ref<any>();
+
+watchEffect(async (onCleanup) => {
+  if (!mapEl.value || !resultEl.value) {
+    return;
+  }
+//   const AMap = await AMapLoader.load({
+//     plugins: ["AMap.PlaceSearch", "AMap.Event"],
+//     key: "e661b00bdf2c44cccf71ef6070ef41b8",
+//     version: "2.0",
+//   });
+
+//   const map = new AMap.Map(mapEl.value, {
+//     WebGLParams: {
+//       preserveDrawingBuffer: true,
+//     },
+//     resizeEnable: true,
+//   });
+//   const placeSearch = new AMap.PlaceSearch({
+//     pageSize: 5,
+//     showCover: false,
+//     pageIndex: 1,
+//     map: map,
+//     panel: resultEl.value,
+//     autoFitView: true,
+//   });
+//   const setSearch = (data) => {
+//     console.log('setSearch', data);
+//     let city = data.cityname == data.adname? data.cityname : (data.cityname + data.adname);
+//     searchInfo.value = {
+//       text: data.pname + city + data.address,
+//       lat: data.location.lat,
+//       lng: data.location.lng,
+//       zoom: 0,
+//     };
+//   };
+
+//   placeSearch.on("listElementClick", (e) => {
+//     setSearch(e.data);
+//     showSearch.value = false;
+//   });
+//   placeSearch.on("complete", function (result) {
+//     setTimeout(() => {
+//       const markers = map.getAllOverlays("marker");
+//       for (const marker of markers) {
+//         marker.on("click", () => {
+//           clickMarker && map.remove(clickMarker);
+//           clickMarker = null;
+//           setSearch(marker._data);
+//         });
+//       }
+//     }, 500);
+//   });
   //绑定地图移动与缩放事件
   map.on("moveend", () => {
     info.value = getMapInfo();
@@ -149,6 +167,55 @@ watchEffect(async (onCleanup) => {
     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) => {
+  getTipsList(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],
@@ -216,6 +283,11 @@ defineExpose<QuiskExpose>({
     max-height: 450px;
     overflow-y: auto;
   }
+  .search-list{
+    background: #fff;
+    padding-left: 10px;
+    line-height: 36px;
+  }
 }
 
 .def-map-info {

+ 5 - 0
yarn.lock

@@ -927,6 +927,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@^1.9.4:
+  version "1.9.4"
+  resolved "https://mirrors.cloud.tencent.com/npm/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d"
+  integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==
+
 local-pkg@^0.5.0:
   version "0.5.1"
   resolved "https://mirrors.cloud.tencent.com/npm/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d"