From 43b9b5eb9a46cc0ebe46f207a37fb6832e8b7046 Mon Sep 17 00:00:00 2001
From: guoshilong <123456>
Date: Sat, 26 Nov 2022 14:55:44 +0800
Subject: [PATCH] 范围管理详情显示地图

---
 src/views/securityManageCar/securityManageCar.vue |   27 +++
 package.json                                      |    2 
 src/views/range/range.vue                         |   27 +++
 src/components/map/mapBox.vue                     |  412 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 466 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 7a9dddb..e01e97e 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "test:e2e": "vue-cli-service test:e2e"
   },
   "dependencies": {
+    "@dvgis/dc-sdk": "^2.17.0",
     "avue-plugin-ueditor": "^0.1.4",
     "axios": "^0.18.0",
     "babel-polyfill": "^6.26.0",
@@ -23,6 +24,7 @@
     "mockjs": "^1.0.1-beta3",
     "node-gyp": "^5.0.6",
     "nprogress": "^0.2.0",
+    "ol": "^7.1.0",
     "portfinder": "^1.0.23",
     "script-loader": "^0.7.2",
     "vue": "^2.6.10",
diff --git a/src/components/map/mapBox.vue b/src/components/map/mapBox.vue
new file mode 100644
index 0000000..19e92a8
--- /dev/null
+++ b/src/components/map/mapBox.vue
@@ -0,0 +1,412 @@
+<template>
+  <div>
+    <div id='map' :style="{height:isDetail?'90vh':'40vh',width:'100%'}">
+      <div style="position: absolute;right:40%;top:-1%;z-index: 999999">
+        <p style="margin-top: 10px" v-if="!isDetail">
+          <el-button type="primary" size="small" @click="point()">绘制路线</el-button>
+          <el-button type="danger" size="small" @click="clearDraw()">重置</el-button>
+        </p>
+      </div>
+      <!--画线后的提示-->
+      <div class="mapTip" v-if="showTip" :style="{ top: tipPosition.h + 'px', left: tipPosition.w + 'px' }">
+        {{ tipTitle }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import 'ol/ol.css'
+import {Map, View, Feature} from 'ol'
+import VectorSource from 'ol/source/Vector'
+import Cluster from 'ol/source/Cluster'
+import {Vector as VectorLayer, Tile as TileLayer} from 'ol/layer'
+import LineString from "ol/geom/LineString";
+import Point from 'ol/geom/Point';
+import Icon from 'ol/style/Icon';
+import {Style, Fill as StyleFill, Stroke as StyleStroke, Text as StyleText, Circle as StyleCircle} from 'ol/style'
+import {Circle as GeomCircle, Point as GeomPoint, LineString as GeomLineString, Polygon as GeomPolygon} from 'ol/geom'
+import Draw from 'ol/interaction/Draw'
+import XYZ from "ol/source/XYZ";
+import 'ol/ol.css'
+
+export default {
+  name: 'mapBox',
+  props:['routeRange','isDetail',"pointLonLat"],
+  data() {
+    return {
+      map: null,
+      points: [],
+      // 线条点数组
+      linePoints: [],
+      // 多边形数组
+      polygonPoints: [],
+      draw: null,
+      drawLayer: null,
+      lineVector: null,
+      pointVector:null,
+      coordinates: [],// 保存绘画坐标地址   [[115.90490549080435, 28.746101718722358],[115.93151300423209, 28.741123538790717]]
+      toData: null,// 保存数据库格式坐标地址
+      showTip:false,
+      tipPosition: {//提示的位置
+        w: 200,
+        h: 10,
+      },
+      tipTitle:null
+    }
+  },
+  methods: {
+
+    createMap() {
+      let _this = this
+
+      _this.map = new Map({
+        target: 'map',
+        layers: [
+          new TileLayer({
+            source: new XYZ({
+              url: "https://webmap-tile.sf-express.com/MapTileService/rt?fetchtype=static&x={x}&y={y}&z={z}&project=sfmap&pic_size=256&pic_type=png8&data_name=361100&data_format=merged-dat&data_type=normal", // 行政区划
+            })
+          }),
+
+        ],
+        view: new View({
+          // 设置中心点,默认南昌,用于规划南昌市的路线
+          center: [115.9032747077233, 28.67433116990186],
+          projection: 'EPSG:4326',
+          // 设置缩放倍数
+          zoom: 13,
+          minZoom: 8,
+          maxZoom: 19
+        })
+      })
+      _this.lineVector = new VectorLayer({
+        //layer所对应的source
+        source: new VectorSource({
+          wrapX: false // 禁止横向无限重复(底图渲染的时候会横向无限重复),设置了这个属性,可以让绘制的图形不跟随底图横向无限重复
+        }),
+      })
+      _this.pointVector = new VectorLayer({
+        //layer所对应的source
+        source: new VectorSource({
+          wrapX: false // 禁止横向无限重复(底图渲染的时候会横向无限重复),设置了这个属性,可以让绘制的图形不跟随底图横向无限重复
+        }),
+      })
+      _this.map.addLayer(_this.lineVector)
+      _this.map.addLayer(_this.pointVector)
+      _this.addLineDraw(_this.routeRange)
+      _this.addPoint(_this.pointLonLat)
+    },
+    // 绘画之后的样式
+    styleFunction() {
+      // 绘画之后的样式
+      let styles = [
+        new Style({
+          fill: new StyleFill({color: "rgba(255, 255, 255, 0.2)"}),
+          stroke: new StyleStroke({
+            color: 'rgb(252, 94, 32)',
+            width: 5
+          })
+        })
+      ]
+      return styles
+    },
+    // 添加线路
+    addLineDraw(toData) {
+      // toData = 'LINESTRING(115.90505364627936 28.740342332731327,115.9119724729309 28.74040302419318,115.90766337913915 28.73566909016844)'
+      if (toData) {
+        // 将数据库点坐标数据转换
+        let entityData = "";
+        let entityArr = [];
+        entityData = toData.match(/\(([^)]*)\)/);
+        if (entityData && entityData != "") {
+          entityData = entityData[1].split(",");
+          for (let j = 0; j < entityData.length; j++) {
+            entityArr.push([
+              Number(entityData[j].split(" ")[0]),
+              Number(entityData[j].split(" ")[1]),
+            ]);
+          }
+        }
+        // let lineCoords = [[115.90490549080435, 28.746101718722358],[115.93151300423209, 28.741123538790717],[115.90696542732779, 28.73408542233564],[115.90696542732779, 28.73408542233564]]
+        let lineCoords = entityArr
+        let view = this.map.getView();
+        view.setCenter([
+          lineCoords[Math.ceil(lineCoords.length / 2)][0],
+          lineCoords[Math.ceil(lineCoords.length / 2)][1],
+        ]);
+        view.setZoom(14.5);
+
+        let feature_LineString = new Feature({
+          geometry: new LineString(lineCoords),
+        });
+        feature_LineString.setStyle(this.styleFunction());// 设置样式
+        this.lineVector.getSource().addFeature(feature_LineString);
+      }
+    },
+    // 添加点
+    addPoint(pointLonLat){
+      if (pointLonLat){
+        //设置点
+        let feature_Point = new Feature({
+          geometry: new Point([Number(pointLonLat.lon), Number(pointLonLat.lat)])
+        })
+        //点样式
+        let style = new Style({
+          image: new Icon({
+            src: "/img/dwicon.jpeg",
+            anchor: [0.48, 0.52],
+            // imgSize: [250,320],
+            scale: 0.2
+          }),
+        });
+        feature_Point.setStyle(style);
+        this.pointVector.getSource().addFeature(feature_Point);
+        let center = [Number(pointLonLat.lon), Number(pointLonLat.lat)];
+        let view = this.map.getView();
+        view.setZoom(16);
+        view.animate({
+          center: center,
+          duration: 5,
+        });
+      }
+    },
+    // 将点坐标集合转换为数据库数据
+    doData(val) {
+      let str = "LINESTRING(";
+      for (let k = 0; k < val.length; k++) {
+        str += `${val[k][0]} ${val[k][1]}`;
+        if (k != val.length - 1) {
+          str += ",";
+        }
+      }
+      str += ")";
+      // console.log(str)
+      return '\''+str+'\'';
+    },
+    // 开始绘制
+    point() {
+      let _this = this
+      _this.coordinates = []
+      _this.map.removeInteraction(_this.draw)
+      _this.lineVector.getSource().clear()
+      //提示
+      if(!_this.showTip){
+        _this.showTip = true
+      }
+      _this.tipTitle = "单击左键或者右键开始绘画"
+      //提示器
+      $("#map").off("mousemove").mousemove(function (e) {
+        _this.setTipPosition(e.offsetX, e.offsetY, 5, 5);
+      })
+      $("#map").off("mousedown").mousedown(function () {
+        _this.tipTitle = "可继续,或选择最终位置双击结束绘画"
+      })
+
+      _this.draw = new Draw({
+        source: _this.lineVector.getSource(),
+        type: 'LineString',
+        style: new Style({
+          stroke: new StyleStroke({
+            color: "red",
+            width: 3,
+          })
+        }),
+      })
+      _this.map.addInteraction(_this.draw)
+      // 点击事件
+      _this.map.on('click', function (e) {
+        // 将点坐标保存集合
+        _this.coordinates.push(e.coordinate)
+      })
+      // 结束事件
+      _this.draw.on('drawend', function () {
+
+        _this.map.removeInteraction(_this.draw);
+        _this.lineVector.setStyle(_this.styleFunction())// 路线画好之后的样式
+        // 将点坐标集合转换为数据库数据
+        let toData = _this.doData(_this.coordinates)
+        // 传值给父组件
+        _this.$emit('toData',toData)
+        //隐藏提示
+        _this.tipTitle = null;
+        _this.showTip = false
+      })
+    },
+    // 设置统一控制点击事件,需要画图方式在此处切换
+    handleClick(point) {
+      // 绘制连线
+      this.drawLineString(point)
+      // 绘制点
+      // this.drawPoint(point)
+      // 绘制圆形
+      // this.drawCircle(point)
+      // 绘制多边形
+      // this.drawPolygon(point)
+    },
+    // 绘制点位
+    drawPoint(center) {
+      let vectorLayer = this.getLayer()
+
+      let point = new GeomPoint(center)
+      let feature = new Feature(point)
+      vectorLayer.getSource().addFeature(feature)
+      this.map.addLayer(vectorLayer)
+    },
+    // 绘制连线
+    drawLineString(point) {
+      this.linePoints.push(point)
+      let featureLine = new Feature({
+        geometry: new GeomLineString(this.linePoints),
+      });
+
+      // 添加线的样式
+      let lineStyle = new Style({
+        fill: new StyleFill({
+          color: 'rgba(1, 210, 241, 0.1)'
+        }),
+        stroke: new StyleStroke({
+          color: 'rgba(255, 0, 0)',
+          width: 4,
+        }),
+      });
+      featureLine.setStyle(lineStyle);
+
+      let source = new VectorSource()
+      source.addFeature(featureLine)
+      let layer = new VectorLayer()
+      layer.setSource(source)
+      this.map.addLayer(layer)
+    },
+    // 绘制区域圆形
+    drawCircle(center) {
+      let vectorLayer = this.getLayer()
+
+      // 设置半径
+      let circle = new GeomCircle(center, 0.003)// 新建圆对象
+      let feature = new Feature(circle)// 新建Feature对象 并将circle传入
+      vectorLayer.getSource().addFeature(feature)// 将Feature对象填入图层源
+      this.map.addLayer(vectorLayer) // 将图层添至地图对象
+    },
+    // 画多边形
+    drawPolygon(point) {
+      this.polygonPoints.push(point)
+      let feature = new Feature({
+        geometry: new GeomPolygon([this.polygonPoints]),
+        attributes: null
+      });
+      // 添加线的样式
+      let lineStyle = new Style({
+        fill: new StyleFill({
+          color: 'rgba(1, 210, 241, 0.1)'
+        }),
+        stroke: new StyleStroke({
+          color: 'rgba(255, 0, 0)',
+          width: 4,
+        }),
+      });
+      feature.setStyle(lineStyle);
+      let source = new VectorSource();
+      source.addFeature(feature)
+      let vectorLayer = new VectorLayer({
+        source: source
+      })
+      this.map.addLayer(vectorLayer)
+    },
+    // 设置聚合点
+    addMarker() {
+      let source = new VectorSource();
+      // 随机创建200个要素,后台点位取出后按此格式处理
+      for (let i = 1; i <= 200; i++) {
+        let coordinates = [115.90 + Math.random() * 0.05, 28.64 + Math.random() * 0.05];
+        let feature = new Feature(new GeomPoint(coordinates));
+        source.addFeature(feature);
+      }
+
+      // 聚合
+      let clusterSource = new Cluster({
+        source: source,
+        distance: 50
+      })
+
+      let clusters = new VectorLayer({
+        source: clusterSource,
+        style: function (feature) {
+          let size = feature.get('features').length;
+          let style = new Style({
+            image: new StyleCircle({
+              radius: 20,
+              stroke: new StyleStroke({
+                color: 'white'
+              }),
+              fill: new StyleFill({
+                color: '#AAD3DF'
+              })
+            }),
+            text: new StyleText({
+              text: size.toString(),
+              fill: new StyleFill({
+                color: 'black'
+              })
+            })
+          })
+          return style;
+        }
+      });
+
+      this.map.addLayer(clusters)
+    },
+    // 重置图层
+    clearDraw(){
+      let _this = this
+      _this.coordinates = []
+      _this.map.removeInteraction(_this.draw)
+      _this.lineVector.getSource().clear()
+      _this.showTip = false
+      _this.tipTitle = null
+    },
+    // 获取新的 layer 图层对象
+    getLayer() {
+      return new VectorLayer({
+        source: new VectorSource({
+          features: ''
+        }),
+        // 设置样式,但不完全兼容
+        // style: function (feature) {
+        //   let style = new Style({
+        //     stroke: new StyleStroke({
+        //       color: '#E80000',
+        //       width: 2
+        //     }),
+        //     fill: new StyleFill({
+        //       color: 'rgba(0,0,0,0)'
+        //     })
+        //   })
+        //   return style
+        // }
+      })
+    },
+    // 设置提示位置
+    setTipPosition(x, y, n, m) {
+      let _this = this
+      _this.tipPosition.w = x + n;
+      _this.tipPosition.h = y + m;
+    },
+  },
+  mounted() {
+    this.createMap()
+  }
+
+}
+</script>
+
+<style>
+.mapTip {
+  background-color: rgb(168, 168, 168);
+  padding: 5px;
+  border: 1px solid #000;
+  position: absolute;
+  z-index: 10 !important;
+  border-radius: 5px;
+}
+</style>
diff --git a/src/views/range/range.vue b/src/views/range/range.vue
index 9c41d6e..457b6ad 100644
--- a/src/views/range/range.vue
+++ b/src/views/range/range.vue
@@ -27,15 +27,34 @@
                    @click="handleDelete">删 除
         </el-button>
       </template>
+      <template slot-scope="{row,index}" slot="menu">
+        <el-button  type="text"
+                   size="small"
+                   icon="el-icon-view"
+                   @click="handleDetail(row)">详情
+        </el-button>
+      </template>
     </avue-crud>
+
+    <el-drawer
+      title="地图详情"
+      :visible.sync="isDetail"
+      :append-to-body="true"
+      size="60%"
+      direction="rtl"
+      :before-close="handleClose">
+      <map-box v-if="isDetail" :is-detail="isDetail" :route-range="routeRange"></map-box>
+    </el-drawer>
   </basic-container>
 </template>
 
 <script>
   import {getList, getDetail, add, update, remove} from "@/api/range/range";
   import {mapGetters} from "vuex";
+  import MapBox from "@/components/map/mapBox";
 
   export default {
+    components: {MapBox},
     data() {
       return {
         form: {},
@@ -156,7 +175,9 @@
             },
           ]
         },
-        data: []
+        data: [],
+        isDetail:false,
+        routeRange:"",
       };
     },
     computed: {
@@ -243,6 +264,10 @@
             this.$refs.crud.toggleSelection();
           });
       },
