上饶市警务平台后台管理前端
guoshilong
2023-02-14 f6ca44fd34e71b9d5ae9a52ac6b7781a13b8ed7b
安保管理地图选点
4 files modified
2 files added
550 ■■■■■ changed files
src/api/security/security.js 42 ●●●●● patch | view | raw | blame | history
src/components/map/mapBox.vue 17 ●●●● patch | view | raw | blame | history
src/components/map/searchMap.vue 89 ●●●●● patch | view | raw | blame | history
src/components/map/searchMapBox.vue 350 ●●●●● patch | view | raw | blame | history
src/views/security/security.vue 46 ●●●●● patch | view | raw | blame | history
vue.config.js 6 ●●●●● patch | view | raw | blame | history
src/api/security/security.js
@@ -67,3 +67,45 @@
  })
}
//http://192.168.0.112:18080/sf3d/area/getAoiByPt?lng=117.9471794&lat=28.4474852&height=0&tolerance=10&adcode=361102
export const getAoiByPt = (row) =>{
  return request({
    url:'http://192.168.0.112:18080/sf3d/area/getAoiByPt',
    method:'get',
    data:row
  })
}
//192.168.0.112:9091/zhs/bs/search?ak=ebf48ecaa1fd436fa3d40c4600aa051f&region=361100&query=公安局&ids=61743e28bbf11700e9fc4ef03dd8bea9
export const searchByQuery  = (ak, region, query, ids) => {
  return request({
    url: '/bsapi/zhs/bs/search',
    method: 'get',
    params: {
      ak,
      region,
      query,
      ids
    }
  })
}
//http://{IP}:{PORT}/zhs/bs/search?ak=***&query= 万 达 商 场
// &region=440300&region_type=circle&page_size=3&page_num=1&infos=1&radius=500&location=113.841901,22.628249
export const searchByLonLat  = (ak, query,region,region_type,page_size,page_num,infos,radius,location) => {
  return request({
    url: '/bsapi/zhs/bs/search',
    method: 'get',
    params: {
      ak,
      query,
      region,
      region_type,
      page_size,
      page_num,
      infos,
      radius,
      location
    }
  })
}
src/components/map/mapBox.vue
@@ -32,7 +32,7 @@
export default {
    name: 'mapBox',
    props: ['routeRange', 'isDetail'],
  props: ['routeRange', 'isDetail', "searchMap"],
    data () {
        return {
            map: null,
@@ -73,7 +73,7 @@
                ],
                view: new View({
                    // 设置中心点,默认南昌,用于规划南昌市的路线
                    center: [115.9032747077233, 28.67433116990186],
          center: [117.951478782, 28.447896798],
                    projection: 'EPSG:4326',
                    // 设置缩放倍数
                    zoom: 13,
@@ -81,6 +81,7 @@
                    maxZoom: 19
                })
            })
            _this.lineVector = new VectorLayer({
                //layer所对应的source
                source: new VectorSource({
@@ -184,10 +185,6 @@
                })
            }
        },
        //回显多边形区域
        addPolygon(area){
        },
        // 将点坐标集合转换为数据库数据
        doData (val) {
            let str = "LINESTRING("
@@ -213,16 +210,20 @@
                _this.showTip = true
            }
            _this.tipTitle = "单击左键或者右键开始绘画"
            //提示器
            function mapMousemove (e) {
                _this.setTipPosition(e.offsetX, e.offsetY, 5, 5)
            }
            this.$refs.MapContent.addEventListener('mousemove', mapMousemove)
          // this.$refs.MapContent.removeEventListener('mousemove', mapMousemove)
            function mapMousedown () {
                _this.tipTitle = "可继续,或选择最终位置双击结束绘画"
            }
            this.$refs.MapContent.addEventListener('mousedown', mapMousedown)
            // this.$refs.MapContent.removeEventListener('mousedown', mapMousedown)
