From 8e3865214943c20e1269a06d6e1cbbc4c8c7890f Mon Sep 17 00:00:00 2001
From: guanqb <18720758508@163.com>
Date: Tue, 16 Jan 2024 16:02:46 +0800
Subject: [PATCH] 派遣服务地图标点

---
 public/img/map/unit.png                       |    0 
 src/views/dispatch/components/OlMapBox.vue    |  428 +++++++++++++++++++++++++++++++++++++++++++++++
 src/api/dispatch/dispatch.js                  |   11 +
 src/views/dispatch/dispatchView.vue           |   40 ++-
 src/views/dispatch/components/dispatchMap.vue |   23 +
 5 files changed, 477 insertions(+), 25 deletions(-)

diff --git a/public/img/map/unit.png b/public/img/map/unit.png
new file mode 100644
index 0000000..d5435a6
--- /dev/null
+++ b/public/img/map/unit.png
Binary files differ
diff --git a/src/api/dispatch/dispatch.js b/src/api/dispatch/dispatch.js
index e9283f4..50e57c6 100644
--- a/src/api/dispatch/dispatch.js
+++ b/src/api/dispatch/dispatch.js
@@ -1,4 +1,4 @@
-import request from '@/router/axios';
+import request from '@/router/axios'
 
 export const getdata = (current, size, params) => {
     return request({
@@ -12,6 +12,15 @@
     })
 }
 
