瀏覽代碼

提交代码

tangning 2 月之前
父節點
當前提交
907dd955c2

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

@@ -0,0 +1,152 @@
+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);
+};

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

@@ -0,0 +1,361 @@
+<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, 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);
+const getblc = function() {
+  const size = map.getSize();
+  // 获取地图容器相对于视口的位置
+const container = map.getContainer();
+const position = container.getBoundingClientRect();
+
+const box = {
+  width: size.x,
+  height: size.y,
+  left: position.left,
+  top: position.top,
+  right: position.left + size.x,
+  bottom: position.top + size.y
+};
+console.log('getblc',box);
+const bounds = map.getBounds();
+// 获取东北角和西北角(计算高度)
+const northEast = bounds.getNorthEast();
+const northWest = L.latLng(northEast.lat, bounds.getSouthWest().lng);
+
+// 获取西南角和东南角(计算宽度)
+const southWest = bounds.getSouthWest();
+const southEast = L.latLng(southWest.lat, northEast.lng);
+
+// 计算宽度(东西方向距离)
+const widthInMeters = northEast.distanceTo(northWest);
+
+// 计算高度(南北方向距离)
+const heightInMeters = northEast.distanceTo(southEast);
+
+const geoBox = {
+  width: widthInMeters,  // 宽度(米)
+  height: heightInMeters, // 高度(米)
+  center: bounds.getCenter(),
+  zoom: map.getZoom()
+};
+
+console.log('getblc',geoBox);
+return geoBox
+}
+watchEffect(() => {
+  searchAMap.value && search(keyword.value);
+});
+
+defineExpose<QuiskExpose>({
+  submit() {
+    return new Promise<MapImage>((resolve) => {
+      console.log("searchInfo", searchInfo.value, mapEl.value);
+      const info = getblc();
+      if (mapEl.value) {
+        const canvas = mapEl.value.querySelector("canvas") as HTMLCanvasElement;
+        console.log(canvas, "canvas");
+        canvas &&
+          canvas.toBlob((blob) => resolve({ blob, search: searchInfo.value!, ...info })); // || 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!, ...info });
+          });
+        }
+      } 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/selectMapImagess.vue";
+// import SelectMapImage, { MapImage } from "./draw/selectMapImagess.vue";
+import SelectMapImage, { MapImage } from "./draw/selectMapleaftImages.vue";
 // import SelectMapImage, { MapImage } from "./draw/selectMapImage.vue";
 import { quiskMountFactory } from "@/helper/mount";
 import { nextTick } from "vue";

+ 16 - 6
src/view/material/index.vue

@@ -25,12 +25,16 @@
           >
             绘制方位图
           </el-button>
-          <div class="phote my-4 w-full" v-for="item,index in list.xct" :key="index" v-show="item.caseFilesList?.length">
-            <p class="pb-2 title1">{{item.filesTypeName}}</p>
+          <div class="phote my-4 w-full">
+            <p class="pb-2 title1">平面图</p>
             <div class="pmt-phote w-full flex justify-between ">
-              <viewImg :list="item.filesTypeName=='平面图'?list.pmt:list.fwt || []" delete  @handleItem="handleoverviewItem" height="66px" />
-              <!-- <viewImg :list="item.caseFilesList || []"  @handleItem="handleItem" height="66px" /> -->
-              <!-- <viewImg :list="item.caseFilesList || []"  @handleItem="handleItem" height="66px" /> -->
+              <viewImg :list="list.pmt" delete  @handleItem="handleoverviewItem" height="66px" />
+            </div>
+          </div>
+          <div class="phote my-4 w-full">
+            <p class="pb-2 title1">方位图</p>
+            <div class="pmt-phote w-full flex justify-between ">
+              <viewImg :list="list.fwt || []" delete  @handleItem="handleoverviewItem" height="66px" />
             </div>
           </div>
         </div>
@@ -169,13 +173,19 @@ const gotoDraw = async (type: BoardType, id: number) => {
   if(BoardType.scene == type) {
     window.open(`/draw/#/overview?caseId=${caseId.value}`);
   }else{
-    const {blob} = await selectMapImage({});
+    const {blob, width, height} = await selectMapImage({});
+    console.log('blob', blob)
+    if(!blob){
+      return
+    }
     const file = new File([blob], `方位图_.jpg`)
     const mapUrl = await uploadOldFile(file)
     const res = await overviewAdd({
       caseId: caseId.value,
       title: '方位图',
       cover: mapUrl,
+      height,
+      width,
       mapUrl
     })
     window.open(`/draw/#/overview?caseId=${caseId.value}&overviewId=${res.id}`);