@@ -420,12 +421,12 @@
            _this.tipPosition.h = y + m
        },
        startAdd (routeRange) {
      if (routeRange) {
            if (routeRange.startsWith("LINESTRING")) {
                this.addLineDraw(routeRange)
            } else if (routeRange.startsWith("POINT")) {
                this.addPoint(routeRange)
            } else if (routeRange.startsWith("POLYGON")){
              this.addPolygon(routeRange)
        }
            }
        }
    },
src/components/map/searchMap.vue
New file
@@ -0,0 +1,89 @@
<template>
  <div class="basic-container">
    <div class="search-line">
      <el-input class="search-input" v-model="queryString" placeholder="请输入内容"></el-input>
      <el-button class="search-button" @click="getAddressByQuery">查询</el-button>
    </div>
    <search-map-box ref="OpenLayersMap" @getMapData="getMapData" :route-range="point"
                    :is-detail="true"></search-map-box>
  </div>
</template>
<script>
import SearchMapBox from "@/components/map/searchMapBox";
import {getAoiByPt, search, searchByLonLat, searchByQuery} from "@/api/security/security";
export default {
  name: "searchMap",
  components: {SearchMapBox},
  props: ['pointLonLat'],
  data() {
    return {
      ak:"ebf48ecaa1fd436fa3d40c4600aa051f",
      region:"361100",
      longitude: "",
      latitude: "",
      queryString: "",
      point: "",
    }
  },
  watch:{
    longitude:{
      handler(newVal){
        if (newVal){
          this.getAddressByLonLat()
        }
      }
    }
  },
  created() {
    this.point = this.pointLonLat
  },
  methods: {
    getMapData(data) {
      this.longitude = data[0][0]
      this.latitude = data[0][1]
      this.$emit("getLonLat", data[0])
    },
    getAddressByQuery() {
      let ak = this.ak
      let region = this.region
      let query = this.queryString
      let ids = "61743e28bbf11700e9fc4ef03dd8bea9"
      searchByQuery(ak,region,query,ids).then(res => {
        console.log(res)
      })
    },
    getAddressByLonLat(){
      let ak = this.ak
      let query = ""
      let region = this.region
      let region_type = "circle"
      let page_size = "3"
      let page_num = "1"
      let infos = 1
      let radius = 10
      let location = this.longitude+" "+this.latitude
      searchByLonLat(ak,query,region,region_type,page_size,page_num,infos,radius,location).then(res=>{
        console.log(res)
      })
    }
  }
}
</script>
<style scoped>
.search-line {
  display: flex;
}
.search-input {
  margin-bottom: 2%;
}
.search-button {
  height: 10%;
}
</style>
src/components/map/searchMapBox.vue
New file
@@ -0,0 +1,350 @@
<template>
  <div>
    <div id='searchMap' style="height: 50vh; width: 100%" ref="MapContent">
    </div>
  </div>