+export const getAlldata = (params) => {//不分页
+    return request({
+        url: '/api/dispatcherUnit/getAll',
+        method: 'get',
+        params: {
+            ...params
+        }
+    })
+}
 
 export const getDispatcherUnitByDeptId = (deptId) => {
     return request({
diff --git a/src/views/dispatch/components/OlMapBox.vue b/src/views/dispatch/components/OlMapBox.vue
new file mode 100644
index 0000000..2292e3d
--- /dev/null
+++ b/src/views/dispatch/components/OlMapBox.vue
@@ -0,0 +1,428 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2023-10-11 16:01:58
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2023-11-29 14:17:09
+ * @FilePath: \web\business\src\components\OlMapBox\index.vue
+ * @Description:
+ *
+ * Copyright (c) 2023 by shuishen, All Rights Reserved.
+-->
+<template>
+    <div class="w100 h100">
+        <div id="OlMapBoxElement" class="w100 h100">
+        </div>
+        <div id="popup" class="ol-popup" v-show="isShowUnitInfoPopover">
+            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
+            <div id="popup-content">
+                <p>负责人:{{ unitData.securityLinkman }}</p>
+                <p>联系方式:{{ unitData.cell }}</p>
+                <p>派遣保安员数:{{ unitData.num }}</p>
+                <p>派遣单位行业:{{ unitData.professionName }}</p>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import "ol/ol.css"
+import OlView from "ol/View.js"
+import OlLayerTile from "ol/layer/Tile.js"
+import Overlay from "ol/Overlay.js"
+import OlMap from "ol/Map.js"
+import XYZ from "ol/source/XYZ"
+import Cluster from "ol/source/Cluster"
+import VectorLayer from "ol/layer/Vector"
+import VectorSource from "ol/source/Vector"
+import Feature from 'ol/Feature.js'
+import Point from 'ol/geom/Point.js'
+import { Icon, Style, Fill, Text, Stroke, Circle } from 'ol/style.js'
+import { getAlldata } from "@/api/dispatch/dispatch"
+import { mapGetters } from "vuex"
+import { mapState } from "vuex"
+
+let mapView = null
+let layersObjcect = {}
+
+let baseMapLayer = {
+    yx: [],
+    sl: []
+}
+
+let unitInfoPopover = null
+
+export default {
+    name: 'OlMapBox',
+
+    props: {
+        mapType: {
+            type: String,
+            default: 'sl'
+        },
+
+        mapContrast: {
+            type: String,
+            default: 'custom'
+        }
+    },
+
+    data () {
+        return {
+            publicPath: process.env.BASE_URL,
+            unitData: {},
+            isShowUnitInfoPopover: false
+        }
+    },
+
+    computed: {
+        ...mapGetters(["permission", "userInfo"]),
+
+        ...mapState({
+            userInfo: state => state.user.userInfo
+        })
+    },
+    mounted () {
+        const that = this
+
+        this.$nextTick(() => {
+            mapView = new OlMap({
+                target: 'OlMapBoxElement',
+                layers: [],
+                view: new OlView({
+                    // 初始化中心点坐标,经纬度一会自己换一下
+                    center: [112.85857823133, 35.496284586473],
+                    zoom: 18,
+                    projection: "EPSG:4326"
+                }),
+            })
+
+            mapView.on("singleclick", function (event) {
+                mapView.forEachFeatureAtPixel(
+                    event.pixel,
+                    (feature) => {
+                        feature.dispatchEvent && feature.dispatchEvent({ type: 'click', event: event })
+                    }
+                )
+            })
+
+            mapView.getView().on('change:resolution', function () {
+                // console.log('mapView地图缩放事件')
+            })
+
+            that.getAlldata()
+            that.baseInitLayer(that.mapType)
+        })
+    },
+
+    methods: {
+        // 图标点击事件
+        pqfwIconClick (e) {
+            this.generateMapPopup(e)
+        },
+
+        // 获取派遣服务列表
+        getAlldata () {
+            let params = {}
+            let roleName = this.userInfo.role_name
+            if (
+                roleName == "保安公司管理员" ||
+                roleName == "保安" ||
+                roleName == "分公司管理员"
+            ) {
+                params.deptId = this.userInfo.dept_id
+            } else if (roleName == "公安管理员" || roleName == "administrator" || roleName == "民警") {
+                params.jurisdiction = this.userInfo.jurisdiction
+            }
+            getAlldata(params).then(res => {
+                this.$nextTick(() => {
+                    this.mapRemoveLayer(['pqfwLayer'])
+                    this.mapAddClusterLayer('pqfwLayer', 'img/map/unit.png', res.data.data, this.pqfwIconClick)
+                })
+            })
+        },
+
+        /**
+         * @description: 底图加载
+         * @param {*} type
+         * @return {*}
+         */
+        baseInitLayer (type) {
+            if (baseMapLayer.yx.length) {
+                baseMapLayer.yx.forEach(item => {
+                    mapView.removeLayer(item)
+                })
+                baseMapLayer.yx = []
+            }
+
+            if (baseMapLayer.sl.length) {
+                baseMapLayer.sl.forEach(item => {
+                    mapView.removeLayer(item)
+                })
+                baseMapLayer.sl = []
+            }
+
+            if (type == 'yx') {
+                let yxImgW = new OlLayerTile({
+                    zIndex: 1,
+                    title: '影像',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(yxImgW)
+
+                baseMapLayer.yx.push(yxImgW)
+
+                let yxCvaW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '影像标注',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(yxCvaW)
+
+                baseMapLayer.yx.push(yxCvaW)
+            } else if (type == 'sl') {
+                let slVecW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '矢量',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(slVecW)
+
+                baseMapLayer.sl.push(slVecW)
+
+                let slCvaW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '矢量标注',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(slCvaW)
+
+                baseMapLayer.sl.push(slVecW)
+            }
+        },
+
+        // javascript 转换
+        lonLat2Mercator (lonlat) {
+            var mercator = {
+                x: 0,
+                y: 0
+            }
+            var earthRad = 6378137.0
+            mercator.x = lonlat.lng * Math.PI / 180 * earthRad
+            var a = lonlat.lat * Math.PI / 180
+            mercator.y = earthRad / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)))
+            return mercator
+        },
+
+        // 生成图标图层
+        getCurItemFeature (params) {
+            const iconFeature = new Feature({
+                geometry: new Point([Number(params.lng), Number(params.lat)]),
+                attributes: params.item
+            })
+
+            let styleOptions = {
+                cursor: 'pointer',
+            }
+
+            if (params.url) {
+                styleOptions.image = new Icon({
+                    scale: params.scale || 1,
+                    imgSize: params.imgSize || [32, 32],
+                    src: params.url,
+                })
+            }
+
+            if (params.text) {
+                let textElement = document.createElement('span')
+                textElement.innerHTML = params.text
+
+                let color = '#0000FF'
+
+                styleOptions.text = new Text({
+                    // 对齐方式
+                    textAlign: 'center',
+                    // 文本基线
+                    textBaseline: 'middle',
+                    text: textElement.innerHTML,
+                    font: '14px Arial',
+                    fill: new Fill({
+                        color: 'white'
+                    }),
+                    // 填充背景
+                    backgroundFill: new Fill({
+                        color: color
+                    }),
+                    padding: [2, 5, 2, 5],
+                    stroke: new Stroke({ color: '#00000000', width: 1 }),
+                    // offsetX: -60,
+                    offsetY: 30
+                })
+            }
+
+            iconFeature.setStyle(new Style(styleOptions))
+
+            iconFeature.on('click', (e) => {
+                if (params.event) {//icon事件参数
+                    params.event(e.target.values_.attributes)//点击事件触发事件并传参
+                }
+            })
+            return iconFeature
+        },
+
+        /**
+         * 删除图层
+         * @param {*} layerName 图层名称
+         */
+        mapRemoveLayer (layerNames) {
+            layerNames.forEach(item => {
+                if (layersObjcect[item] && layersObjcect[item] != null) {
+                    mapView.removeLayer(layersObjcect[item])
+                    delete layersObjcect[item]
+                }
+
+                if (layersObjcect[item + 'ONE'] && layersObjcect[item + 'ONE'] != null) {
+                    mapView.removeLayer(layersObjcect[item + 'ONE'])
+                    delete layersObjcect[item + 'ONE']
+                }
+
+                if (layersObjcect[item + 'TWO'] && layersObjcect[item + 'TWO'] != null) {
+                    mapView.removeLayer(layersObjcect[item + 'TWO'])
+                    delete layersObjcect[item + 'TWO']
+                }
+            })
+        },
+
+        // 添加聚合图层的新模式,水库点分布
+        mapAddClusterLayer (layerName, imgUrl, positionData, incident = (e) => { }, type = '') {
+            const that = this
+            if (!layersObjcect[layerName]) {
+                layersObjcect[layerName] = new VectorLayer({
+                    // 图标图层
+                    zIndex: 24,
+                    // minZoom: 12,
+                    source: new VectorSource(),
+                })
+                mapView.addLayer(layersObjcect[layerName])
+            }
+
+            positionData.forEach(item => {
+                layersObjcect[layerName].getSource().addFeature(that.getCurItemFeature({
+                    item,
+                    lng: item.longitude,
+                    lat: item.latitude,
+                    text: item.name,
+                    url: imgUrl,
+                    event: incident
+                }))
+            })
+            mapView.getView().animate({ // 只设置需要的属性即可
+                center: [positionData[0].longitude, positionData[0].latitude], // 中心点
+                // zoom: 18, // 缩放级别
+                rotation: undefined, // 缩放完成view视图旋转弧度
+                // duration: 1000 // 缩放持续时间,默认不需要设置
+            })
+        },
+
+        // 生成地图弹窗
+        generateMapPopup (e) {
+            const that = this
+            this.unitData = e
+            this.isShowUnitInfoPopover = true
+            var container = document.getElementById('popup')
+            var closer = document.getElementById('popup-closer')
+
+            // 创建popup
+            unitInfoPopover = new Overlay({
+                element: container,
+                autoPan: true,
+                positioning: 'bottom-center',
+                stopEvent: false,
+                autoPanAnimation: {
+                    duration: 250
+                }
+            })
+            mapView.addOverlay(unitInfoPopover)
+            closer.onclick = function () {
+                unitInfoPopover.setPosition(undefined)
+                closer.blur()
+                return false
+            }
+            unitInfoPopover.setPosition([e.longitude, e.latitude])
+        },
+
+
+    }
+}
+</script>
+
+<style lang='scss' scope>
+.w100 {
+    width: 100%;
+}
+
+.h100 {
+    height: 100%;
+}
+
+.ol-popup {
+    position: absolute;
+    background-color: white;
+    -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
+    filter: drop-shadow(0 1px 4px #FFC125);
+    padding: 15px;
+    border-radius: 10px;
+    border: 1px solid #cccccc;
+    bottom: 34px;
+    left: -46px;
+    min-width: 300px;
+}
+
+.ol-popup:after,
+.ol-popup:before {
+    top: 100%;
+    border: solid transparent;
+    content: " ";
+    height: 0;
+    width: 0;
+    position: absolute;
+    pointer-events: none;
+}
+
+.ol-popup:after {
+    border-top-color: white;
+    border-width: 10px;
+    left: 48px;
+    margin-left: -10px;
+}
+
+.ol-popup:before {
+    border-top-color: #cccccc;
+    border-width: 11px;
+    left: 48px;
+    margin-left: -11px;
+}
+
+.ol-popup-closer {
+    text-decoration: none;
+    position: absolute;
+    top: 2px;
+    right: 8px;
+    color: red;
+}
+
+.ol-popup-closer:after {
+    content: "✖";
+}
+</style>
diff --git a/src/views/dispatch/components/dispatchMap.vue b/src/views/dispatch/components/dispatchMap.vue
index 6d81b3a..3c3317e 100644
--- a/src/views/dispatch/components/dispatchMap.vue
+++ b/src/views/dispatch/components/dispatchMap.vue
@@ -1,15 +1,24 @@
 <template>
-  <div>
-    222
-  </div>
+    <div style="width: 100%; height: 100%;">
+        <OlMapBox ref="olmapboxelement"></OlMapBox>
+    </div>
 </template>
 
 <script>
+import OlMapBox from "./OlMapBox.vue"
+
 export default {
-  name: "dispatchMap"
+    name: "dispatchMap",
+    components: { OlMapBox },
+
+    mounted () {
+        this.$nextTick(() => {
+            this.$refs.olmapboxelement.getAlldata()
+        })
+    }
 }
+
+
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>
diff --git a/src/views/dispatch/dispatchView.vue b/src/views/dispatch/dispatchView.vue
index 10a17d8..e4de296 100644
--- a/src/views/dispatch/dispatchView.vue
+++ b/src/views/dispatch/dispatchView.vue
@@ -1,29 +1,35 @@
 <template>
-  <el-tabs v-model="activeName" >
-    <el-tab-pane label="列表展示" name="list">
-      <dispatch-list></dispatch-list>
-    </el-tab-pane>
-    <el-tab-pane label="地图展示" name="map">
-      <dispatch-map></dispatch-map>
-    </el-tab-pane>
-  </el-tabs>
+    <el-tabs v-model="activeName" style="height: 100%;">
+        <el-tab-pane label="列表展示" name="list">
+            <dispatch-list></dispatch-list>
+        </el-tab-pane>
+        <el-tab-pane label="地图展示" name="map">
+            <dispatch-map :key="new Date().getTime()"></dispatch-map>
+        </el-tab-pane>
+    </el-tabs>
 </template>
 
 <script>
-import DispatchMap from "@/views/dispatch/components/dispatchMap.vue";
-import DispatchList from "@/views/dispatch/dispatch.vue";
+import DispatchMap from "@/views/dispatch/components/dispatchMap.vue"
+import DispatchList from "@/views/dispatch/dispatch.vue"
 
 export default {
-  name: "dispatchView",
-  components: {DispatchList, DispatchMap},
-  data(){
-    return{
-      activeName: 'list'
+    name: "dispatchView",
+    components: { DispatchList, DispatchMap },
+    data () {
+        return {
+            activeName: 'list'
+        }
     }
-  }
 }
 </script>
 
-<style scoped>
+<style lang="scss"scoped>
+::v-deep .el-tabs__content {
+    height: calc(100% - 55px);
+}
 
+::v-deep .el-tab-pane {
+    height: 100%;
+}
 </style>

--
Gitblit v1.9.3