+      handleDetail(row){
+        this.routeRange = row.positions
+        this.isDetail = true
+      },
       beforeOpen(done, type) {
         if (["edit", "view"].includes(type)) {
           getDetail(this.form.id).then(res => {
diff --git a/src/views/securityManageCar/securityManageCar.vue b/src/views/securityManageCar/securityManageCar.vue
index e3bfa1b..2490135 100644
--- a/src/views/securityManageCar/securityManageCar.vue
+++ b/src/views/securityManageCar/securityManageCar.vue
@@ -27,15 +27,34 @@
                    @click="handleDelete">删 除
         </el-button>
       </template>
+      <template slot-scope="{row,index}" slot="menu">
+        <el-button  type="text"
+                    size="small"
+                    icon="el-icon-view"
+                    @click="handleDetail(row)">详情
+        </el-button>
+      </template>
     </avue-crud>
+
+    <el-drawer
+      title="地图详情"
+      :visible.sync="isDetail"
+      :append-to-body="true"
+      size="60%"
+      direction="rtl"
+      :before-close="handleClose">
+      <map-box v-if="isDetail" :is-detail="isDetail" :route-range="routeRange"></map-box>
+    </el-drawer>
   </basic-container>
 </template>
 
 <script>
   import {getPage, getDetail, add, update, remove} from "@/api/securityManageCar/securityManageCar";
   import {mapGetters} from "vuex";
+  import MapBox from "@/components/map/mapBox";
 
   export default {
+    components: {MapBox},
     data() {
       return {
         form: {},
@@ -197,7 +216,9 @@
             },
           ]
         },
-        data: []
+        data: [],
+        isDetail:false,
+        routeRange:"",
       };
     },
     computed: {
@@ -284,6 +305,10 @@
             this.$refs.crud.toggleSelection();
           });
       },
+      handleDetail(row){
+        this.routeRange = row.position
+        this.isDetail = true
+      },
       beforeOpen(done, type) {
         if (["edit", "view"].includes(type)) {
           getDetail(this.form.id).then(res => {

--
Gitblit v1.9.3