</template>
<script>
import {Feature, Map, View} from "ol";
import {Tile as TileLayer, Vector as VectorLayer} from "ol/layer";
import XYZ from "ol/source/XYZ";
import VectorSource from "ol/source/Vector";
import {Circle as StyleCircle, Fill as StyleFill, Stroke as StyleStroke, Style, Text as StyleText} from "ol/style";
import Point from "ol/geom/Point";
import Icon from "ol/style/Icon";
import Draw from "ol/interaction/Draw";
import {Circle as GeomCircle, LineString as GeomLineString, Point as GeomPoint, Polygon as GeomPolygon} from "ol/geom";
import Cluster from "ol/source/Cluster";
export default {
  name: "searchMapBox",
  props: ['routeRange'],
  data() {
    return {
      map: null,
      points: [],
      featurePoint:null,
      // 线条点数组
      linePoints: [],
      // 多边形数组
      polygonPoints: [],
      draw: null,
      drawLayer: null,
      pointVector: null,
      coordinates: [],// 保存绘画坐标地址   [[115.90490549080435, 28.746101718722358],[115.93151300423209, 28.741123538790717]]
      toData: null,// 保存数据库格式坐标地址
      showTip: false,
      tipTitle: null
    }
  },
  methods: {
    createMap() {
      let _this = this
      //初始化地图
      _this.map = new Map({
        target: 'searchMap',
        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({
          // 设置中心点
          //117.951478782, 28.447896798, 5000
          center: [117.951478782, 28.447896798],
          projection: 'EPSG:4326',
          // 设置缩放倍数
          zoom: 13,
          minZoom: 8,
          maxZoom: 19
        })
      })
      _this.pointVector = new VectorLayer({
        //layer所对应的source
        source: new VectorSource({
          wrapX: false // 禁止横向无限重复(底图渲染的时候会横向无限重复),设置了这个属性,可以让绘制的图形不跟随底图横向无限重复
        }),
        style: new Style({
          image: new Icon({
            src: "/img/dwicon.jpeg",
            anchor: [0.48, 1],
            // imgSize: [250,320],
            scale: 0.13
          }),
        })
      })
      _this.map.addLayer(_this.pointVector)
      // 在地图上回显线或点
      if (this.routeRange) {
        _this.startAdd(_this.routeRange)
      }
      this.point()
    },
    // 绘画之后的样式
    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
    },
    // 添加点
    addPoint(pointLonLat) {
      // pointLonLat = POINT(115.87531914674 28.8603307485585)
      if (pointLonLat) {
        let pointData = ""
        let pointArray = []
        pointData = pointLonLat.match(/\(([^)]*)\)/)
        pointArray = pointData[1].split(" ")
        //设置点
        let feature_Point = new Feature({
          geometry: new Point([Number(pointArray[0]), Number(pointArray[1])])
        })
        //点样式
        let style = new Style({
          image: new Icon({
            src: "/img/dwicon.jpeg",
            anchor: [0.48, 1],
            // imgSize: [250,320],
            scale: 0.13
          }),
        })
        this.featurePoint = feature_Point
        feature_Point.setStyle(style)
        this.pointVector.getSource().addFeature(feature_Point)
        let center = [Number(pointArray[0]), Number(pointArray[1])]
        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 = str + "," + `${val[0][0]} ${val[0][1]}`
      str += ")"
      // console.log(str)
      return '\'' + str + '\''
    },
    // 开始绘制
    point() {
      let _this = this
      _this.coordinates = []
      _this.map.removeInteraction(_this.draw)
      // _this.pointVector.getSource().clear()
      _this.draw = new Draw({
        source: _this.pointVector.getSource(),
        type: 'Point',
      })
      _this.map.addInteraction(_this.draw)
      // 点击事件
      _this.map.on('click', function (e) {
        if (_this.featurePoint != null){
          _this.pointVector.getSource().removeFeature(_this.featurePoint)
        }
        if (_this.coordinates.length > 0) {
          let featureArray = _this.pointVector.getSource().getFeatures()
          for (let i = 0; i < featureArray.length -1; i++) {
            _this.pointVector.getSource().removeFeature(featureArray[i])
          }
          _this.coordinates = []
        }
        // 将点坐标保存集合
        _this.coordinates.push(e.coordinate)
        _this.$emit("getMapData", _this.coordinates)
      })
    },
    // 设置统一控制点击事件,需要画图方式在此处切换
    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.pointVector.getSource().clear()
      // 传值给父组件
      _this.$emit('toData', "")
    },
    // 获取新的 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
        // }
      })
    },
    startAdd(routeRange) {
      if (routeRange.startsWith("POINT")) {
        this.addPoint(routeRange)
      }
    }
  },
  mounted() {
    this.createMap()
  }
}
</script>
<style scoped>
</style>
src/views/security/security.vue
@@ -12,9 +12,11 @@
            </template>
            <template slot-scope="{type,size,row,index}" slot="menu">
                <el-button icon="el-icon-coordinate" :size="size" :type="type"
                    @click="handlePersonList(row)">活动人员</el-button>
                   @click="handlePersonList(row)">活动人员
        </el-button>
                <el-button icon="el-icon-data-line" :size="size" :type="type"
                    @click="handleCarList(row)">活动车辆</el-button>
                   @click="handleCarList(row)">活动车辆
        </el-button>
            </template>
            <template slot="activityAreaForm">
              <map-box ref="OpenLayersMap" @toData="toData" :routeRange="form.activityArea"></map-box>
@@ -29,6 +31,18 @@
        <el-drawer title="活动车辆区域" :visible.sync="carBox" :append-to-body="true" size="50%" :destroy-on-close="true">
            <securityManageCar ref="car" :securityId="securityId" />
        </el-drawer>
    <el-dialog
      title="提示"
      :visible.sync="placeBox"
      append-to-body
      destroy-on-close
      width="70%">
      <search-map @getLonLat="getLonLat" :point-lon-lat="point"></search-map>
      <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="confirmLonLat">确 定</el-button>
          </span>
    </el-dialog>
    </basic-container>
</template>
@@ -40,9 +54,11 @@
import securityManage from "@/views/securityManage/securityManage"
import securityManageCar from "@/views/securityManageCar/securityManageCar"
import MapBox from "@/components/map/mapBox";
import SearchMap from "@/components/map/searchMap";
export default {
    components: {
    SearchMap,
      MapBox,
        securityManage,
        securityManageCar
@@ -52,6 +68,9 @@
            securityId: "",
            carBox: false,
            personBox: false,
      placeBox: false,
      point:"",
      chosePoint:{},
            form: {},
            query: {},
            loading: true,
@@ -115,7 +134,10 @@
                    {
                        label: "活动地点",
                        prop: "place",
                        span: 24
            span: 24,
            click: () => {
              this.placeBox = !this.placeBox
            },
                        // addDisplay: false,
                        // editDisplay: false,
                        // viewDisplay: false,
@@ -125,6 +147,7 @@
                      prop: "longitude",
                      span: 12,
                      hide: true,
            disabled:true,
                      rules: [{
                        required: true,
                        message: "请输入纬度",
@@ -136,6 +159,7 @@
                      prop: "latitude",
                      span: 12,
                      hide: true,
            disabled: true,
                      rules: [{
                        required: true,
                        message: "请输入纬度",
@@ -316,6 +340,11 @@
              return
            }
      if (row.activityArea.startsWith("LINESTRING")){
      }else {
        row.activityArea = "'LINESTRING("+row.activityArea+")'"
      }
            row.position = row.longitude + " " + row.latitude
            update(row).then(() => {
                this.onLoad(this.page)
@@ -375,6 +404,7 @@
                    this.form = data
                    this.form['longitude'] = data.position.split(" ")[0]
                    this.form['latitude'] = data.position.split(" ")[1]
          this.point = "POINT("+this.form.longitude +" "+this.form.latitude+")"
                })
            }
            done()
@@ -433,6 +463,16 @@
        //地图传回的polygon坐标
        toData(data){
          this.form.activityArea = data
    },
    getLonLat(data){
      this.chosePoint.longitude = data[0]
      this.chosePoint.latitude = data[1]
    },
    confirmLonLat(){
      this.form.longitude =  this.chosePoint.longitude
      this.form.latitude =  this.chosePoint.latitude
      this.point = "POINT("+this.form.longitude +" "+this.form.latitude+")"
      this.placeBox = false
        }
    }
}
vue.config.js
@@ -43,6 +43,12 @@
                pathRewrite: {
                    '^/api': '/'
                }
            },
          'bsapi': {
              target: 'http://192.168.0.112:9091',
              pathRewrite: {
                '^/bsapi': '/'
              }
            }
        }
    }