From 1adb6bd1d242cd061cdaf324dc5e7d1cf5a03290 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Mon, 02 Dec 2024 16:59:16 +0800
Subject: [PATCH] 布局及路由相关文件
---
src/pages/map/index.vue | 260 ++++
src/pages/map/components/scomponents/tool/measure.vue | 220 ++++
src/pages/single/index.vue | 223 ++++
src/pages/single/components/mainMenu.vue | 120 ++
src/pages/map/components/mainSearch.vue | 208 +++
src/pages/map/components/mainMenu.vue | 120 ++
src/pages/map/components/scomponents/popup/panorama.vue | 70 +
src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/CoordTransform.js | 178 +++
src/pages/map/components/scomponents/layersControl.vue | 968 +++++++++++++++++
src/pages/map/components/scomponents/baseMap.vue | 359 ++++++
src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/index.js | 53
src/pages/map/components/mainTool.vue | 115 ++
src/pages/map/components/scomponents/tool/exportScene.vue | 10
src/pages/map/components/scomponents/tool/location.vue | 89 +
src/pages/map/components/scomponents/toolList.vue | 134 ++
src/pages/map/components/scomponents/tool/curtain.vue | 108 ++
16 files changed, 3,235 insertions(+), 0 deletions(-)
diff --git a/src/pages/map/components/mainMenu.vue b/src/pages/map/components/mainMenu.vue
new file mode 100644
index 0000000..fad7483
--- /dev/null
+++ b/src/pages/map/components/mainMenu.vue
@@ -0,0 +1,120 @@
+<template>
+ <div class="page-mode">
+ <div @mouseenter="item.childrenFlag = true" :class="{ active: currentUrl.indexOf(item.path) != -1 }"
+ @mouseleave="item.childrenFlag = false" @click="goToPath(item)" v-for="(item, index) in menuList" :key="index">
+ {{ item.menuName }}
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, watch } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
+import { Search } from '@element-plus/icons-vue'
+import { getTime } from '@/utils/getTime.js'
+import { useRouterStore } from 'store/router'
+const store = useRouterStore()
+let router = useRouter()
+let currentUrl = ref('statistics')
+
+const menuList = ref(
+ [
+ {
+ menuName: '园区概况',
+ path: '/layout/map/survey'
+ },
+ {
+ menuName: '风险源',
+ path: '/layout/map/rs'
+ },
+ {
+ menuName: '应急空间',
+ path: '/layout/map/space'
+ },
+ {
+ menuName: '应急物资',
+ path: '/layout/single/supplies'
+ },
+ {
+ menuName: '三级防控',
+ path: '/layout/map/pac'
+ },
+ {
+ menuName: '救援队伍',
+ path: '/layout/single/rt'
+ },
+ {
+ menuName: '突发事件模拟',
+ path: '/layout/map/pd'
+ },
+ {
+ menuName: '作战图',
+ path: '/layout/single/ochart'
+ },
+ ]
+)
+
+const goToPath = (params) => {
+ if (params.children && params.children.length > 0) return
+
+ if (params.path) {
+ if (router.currentRoute.value.path == params.path) return
+ router.push({
+ path: params.path
+ })
+ } else {
+ params.childrenFlag = !params.childrenFlag
+ }
+}
+
+watch(
+ () => router.currentRoute.value,
+ (newValue, oldValue) => {
+
+ currentUrl.value = newValue.path
+
+ },
+ { immediate: true }
+)
+
+const userName = ref('管理员')
+</script>
+
+<style lang="scss" scoped>
+.page-mode {
+ position: absolute;
+ top: auto;
+ bottom: 55px;
+ left: 50%;
+ z-index: 99;
+ transform: translateX(-50%);
+ display: flex;
+ pointer-events: auto;
+
+ &>div {
+ background-image: url(/images/mode-tab.png);
+ background-size: cover;
+ width: 136px;
+ height: 50px;
+ font-size: 16px;
+ text-align: center;
+ font-weight: bold;
+ color: #BFD3E5;
+ line-height: 32px;
+ padding-top: 12px;
+ margin-right: -20px;
+ font-style: italic;
+ cursor: pointer;
+ box-sizing: border-box;
+
+ &:last-child {
+ margin-right: 0px;
+ }
+
+ &.active {
+ color: #F6FCFF;
+ background-image: url(/images/mode-tab-ac.png);
+ }
+ }
+}
+</style>
diff --git a/src/pages/map/components/mainSearch.vue b/src/pages/map/components/mainSearch.vue
new file mode 100644
index 0000000..94808e5
--- /dev/null
+++ b/src/pages/map/components/mainSearch.vue
@@ -0,0 +1,208 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-26 16:09:35
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-11-28 19:25:51
+ * @FilePath: \bigScreen\src\pages\map\components\mainSearch.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <div class="page-search">
+ <el-input placeholder="请输入内容" :suffix-icon="Search" @input="onSearch()" v-model="searchVal"
+ @focus="onFocus"></el-input>
+ <div class="page-search-value-box" v-show="isShowSearchSKValBox">
+ <ul>
+ <li v-if="searchSKValList.length > 0" v-for="(item, index) in searchSKValList" :key="index"
+ @click="sKValItemClick(item)">{{ item.name }}
+ </li>
+ <!-- <li v-else>暂无数据</li> -->
+ <span v-else>{{ showText }}</span>
+ </ul>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { Search } from '@element-plus/icons-vue'
+
+import { fuzzyQuery } from '../../../api/firmInfo/firmInfo'
+
+// 搜索栏相关
+let isShowSearchSKValBox = false
+let searchVal = ref('')
+let searchSKValList = ref([])
+
+let showText = ref('暂无数据')
+
+const onSearch = () => {
+ if (searchVal.value == '') {
+ isShowSearchSKValBox = false
+ // 清空
+ clearPoint()
+ } else {
+ showText.value = '搜索中...'
+ searchSKValList.value = []
+ isShowSearchSKValBox = true
+ getFuzzyQuery()
+ }
+}
+
+function getFuzzyQuery () {
+ fuzzyQuery({
+ name: searchVal.value
+ }).then(res => {
+ if (res.data.data.length > 0) {
+ searchSKValList.value = res.data.data
+ } else {
+ showText.value = '暂无数据'
+ }
+ })
+}
+
+const onFocus = () => {
+ onSearch()
+}
+
+const sKValItemClick = (item) => {
+ isShowSearchSKValBox = false
+ if (item.lat && item.lng) {
+ handleCheckChange(item)
+ } else {
+ console.log('没有经纬度')
+ }
+}
+let addTileLayers = {}
+const handleCheckChange = (item) => {
+ // 先清空,在添加
+ clearPoint()
+ if (!addTileLayers[item.name]) {
+ addTileLayers[item.name] = new DC.HtmlLayer(item.name)
+ window.$viewer.addLayer(addTileLayers[item.name])
+ let iconEl = ''
+ if ('showPanel' in item && item.showPanel == false) {
+ if (item.backgroundIcon) {
+ iconEl = `
+ <div class="map-name">${i[item.showParams] || item.name}</div>
+ <div class="map-icon">
+ <img src="${item.backgroundIcon}">
+ </div>
+ `
+ }
+ } else {
+ iconEl = `<div class="marsBlueGradientPnl">
+ <div>${item.name}</div> </div>`
+ }
+ let divIcon = new DC.DivIcon(
+ new DC.Position(item.lng, item.lat, 0),
+ `<div class="public-map-popup">
+ ${iconEl}
+ </div>`
+ )
+
+ divIcon.attrParams = item
+
+ let incident = () => { }
+
+ if (item.incident) incident = item.incident
+
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+
+ addTileLayers[item.name].addOverlay(divIcon)
+ window.$viewer.flyToPosition(new DC.Position(item.lng, item.lat, 2000, 0, -90, 0))
+
+ } else {
+ window.$viewer.removeLayer(addTileLayers[item.name])
+ addTileLayers[item.name] = null
+ delete addTileLayers[item.name]
+ }
+}
+
+
+function clearPoint () {
+ let arr = Object.keys(addTileLayers)
+ arr.forEach(i => {
+ addTileLayers[i] && window.$viewer && window.$viewer.removeLayer(addTileLayers[i])
+ addTileLayers[i] = null
+ delete addTileLayers[i]
+ })
+}
+
+onUnmounted(() => {
+ let arr = Object.keys(addTileLayers)
+ arr.forEach(i => {
+ addTileLayers[i] && window.$viewer && window.$viewer.removeLayer(addTileLayers[i])
+ addTileLayers[i] = null
+ delete addTileLayers[i]
+ })
+
+ addTileLayers = null
+})
+</script>
+
+<style lang="scss" scoped>
+.page-search {
+ position: absolute;
+ left: 488px;
+ z-index: 99;
+ top: 110px;
+ pointer-events: auto;
+
+ ::v-deep(.el-input) {
+ height: 38px;
+ width: 280px;
+
+ .el-input__wrapper {
+ font-size: 16px;
+ font-weight: 400;
+ border: 1px solid #4081CB;
+ border-radius: 4px;
+ background: rgba(135, 158, 199, 0.3);
+ box-shadow: inset 0px 3px 7px 0px rgba(42, 138, 236, 0.95);
+
+ .el-input__inner {
+ color: #BFD3E5;
+ }
+ }
+ }
+
+ .page-search-value-box {
+ position: absolute;
+ width: 100%;
+ height: 200px;
+ left: 0;
+ top: 40px;
+ background: rgba(135, 158, 199, 0.3);
+ border-radius: 2px;
+ overflow-y: scroll;
+
+ ul>li {
+ color: #ffffff;
+ cursor: pointer;
+ height: 20px;
+ margin: 3px;
+ line-height: 20px;
+ padding-left: 10px;
+ overflow: hidden;
+ }
+
+ ul>li:hover {
+ background-color: #949597;
+ }
+ }
+
+ .page-search-value-box>ul>span {
+ color: #fff;
+ display: flex;
+ justify-content: center;
+ margin-top: 20px;
+ }
+
+
+
+ .page-search-value-box::-webkit-scrollbar {
+ display: none
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/mainTool.vue b/src/pages/map/components/mainTool.vue
new file mode 100644
index 0000000..98ed57a
--- /dev/null
+++ b/src/pages/map/components/mainTool.vue
@@ -0,0 +1,115 @@
+<template>
+ <div class="toolBarRight animation-slide-top no-print-view">
+ <el-button v-for="item, index in btnGroup" :key="index" @click="btnClick(item)"
+ class="btn btn-link toolBarRight-btn">
+ <i :class="item.icon"></i>{{ item.name }}
+ </el-button>
+ </div>
+
+ <base-map v-show="currentComponent == 'map'" @close="closeBox"></base-map>
+ <layers-control :show="currentComponent == 'layers'" @close="closeBox"></layers-control>
+ <tool-list :moreToolShow="moreToolShow" @close="closeBox"></tool-list>
+</template>
+
+<script setup>
+import baseMap from './scomponents/baseMap.vue'
+import layersControl from './scomponents/layersControl.vue'
+import toolList from './scomponents/toolList.vue'
+
+const currentComponent = ref('')
+let moreToolShow = ref(false)
+
+const btnGroup = [
+ {
+ name: '底图',
+ icon: 'fa fa-map',
+ key: 'map',
+ },
+ {
+ name: '图层',
+ icon: 'fa fa-tasks',
+ key: 'layers',
+ },
+ {
+ name: '工具',
+ icon: 'fa fa-cubes',
+ key: 'tool',
+ },
+]
+
+const btnClick = (item) => {
+ if (item.key == 'tool') {
+ moreToolShow.value = !moreToolShow.value
+ return
+ }
+
+ if (currentComponent.value == item.key) {
+ closeBox(item.key)
+ return
+ }
+
+ currentComponent.value = item.key
+}
+
+const closeBox = (type) => {
+ if (type == 'tool') {
+ moreToolShow.value = false
+ } else {
+ currentComponent.value = ''
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.toolBarRight {
+ display: flex;
+ flex-wrap: nowrap;
+ position: absolute;
+ right: 540px;
+ z-index: 99;
+ top: 110px;
+
+ border: 1px solid #4081CB;
+ border-radius: 4px;
+ background: rgba(135, 158, 199, 0.3);
+ box-shadow: inset 0px 3px 7px 0px rgba(42, 138, 236, 0.95);
+ pointer-events: auto;
+
+ ::v-deep(.el-button) {
+ margin-left: 0;
+ border: none;
+ border-radius: 0;
+ background: transparent;
+
+ &.btn {
+ padding: 4px 12px;
+ font-size: 14px;
+ line-height: 1.6;
+ -webkit-transition: border .2s linear, color .2s linear, width .2s linear, background-color .2s linear;
+ -o-transition: border .2s linear, color .2s linear, width .2s linear, background-color .2s linear;
+ transition: border .2s linear, color .2s linear, width .2s linear, background-color .2s linear;
+ }
+
+ &.btn-link {
+ font-weight: 400;
+ color: #007bff;
+ text-decoration: none;
+ }
+
+ &.toolBarRight-btn {
+ list-style-type: none;
+ cursor: pointer;
+ border-right: solid 1px #2b2c2f;
+ color: #edffff;
+ }
+
+ &.toolBarRight-btn:last-child {
+ border-right: none;
+ }
+
+ i {
+ margin-right: 4px;
+ }
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/baseMap.vue b/src/pages/map/components/scomponents/baseMap.vue
new file mode 100644
index 0000000..8828cae
--- /dev/null
+++ b/src/pages/map/components/scomponents/baseMap.vue
@@ -0,0 +1,359 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-28 11:44:45
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-11-25 19:39:24
+ * @FilePath: \bigScreen\src\pages\layout\components\scomponents\baseMap.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <public-box>
+ <template #name>
+ <div class="name"><i class="fa fa-map"></i> 底图</div>
+ </template>
+
+ <template #close>
+ <div class="close cursor-p" @click="$emit('close', 'map')"><i class="fa fa-close"></i></div>
+ </template>
+
+ <template #content>
+ <div class="layers-box-content">
+ <ul class="layers-box">
+ <li :class="{ on: item.mode == curMode }" v-for="item, index in baseMaps" :key="index"
+ @click="loadLAYER(item.mode, index)">
+ <div><img :src="item.src"></div>
+ <div>{{ item.name }}</div>
+ </li>
+ </ul>
+ </div>
+
+ <div class="show-terrain" style="margin-left:10px;color:#fff">
+ <el-checkbox @change="terrainChange" v-model="showTerrainFlag" label="显示地形" size="large" />
+ </div>
+ </template>
+ </public-box>
+</template>
+
+<script setup>
+import { getAssetsFile } from 'utils/utils'
+import AmapMercatorTilingScheme from './cesium/AmapMercatorTilingScheme/index'
+
+const { appContext } = getCurrentInstance()
+const global = appContext.config.globalProperties
+
+const cesiumToken =
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYTZlNGNlYS01NTU1LTQ1MGEtYmNlZS0yNTE2NDk5YWM2MjEiLCJpZCI6MTc5Njk2LCJpYXQiOjE3MDA1NDcwMjV9.qcl4AH2731cfFd0-I1ZLUINPXqvglLkDFD-UGR2zU5M'
+window.$Cesium.Ion.defaultAccessToken = cesiumToken
+
+const TDT_Token = 'c6eea7dad4fa1e2d1e32ec0e7c9735db'
+// 天地图Key
+// 天地图地图
+const TDT_IMG_C = 'https://{s}.tianditu.gov.cn/img_c/wmts?service=wmts&request=GetTile&version=1.0.0' +
+ '&LAYER=img&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
+ '&style=default&format=tiles&tk=' + TDT_Token
+// 天地图注记
+const TDT_ZJ = 'https://{s}.tianditu.gov.cn/cia_c/wmts?service=wmts&request=GetTile&version=1.0.0' +
+ '&LAYER=cia&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
+ '&style=default&format=tiles&tk=' + TDT_Token
+// 标准地图注记
+const TID_STAND = 'https://{s}.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0' +
+ '&LAYER=img&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
+ '&style=default&format=tiles&tk=' + TDT_Token
+
+const imageryProvider_standZh = new window.$Cesium.UrlTemplateImageryProvider({
+ url: 'https://t{s}.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+ subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+ maximumLevel: 18,
+ credit: 'stand_zj',
+})
+
+const imageryProvider_stand = new window.$Cesium.UrlTemplateImageryProvider({
+ url: 'https://t{s}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+ subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+ // format: 'image/jpeg',
+ // show: true,
+ maximumLevel: 18,
+ credit: 'stand_tc',
+})
+
+const annotation = new window.$Cesium.WebMapTileServiceImageryProvider({
+ url: TDT_ZJ,
+ layer: 'tdtZwImg_c',
+ style: 'default',
+ format: 'tiles',
+ tileMatrixSetID: 'c',
+ subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
+ tilingScheme: new window.$Cesium.GeographicTilingScheme(),
+ tileMatrixLabels: [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ '13',
+ '14',
+ '15',
+ '16',
+ '17',
+ '18',
+ '19',
+ ],
+ maximumLevel: 50,
+})
+
+const imageryProvider_tdt = new window.$Cesium.WebMapTileServiceImageryProvider({
+ url: TDT_IMG_C,
+ layer: 'tdtImg_c',
+ style: 'default',
+ format: 'tiles',
+ tileMatrixSetID: 'c',
+ subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
+ tilingScheme: new window.$Cesium.GeographicTilingScheme(),
+ tileMatrixLabels: [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ '13',
+ '14',
+ '15',
+ '16',
+ '17',
+ '18',
+ '19',
+ ],
+ maximumLevel: 17,
+})
+
+const imageryProvider_ammapSL = new window.$Cesium.UrlTemplateImageryProvider({
+ url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
+ layer: 'tdtVecBasicLayer',
+ style: 'default',
+ format: 'image/png',
+ tileMatrixSetID: 'GoogleMapsCompatible',
+ subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+ maximumLevel: 18,
+ tilingScheme: new AmapMercatorTilingScheme(),
+ credit: 'amap_SL',
+})
+
+const imageryProvider_ammap = new window.$Cesium.UrlTemplateImageryProvider({
+ url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
+ layer: 'tdtVecBasicLayer',
+ style: 'default',
+ format: 'image/png',
+ tileMatrixSetID: 'GoogleMapsCompatible',
+ subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+ maximumLevel: 18,
+ tilingScheme: new AmapMercatorTilingScheme(),
+ credit: 'amap_stand',
+})
+
+const imageryProvider_ammapBz = new window.$Cesium.UrlTemplateImageryProvider({
+ url: 'https://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8',
+ tilingScheme: new AmapMercatorTilingScheme(),
+ minimumLevel: 3,
+})
+
+let mapLayers = [
+ {
+ src: getAssetsFile('stand.png'),
+ mode: '0',
+ name: '天地图矢量',
+ layers: [
+ { key: 'imageryProvider_standZh', layer: imageryProvider_standZh },
+ { key: 'imageryProvider_stand', layer: imageryProvider_stand },
+ ]
+ },
+ {
+ src: getAssetsFile('satellite.png'),
+ mode: '1',
+ name: '天地图影像',
+ layers: [
+ { key: 'annotation', layer: annotation },
+ {
+ key: 'imageryProvider_tdt',
+ layer: imageryProvider_tdt,
+ }
+ ]
+ },
+ {
+ src: getAssetsFile('stand.png'),
+ mode: '2',
+ name: '高德矢量',
+ layers: [
+ {
+ key: 'imageryProvider_ammapSL',
+ layer: imageryProvider_ammapSL,
+ }
+ ]
+ },
+ {
+ src: getAssetsFile('satellite.png'),
+ mode: '3',
+ name: '高德影像',
+ layers: [
+ { key: 'imageryProvider_ammapBz', layer: imageryProvider_ammapBz },
+ { key: 'imageryProvider_ammap', layer: imageryProvider_ammap },
+ ]
+ }
+]
+
+let curMode = ref(null)
+let baseMaps = reactive([])
+
+baseMaps = mapLayers.map(item => {
+ return {
+ src: item.src,
+ mode: item.mode,
+ name: item.name,
+ }
+})
+
+let globalBaseMapLayers = []
+
+const loadLAYER = (mode, ind, cb = () => { }) => {
+ if (mode == curMode.value) return
+
+ let curmapLayers = []
+
+ globalBaseMapLayers.length &&
+ globalBaseMapLayers.forEach((item) => {
+ item.mapLayer.show = false
+ })
+
+ curmapLayers.push(
+ ...mapLayers[ind].layers,
+ )
+
+ // 创建一个Set来快速查找array2中的id
+ let keyBaseMap = new Set(globalBaseMapLayers.map((item) => item.key))
+ let keyMapLayers = new Set(curmapLayers.map((item) => item.key))
+
+ let keyExistBaseMap = curmapLayers.filter((item) => !keyBaseMap.has(item.key))
+
+ let keyNoExistBaseMap = globalBaseMapLayers.filter((item) =>
+ keyMapLayers.has(item.key),
+ )
+
+ keyExistBaseMap.length &&
+ keyExistBaseMap.forEach((item) => {
+ let curLayer = {
+ key: item.key,
+ mapLayer: window.$viewer?.imageryLayers.addImageryProvider(item.layer),
+ }
+
+ curLayer.mapLayer.show = true
+ window.$viewer?.imageryLayers.lowerToBottom(curLayer.mapLayer)
+
+ globalBaseMapLayers.push(curLayer)
+ })
+
+ keyNoExistBaseMap.length &&
+ keyNoExistBaseMap.forEach((item) => {
+ item.mapLayer.show = true
+ window.$viewer?.imageryLayers.lowerToBottom(item.mapLayer)
+ })
+
+ curMode.value = mode
+
+}
+setTimeout(() => {
+ loadLAYER(1, 1)
+}, 0)
+
+const showTerrainFlag = ref(true)
+
+const terrainChange = (e) => {
+ if (e) {
+ let terrain = DC.TerrainFactory.createTerrain(DC.TerrainType.XYZ, {
+ url: 'https://data.mars3d.cn/terrain'
+ })
+ window.$viewer.setTerrain(terrain)
+ } else {
+ window.$viewer.setTerrain()
+ }
+}
+
+terrainChange(true)
+</script>
+
+<style lang="scss" scoped>
+.close {
+ cursor: pointer;
+}
+
+.layers-box-content {
+ .layers-box {
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ width: 354px;
+ padding: 0 10px;
+ box-sizing: border-box;
+
+ li {
+ margin-top: 10px;
+ cursor: pointer;
+
+ &.on,
+ &:hover {
+ div:first-child {
+ border: solid 2px #337fe5;
+ }
+
+ div:last-child {
+ color: #337fe5;
+ }
+ }
+
+ div:first-child {
+ width: 76px;
+ height: 76px;
+ background: red;
+ border: 2px solid white;
+ box-sizing: border-box;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ div:last-child {
+ width: 76px;
+ height: 20px;
+ line-height: 20px;
+ color: #fff;
+ font-size: 12px;
+ text-align: center;
+ }
+ }
+ }
+}
+
+.show-terrain {
+ ::v-deep(.el-checkbox) {
+ .el-checkbox__label {
+ color: #fff;
+ }
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/CoordTransform.js b/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/CoordTransform.js
new file mode 100644
index 0000000..5b1b4a5
--- /dev/null
+++ b/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/CoordTransform.js
@@ -0,0 +1,178 @@
+// 定义一些常量
+const BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0;
+const PI = 3.1415926535897932384626;
+const RADIUS = 6378245.0;
+const EE = 0.00669342162296594323;
+
+class CoordTransform {
+ /**
+ * BD-09(百度坐标系) To GCJ-02(火星坐标系)
+ * @param lng
+ * @param lat
+ * @returns {number[]}
+ */
+ static BD09ToGCJ02(lng, lat) {
+ let x = +lng - 0.0065;
+ let y = +lat - 0.006;
+ let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * BD_FACTOR);
+ let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * BD_FACTOR);
+ let gg_lng = z * Math.cos(theta);
+ let gg_lat = z * Math.sin(theta);
+ return [gg_lng, gg_lat];
+ }
+
+ /**
+ * GCJ-02(火星坐标系) To BD-09(百度坐标系)
+ * @param lng
+ * @param lat
+ * @returns {number[]}
+ * @constructor
+ */
+ static GCJ02ToBD09(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ let z =
+ Math.sqrt(lng * lng + lat * lat) +
+ 0.00002 * Math.sin(lat * BD_FACTOR);
+ let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * BD_FACTOR);
+ let bd_lng = z * Math.cos(theta) + 0.0065;
+ let bd_lat = z * Math.sin(theta) + 0.006;
+ return [bd_lng, bd_lat];
+ }
+
+ /**
+ * WGS-84(世界大地坐标系) To GCJ-02(火星坐标系)
+ * @param lng
+ * @param lat
+ * @returns {number[]}
+ */
+ static WGS84ToGCJ02(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ if (this.out_of_china(lng, lat)) {
+ return [lng, lat];
+ } else {
+ let d = this.delta(lng, lat);
+ return [lng + d[0], lat + d[1]];
+ }
+ }
+
+ /**
+ * GCJ-02(火星坐标系) To WGS-84(世界大地坐标系)
+ * @param lng
+ * @param lat
+ * @returns {number[]}
+ * @constructor
+ */
+ static GCJ02ToWGS84(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ if (this.out_of_china(lng, lat)) {
+ return [lng, lat];
+ } else {
+ let d = this.delta(lng, lat);
+ let mgLng = lng + d[0];
+ let mgLat = lat + d[1];
+ return [lng * 2 - mgLng, lat * 2 - mgLat];
+ }
+ }
+
+ /**
+ *
+ * @param lng
+ * @param lat
+ * @returns {number[]}
+ */
+ static delta(lng, lat) {
+ let dLng = this.transformLng(lng - 105, lat - 35);
+ let dLat = this.transformLat(lng - 105, lat - 35);
+ const radLat = (lat / 180) * PI;
+ let magic = Math.sin(radLat);
+ magic = 1 - EE * magic * magic;
+ const sqrtMagic = Math.sqrt(magic);
+ dLng = (dLng * 180) / ((RADIUS / sqrtMagic) * Math.cos(radLat) * PI);
+ dLat =
+ (dLat * 180) / (((RADIUS * (1 - EE)) / (magic * sqrtMagic)) * PI);
+ return [dLng, dLat];
+ }
+
+ /**
+ *
+ * @param lng
+ * @param lat
+ * @returns {number}
+ */
+ static transformLng(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ let 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;
+ }
+
+ /**
+ *
+ * @param lng
+ * @param lat
+ * @returns {number}
+ */
+ static transformLat(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ let 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;
+ }
+
+ /**
+ * 判断是否在国内。不在国内不做偏移
+ * @param lng
+ * @param lat
+ * @returns {boolean}
+ */
+ static out_of_china(lng, lat) {
+ lat = +lat;
+ lng = +lng;
+ return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
+ }
+}
+
+export default CoordTransform;
diff --git a/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/index.js b/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/index.js
new file mode 100644
index 0000000..7806256
--- /dev/null
+++ b/src/pages/map/components/scomponents/cesium/AmapMercatorTilingScheme/index.js
@@ -0,0 +1,53 @@
+/*
+ * @Author: GuLiMmo 2820890765@qq.com
+ * @Date: 2024-05-11 09:18:29
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-11-27 11:19:55
+ * @FilePath: \bigScreen\src\pages\layout\components\scomponents\cesium\AmapMercatorTilingScheme\index.js
+ * @Description: 高德地图纠偏
+ * Copyright (c) 2024 by GuLiMmo, All Rights Reserved.
+ */
+const {
+ WebMercatorProjection,
+ WebMercatorTilingScheme,
+ Math,
+ Cartographic,
+ Cartesian2,
+} = DC.__namespace.Cesium
+// window.DC.getLib('Cesium')
+import CoordTransform from './CoordTransform'
+class AmapMercatorTilingScheme extends WebMercatorTilingScheme {
+ constructor() {
+ super()
+
+ let projection = new WebMercatorProjection()
+
+ this._projection.project = function (cartographic, result) {
+ result = CoordTransform.WGS84ToGCJ02(
+ Math.toDegrees(cartographic.longitude),
+ Math.toDegrees(cartographic.latitude),
+ )
+ result = projection.project(
+ new Cartographic(
+ Math.toRadians(result[0]),
+ Math.toRadians(result[1]),
+ ),
+ )
+ return new Cartesian2(result.x, result.y)
+ }
+
+ this._projection.unproject = function (cartesian, result) {
+ let cartographic = projection.unproject(cartesian)
+ result = CoordTransform.GCJ02ToWGS84(
+ Math.toDegrees(cartographic.longitude),
+ Math.toDegrees(cartographic.latitude),
+ )
+ return new Cartographic(
+ Math.toRadians(result[0]),
+ Math.toRadians(result[1]),
+ )
+ }
+ }
+}
+
+export default AmapMercatorTilingScheme
diff --git a/src/pages/map/components/scomponents/layersControl.vue b/src/pages/map/components/scomponents/layersControl.vue
new file mode 100644
index 0000000..8857e66
--- /dev/null
+++ b/src/pages/map/components/scomponents/layersControl.vue
@@ -0,0 +1,968 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-31 10:47:29
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-12-01 21:45:13
+ * @FilePath: \bigScreen\src\pages\map\components\scomponents\layersControl.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <public-box v-show="showLayerControl">
+ <template #name>
+ <div class="name"><i class="fa fa-tasks"></i> 图层</div>
+ </template>
+
+ <template #close>
+ <div class="close cursor-p" @click="emit('close', 'layers')"><i class="fa fa-close"></i></div>
+ </template>
+
+ <template #content>
+ <div class="tree-content">
+ <el-tree ref="treeRef" :data="data" draggable="" show-checkbox node-key="id" default-expand-all
+ :default-checked-keys="indexPoint" :props="defaultProps" :indent="treeProps['indent']"
+ @check="handleCheckChange">
+ <template v-slot:default="{ node }">
+ <element-tree-line :node="node" :showLabelLine="treeProps['showLabelLine']" :indent="treeProps['indent']">
+ <!-- 自定义label的slot -->
+ <template v-slot:node-label>
+ <span style="font-size: 12px">
+ {{ node.label }}
+ <i class="el-icon-eleme"></i></span>
+ </template>
+ <!-- 在右边追加内容的slot -->
+ <!-- <template v-slot:after-node-label>
+ <span style="padding-right: 10px">
+ <el-button type="primary" size="mini" @click.stop="openDrawer(node)">新增子节点</el-button>
+ <el-button type="primary" size="mini" @click.stop="openDrawer(node)">修改</el-button>
+ <el-button type="danger" size="mini" @click.stop="openDialog">删除</el-button></span>
+ </template> -->
+ </element-tree-line>
+ </template>
+ </el-tree>
+ </div>
+ </template>
+ </public-box>
+
+ <panorama v-show="panoramaShow" :title="panoramaTitle" :url="panoramaUrl" @closePanoramaPopup="closePanoramaPopup">
+ </panorama>
+</template>
+
+<script setup>
+let addPupoLayers = {}
+let addTileLayers = {}
+let tileLayers = new DC.TilesetLayer('tileLayers')
+window.$viewer.addLayer(tileLayers)
+
+const {
+ show: showLayerControl
+} = defineProps({
+ show: {
+ default: false
+ }
+})
+
+const emit = defineEmits(['close'])
+import panorama from './popup/panorama.vue'
+import { getPage } from '@/api/indParkInfo'
+import { getPage as getfirmPage } from '@/api/firmInfo/firmInfo'
+import { getList, getGouQu } from "@/api/space/space"
+import { getList as getRiskList } from "@/api/riskSource/riskSource"
+import { getPanoramaList } from "@/api/panorama/"
+import yqfw from "@/assets/json/yqfw"
+import gsgw from "@/assets/json/gsgw"
+import rqgw from "@/assets/json/rqgw"
+import wsgw from "@/assets/json/wsgw"
+import ysgw from "@/assets/json/ysgw"
+import { onUnmounted } from 'vue'
+import EventBus from 'utils/bus'
+import { usePointStore } from 'store/usepoint'
+const pointStore = usePointStore()
+
+const { VITE_APP_BASE } = import.meta.env
+// , '7',
+let indexPoint = ref(['1', '5'])
+
+const treeRef = ref(null)
+
+const treeProps = {
+ indent: 16,
+ showLabelLine: true,
+}
+
+// 全景相关
+const panoramaShow = ref(false)
+const panoramaTitle = ref('')
+const panoramaUrl = ref('')
+const closePanoramaPopup = () => {
+ panoramaShow.value = false
+}
+
+const data = [
+ {
+ id: '1',
+ label: '园区倾斜摄影',
+ type: 'layer',
+ subType: '3Dtile',
+ urlData: [
+
+ ],
+ layerName: 'hgyq'
+ },
+
+ {
+ id: '2',
+ label: '企业分布',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getPage,
+ params: {
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/qy.png',
+ className: 'qyfb-box',
+ showPanel: false,
+ layerName: 'qyfb'
+ },
+
+ {
+ id: '3',
+ label: '应急空间',
+ children: [
+ {
+ id: '3-1',
+ label: '应急池',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 1,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/yjc.png',
+ className: 'yjc-box',
+ showPanel: false,
+ layerName: 'yjc',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ if (!attrParams.imageUrl) {
+ return
+ }
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <div>${attrParams.fullName}</div>
+ <img src="${attrParams.imageUrl}" />
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-two">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+ {
+ id: '3-2',
+ label: '阀门',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 2,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/ysf.png',
+ className: 'ysf-box',
+ showPanel: false,
+ layerName: 'fm',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ if (!attrParams.imageUrl) {
+ return
+ }
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <div>${attrParams.fullName}</div>
+ <img src="${attrParams.imageUrl}" width="160" height="160" />
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-two">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+
+ {
+ id: '3-3',
+ label: '公共管网',
+ children: [
+ // 给水管网、污水管网、燃气管网、雨水管网
+ {
+ id: '3-3-1',
+ label: '给水管网',
+ type: 'layer',
+ subType: 'geojsonPipe',
+ layerName: 'gsgw',
+ source: gsgw,
+ color: DC.Color.BLUE.withAlpha(0.9),
+ height: 65,
+ },
+ {
+ id: '3-3-2',
+ label: '污水管网',
+ type: 'layer',
+ subType: 'geojsonPipe',
+ layerName: 'wsgw',
+ source: wsgw,
+ color: DC.Color.DARKBLUE.withAlpha(0.9),
+ height: 68,
+ },
+ {
+ id: '3-3-3',
+ label: '燃气管网',
+ type: 'layer',
+ subType: 'geojsonPipe',
+ layerName: 'rqgw',
+ source: rqgw,
+ color: DC.Color.RED.withAlpha(0.9),
+ height: 71,
+ },
+ {
+ id: '3-3-4',
+ label: '雨水管网',
+ type: 'layer',
+ subType: 'geojsonPipe',
+ layerName: 'ysgw',
+ source: ysgw,
+ color: DC.Color.CYAN.withAlpha(0.9),
+ height: 75,
+ },
+ ]
+ },
+
+ {
+ id: '3-4',
+ label: '污水提升泵站',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 4,
+ size: 1000
+ },
+ layerName: 'wstsbz',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ if (!attrParams.imageUrl) {
+ return
+ }
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <div>${attrParams.fullName}</div>
+ <img src="${attrParams.imageUrl}" width="160" height="160" />
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-two">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+
+ {
+ id: '3-5',
+ label: '水库',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 5,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/sk.png',
+ className: 'sk-box',
+ showPanel: false,
+ layerName: 'sk',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ if (!attrParams.imageUrl) {
+ return
+ }
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <div>${attrParams.fullName}</div>
+ <img src="${attrParams.imageUrl}" width="160" height="160" />
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-two">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+
+ {
+ id: '3-6',
+ label: '应急泵',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 6,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/yjb.png',
+ className: 'yjb-box',
+ showPanel: false,
+ layerName: 'yjb',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ if (!attrParams.imageUrl) {
+ return
+ }
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <div>${attrParams.fullName}</div>
+ <img src="${attrParams.imageUrl}" width="160" height="160" />
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-two">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+
+ {
+ id: '3-8',
+ label: '沟渠',
+ type: 'layer',
+ subType: 'geojsonPolygon',
+ method: getGouQu,
+ params: {
+ type: 8,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/gouqu.png',
+ className: 'xfs-box',
+ showPanel: false,
+ layerName: 'gouqu'
+ },
+ {
+ id: '3-9',
+ label: '废水处理站',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 9,
+ size: 1000
+ // name: '吉水县绿源污水处理厂',
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/wsclc.png',
+ className: 'xfs-box',
+ showPanel: false,
+ layerName: 'fsclz'
+ },
+ {
+ id: '3-10',
+ label: '排水口',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 10,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/psk.png',
+ className: 'xfs-box',
+ showPanel: false,
+ layerName: 'psk'
+ },
+ {
+ id: '3-11',
+ label: '污水池',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getList,
+ params: {
+ type: 11,
+ size: 1000
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/wsc.png',
+ className: 'xfs-box',
+ showPanel: false,
+ layerName: 'wsc'
+ }
+ ]
+ },
+
+ {
+ id: '4',
+ label: '风险源',
+ children: [
+ {
+ id: '4-1',
+ label: '一般',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getRiskList,
+ params: {
+ riskLevel: 1,
+ size: 1000
+ },
+ showParams: 'category',
+ className: 'fxy-ordinary',
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/fxy.png',
+ showPanel: false,
+ layerName: 'fxyOrdinary',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <li>${attrParams.firmName || ''}</li>
+ <li>${attrParams.riskLevelName || ''}</li>
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-three">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ },
+ {
+ id: '4-2',
+ label: '较大',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getRiskList,
+ params: {
+ riskLevel: 2,
+ size: 1000
+ },
+ showParams: 'category',
+ className: 'fxy-larger',
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/fxy.png',
+ showPanel: false,
+ layerName: 'fxyLarger',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ // 删除
+ destroy()
+ addPupoLayers[attrParams.name] = new DC.HtmlLayer(attrParams.name)
+ window.$viewer.addLayer(addPupoLayers[attrParams.name])
+ let iconEl = `<div class="marsBlueGradientPnl">
+ <li>${attrParams.firmName || ''}</li>
+ <li>${attrParams.riskLevelName || ''}</li>
+ </div>`
+ let divIcon = new DC.DivIcon(
+ new DC.Position(attrParams.lng, attrParams.lat, 64),
+ `<div class="public-map-popup-three">
+ ${iconEl}
+ </div>`
+ )
+ let incident = () => {
+ destroy()
+ }
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+ addPupoLayers[attrParams.name].addOverlay(divIcon)
+ }
+ }
+ ]
+ },
+
+ {
+ id: '5',
+ label: '园区范围',
+ type: 'layer',
+ subType: 'geojsonWall',
+ layerName: 'yqfw',
+ source: yqfw
+ },
+
+ {
+ id: '7',
+ label: '空中全景分布',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getPanoramaList,
+ params: {
+ size: 1000,
+ remark: '1'
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/qj.png',
+ showPanel: false,
+ layerName: 'kzqjdwfb',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ panoramaTitle.value = attrParams.name
+ if (
+ attrParams.url.indexOf("http://vr.jxpskj.com:180") != -1
+ ) {
+ attrParams.url = attrParams.url.replace(
+ "http://vr.jxpskj.com:180",
+ "/panorama"
+ )
+ }
+ panoramaUrl.value = attrParams.url
+ panoramaShow.value = true
+ }
+ },
+ {
+ id: '8',
+ label: '地面全景分布',
+ type: 'layer',
+ subType: 'labelPoint',
+ method: getPanoramaList,
+ params: {
+ size: 1000,
+ remark: '2'
+ },
+ backgroundIcon: VITE_APP_BASE + 'img/mapicon/qj.png',
+ showPanel: false,
+ layerName: 'dtqjdwfb',
+ incident: (e) => {
+ const { attrParams } = e.overlay
+ panoramaTitle.value = attrParams.name
+ if (
+ attrParams.url.indexOf("http://vr.jxpskj.com:180") != -1
+ ) {
+ attrParams.url = attrParams.url.replace(
+ "http://vr.jxpskj.com:180",
+ "/panorama"
+ )
+ }
+ panoramaUrl.value = attrParams.url
+ panoramaShow.value = true
+ }
+ },
+]
+
+// let modellayer = new DC.VectorLayer("modellayer").addTo(window.$viewer)
+// let model = new DC.Model("121.46748793889597,31.22345700031846,200", VITE_APP_BASE + 'gltf/dajiang.gltf')
+// model.setStyle({
+// scale: 10000
+// })
+// modellayer.addOverlay(model)
+// window.$viewer.flyToPosition("121.46748793889597,31.22345700031846,300,0,-90")
+
+const defaultProps = {
+ children: 'children',
+ label: 'label',
+}
+
+const checkType = (value) => {
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
+ return 'obj'
+ } else if (Array.isArray(value)) {
+ return 'arr'
+ }
+}
+// 用于存储收集到的节点的数组
+const collectedNodes = reactive([])
+
+// 递归函数,收集所有 flag 为 true 的子节点
+const collectNodesWithFlag = (nodes) => {
+ if (checkType(nodes) == 'obj') {
+ if (nodes.type == 'layer') {
+ collectedNodes.value.push(nodes)
+ }
+ if (nodes.children && nodes.children.length > 0) {
+ collectNodesWithFlag(nodes.children)
+ return
+ }
+ }
+
+ if (checkType(nodes) == 'arr') {
+ nodes.forEach(item => {
+ if (item) {
+ if (item.type == 'layer') {
+ collectedNodes.value.push(item)
+ }
+
+ if (item.children && item.children.length > 0) {
+ collectNodesWithFlag(item.children)
+ }
+ }
+ })
+ }
+}
+
+const handleCheckChange = (data) => {
+ let options = treeRef.value?.getCheckedNodes()
+ collectedNodes.value = []
+ collectNodesWithFlag(data)
+
+ collectedNodes.value.forEach(item => {
+ if (options?.some(i => i.id == item.id)) {
+
+ // const window.$Cesium = DC
+ if (item.subType == '3Dtile') {
+ if (!addTileLayers[item.layerName]) {
+ // addTileLayers[item.layerName] = []
+ // let tile = window.$viewer.delegate.scene.primitives.add(new window.$Cesium.Cesium3DTileset({
+ // url: '/zhyq/mx/tile_01/tileset.json',
+ // }))
+
+ // url: '/zhyq/mx/tile_01/tileset.json',
+ // }), 121323)
+ // item.urlData.forEach(i => {
+
+ // })
+ addTileLayers[item.layerName] = []
+ item.urlData.forEach((m, ind) => {
+ let tile = new DC.Tileset(m.url, {
+ maximumMemoryUsage: 1024,
+ maximumScreenSpaceError: 8,
+ skipLevels: 5,
+ skipLevelOfDetail: true,
+ skipScreenSpaceErrorFactor: 128,
+ progressiveResolutionHeightFraction: 0.5,
+ baseScreenSpaceError: 1024
+ })
+ tile.setSplitDirection(1)
+ // tile.setHeight(-420)
+ // tile.setSplitDirection(-1)
+ window.$viewer.sceneSplit.addTileset(tile)
+ tileLayers.addOverlay(tile)
+ window.$viewer.sceneSplit.enable = false
+ addTileLayers[item.layerName][ind] = tile
+ })
+ } else {
+ addTileLayers[item.layerName].forEach(m => m.show = true)
+ }
+ } else if (item.subType == 'labelPoint') {
+ if (!addTileLayers[item.layerName]) {
+ addTileLayers[item.layerName] = new DC.HtmlLayer(item.layerName)
+ window.$viewer.addLayer(addTileLayers[item.layerName])
+
+ item.method(item.params).then(res => {
+ let data = res.data.data.records
+
+ data.filter(i => i.lng && i.lng != '' && i.lat && i.lat != '').forEach(i => {
+ let iconEl = ''
+
+ if ('showPanel' in item && item.showPanel == false) {
+ if (item.backgroundIcon) {
+ iconEl = `
+ <div class="map-name">${i[item.showParams] || i.name}</div>
+ <div class="map-icon">
+ <img src="${item.backgroundIcon}">
+ </div>
+ `
+ }
+ } else {
+ iconEl = `<div class="marsBlueGradientPnl">
+ <div>${i[item.showParams] || i.name}</div>
+ </div>`
+ }
+
+ let divIcon = new DC.DivIcon(
+ new DC.Position(i.lng, i.lat, 64),
+ `<div class="public-map-popup ${item.className || ''}">
+ ${iconEl}
+ </div>`
+ )
+
+ divIcon.attrParams = i
+
+ let incident = () => {
+ }
+
+ if (item.incident) incident = item.incident
+
+ divIcon.on(DC.MouseEventType.CLICK, incident)
+
+ addTileLayers[item.layerName].addOverlay(divIcon)
+ })
+ })
+ } else {
+ addTileLayers[item.layerName].show = true
+ }
+ } else if (item.subType == 'geojsonWall') {
+ if (!addTileLayers[item.layerName]) {
+ addTileLayers[item.layerName] = new DC.VectorLayer(item.layerName)
+ window.$viewer.addLayer(addTileLayers[item.layerName])
+
+ item.source.features.forEach(i => {
+ let wall = new DC.Wall(
+ i.geometry.coordinates[0].map(d => [...d, 125].join(',')).join(';')
+ )
+
+ wall.setStyle({
+ material: new DC.WallTrailMaterialProperty({
+ color: window.$Cesium.Color.fromBytes(0, 123, 255, 180),
+ speed: 8
+ })
+ })
+ addTileLayers[item.layerName].addOverlay(wall)
+ })
+ } else {
+ addTileLayers[item.layerName].show = true
+ }
+ } else if (item.subType == 'geojsonPipe') {
+ if (!addTileLayers[item.layerName]) {
+ addTileLayers[item.layerName] = new DC.VectorLayer(item.layerName)
+ window.$viewer.addLayer(addTileLayers[item.layerName])
+
+ function computeCircle (radius) {
+ var positions = []
+ for (var i = 0; i < 360; i++) {
+ var radians = DC.Math.toRadians(i)
+ positions.push({
+ x: radius * Math.cos(radians),
+ y: radius * Math.sin(radians),
+ })
+ }
+ return positions
+ }
+
+ item.source.features.forEach(i => {
+ let polylineVolume = new DC.PolylineVolume(
+ i.geometry.coordinates.map(d => [d[0], d[1], item.height].join(',')).join(';'),
+ computeCircle(2)
+ )
+
+ polylineVolume.setStyle({
+ material: item.color
+ })
+ addTileLayers[item.layerName].addOverlay(polylineVolume)
+ })
+ } else {
+ addTileLayers[item.layerName].show = true
+ }
+ } else if (item.subType == 'geojsonPolygon') {
+ if (!addTileLayers[item.layerName]) {
+ addTileLayers[item.layerName] = new DC.VectorLayer(item.layerName)
+ window.$viewer.addLayer(addTileLayers[item.layerName])
+ item.method(item.params).then(res => {
+ let data = res.data.data.records
+ data.forEach(i => {
+ let stl = ''
+ try {
+ let geom = JSON.parse(i.geom)
+ if (geom && geom.coordinates && geom.coordinates[0]) {
+ stl = geom.coordinates[0][0].map(d => d[0] + ',' + d[1]).join(';')
+ } else {
+ console.error('Invalid geom structure')
+ }
+ } catch (error) {
+ console.error('Failed to parse geom:', error)
+ }
+ let polygon = new DC.Polygon(stl)
+ polygon.setStyle({
+ width: 2,
+ material: DC.Color.BLUE,
+ clampToGround: true
+ })
+ addTileLayers[item.layerName].addOverlay(polygon)
+ })
+ })
+ } else {
+ addTileLayers[item.layerName].show = true
+ }
+ }
+ } else {
+ if (addTileLayers[item.layerName]) {
+ if (item.subType == '3Dtile') {
+ addTileLayers[item.layerName].forEach(m => m.show = false)
+ } else {
+ addTileLayers[item.layerName].clear()
+ window.$viewer && window.$viewer.removeLayer(addTileLayers[item.layerName])
+ addTileLayers[item.layerName] = null
+ delete addTileLayers[item.layerName]
+ }
+ }
+ }
+ })
+}
+
+function findObjectById (data, id) {
+ // 遍历数据数组
+ for (let i = 0; i < data.length; i++) {
+ const item = data[i]
+
+ // 检查当前项的 id 是否匹配
+ if (item.id === id) {
+ return item // 找到匹配项,返回它
+ }
+
+ // 如果当前项有 children 数组,则递归查找
+ if (item.children && item.children.length > 0) {
+ const found = findObjectById(item.children, id)
+ if (found) {
+ return found // 在 children 中找到匹配项,返回它
+ }
+ }
+ }
+
+ // 如果没有找到匹配项,返回 null
+ return null
+}
+
+const restHandleCheckChange = (key) => {
+ let checkIds = treeRef.value?.getCheckedKeys()
+
+ if (checkIds && checkIds.some(i => i == key)) {
+ return
+ }
+
+ treeRef.value?.setCheckedKeys([...checkIds, key])
+ handleCheckChange([findObjectById(data, key)])
+}
+
+const restHandleDelChange = (key) => {
+ let checkIds = treeRef.value?.getCheckedKeys()
+
+ if (checkIds && !checkIds.some(i => i == key)) {
+ return
+ }
+
+ treeRef.value?.setCheckedKeys(checkIds.filter(i => i.indexOf(key)))
+ handleCheckChange([findObjectById(data, key)])
+}
+
+// 飞到园区范围
+const flyToyqfw = () => {
+ window.$viewer.zoomToPosition(new DC.Position(
+ 115.1021,
+ 27.2360,
+ 5000,
+ 0,
+ -45,
+ 0
+ ), () => {
+ })
+}
+
+EventBus.on('restHandleCheckChange', restHandleCheckChange)
+EventBus.on('restHandleDelChange', restHandleDelChange)
+EventBus.on('flyToyqfw', flyToyqfw)
+
+onMounted(() => {
+ setTimeout(() => {
+ handleCheckChange(data.filter(i => indexPoint.value.includes(i.id)))
+ }, 3000)
+})
+
+// const sharedData = computed(() => pointStore.sharedData);
+// watch(sharedData, (newValue) => {
+// });
+
+// 销毁
+function destroy () {
+ let arr = Object.keys(addPupoLayers)
+ arr.filter(i => i != 'hgyq').forEach(i => {
+ addPupoLayers[i] && window.$viewer && window.$viewer.removeLayer(addPupoLayers[i])
+ addPupoLayers[i] = null
+ delete addPupoLayers[i]
+ })
+ addPupoLayers = {}
+}
+
+onUnmounted(() => {
+ if (tileLayers) {
+ tileLayers.clear()
+ window.$viewer && window.$viewer.removeLayer(tileLayers)
+ tileLayers = null
+ }
+
+ let arr = Object.keys(addTileLayers)
+ arr.filter(i => i != 'hgyq').forEach(i => {
+ addTileLayers[i] && window.$viewer && window.$viewer.removeLayer(addTileLayers[i])
+ addTileLayers[i] = null
+ delete addTileLayers[i]
+ })
+ addTileLayers = null
+ // 弹窗销毁
+ destroy()
+ addPupoLayers = null
+
+ EventBus.off('restHandleCheckChange', restHandleCheckChange)
+ EventBus.off('restHandleDelChange', restHandleDelChange)
+ EventBus.off('flyToyqfw', flyToyqfw)
+})
+</script>
+
+<style lang="scss" scoped>
+.tree-content {
+ min-width: 200px;
+ padding: 10px;
+
+ ::v-deep(.el-tree) {
+ color: #fff;
+ background: transparent;
+
+ /* 鼠标浮动过的背景颜色 */
+ .el-tree-node__content:hover {
+ background: #0074b7;
+ }
+
+ /* 鼠标点击时节点的背景颜色 */
+ .el-tree-node:focus>.el-tree-node__content {
+ background-color: #0074b7 !important;
+ color: rgb(255, 255, 255);
+ }
+
+ /* 鼠标失去焦点时节点背景的颜色 */
+ .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
+ background: rgb(0, 129, 204);
+ }
+ }
+}
+</style>
diff --git a/src/pages/map/components/scomponents/popup/panorama.vue b/src/pages/map/components/scomponents/popup/panorama.vue
new file mode 100644
index 0000000..038f311
--- /dev/null
+++ b/src/pages/map/components/scomponents/popup/panorama.vue
@@ -0,0 +1,70 @@
+<template>
+ <div class="panorama-container">
+ <div class="title">
+ <div>{{ title }}</div>
+ <div class="close cursor-p" @click="$emit('closePanoramaPopup')">
+ <i class="fa fa-close"></i>
+ </div>
+ </div>
+ <div class="content">
+ <iframe class="w100 h100" :src="url" frameborder="0"></iframe>
+ </div>
+ </div>
+</template>
+
+<script setup>
+const {
+ title,
+ url
+} = defineProps({
+ title: {
+ default: ''
+ },
+ url: {
+ default: ''
+ }
+})
+
+</script>
+
+<style lang="scss" scoped>
+.panorama-container {
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ z-index: 999;
+ background: transparent;
+ /* fallback for old browsers */
+ // background: -webkit-linear-gradient(to right, #3a7bd5, #00d2ff);
+ /* Chrome 10-25, Safari 5.1-6 */
+ // background: linear-gradient(to right, #3a7bd5, #00d2ff);
+ background-color: rgba($color: #000000, $alpha: 1.0);
+ /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
+ pointer-events: auto;
+ box-shadow: inset 0 0 200px #0377eb;
+
+ .title {
+ padding: 0 10px;
+ display: flex;
+ justify-content: space-between;
+ height: 44px;
+ line-height: 44px;
+ color: #fff;
+
+ .close {
+ cursor: pointer;
+ }
+ }
+
+ .content {
+ padding: 0 10px 10px;
+ width: 100%;
+ height: 0;
+ flex: 1;
+ }
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/tool/curtain.vue b/src/pages/map/components/scomponents/tool/curtain.vue
new file mode 100644
index 0000000..87d2bce
--- /dev/null
+++ b/src/pages/map/components/scomponents/tool/curtain.vue
@@ -0,0 +1,108 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-29 15:48:36
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-11-27 19:17:04
+ * @FilePath: \bigScreen\src\pages\layout\components\scomponents\tool\curtain.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <public-box style="z-index: 100;">
+ <template #name>
+ <div class="name"><i class="fa fa-map-pin"></i> 卷帘对比 </div>
+ </template>
+
+ <template #close>
+ <div class="close cursor-p" @click="$emit('closeChild')"><i class="fa fa-close"></i></div>
+ </template>
+
+ <template #content>
+ <div class="cur-btn">
+ <!-- <div class="m-4">
+ <p>左侧图层</p>
+ <el-select class="transparent-bg" v-model="value1" placeholder="天地图">
+ <el-option v-for="item in components" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </div>
+ <div class="m-4">
+ <p>右侧图层</p>
+ <el-select popper-class="transparent-bg" v-model="value2" collapse-tags placeholder="天地图">
+ <el-option v-for="item in components" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
+ </div> -->
+ </div>
+ </template>
+ </public-box>
+</template>
+
+<script setup>
+const value1 = ref([])
+const value2 = ref([])
+
+
+
+onMounted(() => {
+ window.$viewer.sceneSplit.enable = true
+})
+
+// 关闭
+const close = () => {
+ window.$viewer.sceneSplit.enable = false
+}
+
+const flyTo = () => {
+ // window.$viewer.flyToPosition(new DC.Position(longitude.value, latitude.value, height.value, 0, -90, 0), () => { }, 3)
+}
+
+onUnmounted(() => {
+ window.$viewer && (window.$viewer.sceneSplit.enable = false)
+})
+
+const components = [
+ { label: '天地图', value: '1' },
+ { label: '谷歌影像', value: '2' },
+ { label: '谷歌矢量', value: '3' },
+ { label: '高德影像', value: '4' },
+]
+</script>
+
+<style lang="scss" scoped>
+.cur-btn {
+ margin: 10px 0;
+ display: flex;
+
+ // justify-content: center;
+ // align-items: center;
+
+ // &.el-select {
+ // width: 50px;
+ // }
+}
+
+.m-4 {
+ text-align: center;
+ width: 200px;
+}
+
+.transparent-bg {
+ background: transparent;
+
+}
+
+// 重新el——select样式
+::v-deep .el-select__wrapper {
+ background: transparent;
+
+}
+
+::v-deep .el-select-dropdown {
+ // background: transparent;
+ background-color: aqua;
+}
+
+::v-deep .el-select .el-select__placeholder {
+ color: #fff;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/tool/exportScene.vue b/src/pages/map/components/scomponents/tool/exportScene.vue
new file mode 100644
index 0000000..f139255
--- /dev/null
+++ b/src/pages/map/components/scomponents/tool/exportScene.vue
@@ -0,0 +1,10 @@
+<template>
+</template>
+
+<script setup>
+window.$viewer.exportScene()
+const emit = defineEmits(['closeChild'])
+emit('closeChild')
+</script>
+
+<style lang="scss" scoped></style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/tool/location.vue b/src/pages/map/components/scomponents/tool/location.vue
new file mode 100644
index 0000000..a531121
--- /dev/null
+++ b/src/pages/map/components/scomponents/tool/location.vue
@@ -0,0 +1,89 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-29 15:48:36
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-10-29 19:53:49
+ * @FilePath: \bigScreen\src\views\layout\components\scomponents\tool\location.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <public-box style="z-index: 100;">
+ <template #name>
+ <div class="name"><i class="fa fa-map-pin"></i> 底图</div>
+ </template>
+
+ <template #close>
+ <div class="close cursor-p" @click="$emit('closeChild')"><i class="fa fa-close"></i></div>
+ </template>
+
+ <template #content>
+ <div class="cur-content">
+ <div>
+ <span>经度:</span>
+ <el-input v-model="longitude" size="small" placeholder="请输入经度" />
+ </div>
+ <div>
+ <span>纬度:</span>
+ <el-input v-model="latitude" size="small" placeholder="请输入纬度" />
+ </div>
+ <div>
+ <span>高度:</span>
+ <el-input v-model="height" size="small" placeholder="请输入高度" />
+ </div>
+ </div>
+
+ <div class="cur-btn">
+ <el-button color="rgba(13,100,167,.8)" @click="flyTo" type="primary" size="small">坐标定位</el-button>
+ </div>
+ </template>
+ </public-box>
+</template>
+
+<script setup>
+const longitude = ref(0)
+const latitude = ref(0)
+const height = ref(0)
+
+const flyTo = () => {
+ window.$viewer.flyToPosition(new DC.Position(longitude.value, latitude.value, height.value, 0, -90, 0), () => { }, 3)
+}
+</script>
+
+<style lang="scss" scoped>
+.cur-content {
+ &>div {
+ margin-top: 10px;
+ padding: 0 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ span {
+ width: 54px;
+ }
+
+ ::v-deep(.el-input) {
+ border: none !important;
+
+ .el-input__wrapper {
+ background: rgba(63, 72, 84, .7) !important;
+ border: none !important;
+ box-shadow: none;
+
+ input {
+ color: #fff;
+ }
+ }
+ }
+ }
+}
+
+.cur-btn {
+ margin: 10px 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/tool/measure.vue b/src/pages/map/components/scomponents/tool/measure.vue
new file mode 100644
index 0000000..afcd1c7
--- /dev/null
+++ b/src/pages/map/components/scomponents/tool/measure.vue
@@ -0,0 +1,220 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-29 15:48:36
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-10-29 19:53:49
+ * @FilePath: \bigScreen\src\views\layout\components\scomponents\tool\location.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <public-box style="z-index: 100;">
+ <template #name>
+ <div class="name"><i class="fa fa-map-pin"></i> 测量工具</div>
+ </template>
+
+ <template #close>
+ <div class="close cursor-p" @click="$emit('closeChild')"><i class="fa fa-close"></i></div>
+ </template>
+
+ <template #content>
+
+ <div>
+ <div class="container-box">
+ <div v-for="(item, index) in buttonList" :key="index" class="item" @click="item.click">
+ <img class="icon_img" src="../../../../../assets/images/add.png" alt="" srcset="">
+ <div class="text">{{ item.label }}</div>
+ </div>
+ </div>
+
+ <div class="button-clear">
+ <button @click="deactivate">清空测量数据</button>
+ </div>
+ </div>
+
+
+
+ </template>
+ </public-box>
+</template>
+
+<script setup>
+const longitude = ref(0)
+const latitude = ref(0)
+const height = ref(0)
+let measure = reactive({})
+onMounted(() => {
+ measure = new DC.Measure(window.$viewer)
+})
+
+onUnmounted(() => {
+ deactivate()
+})
+// 空间距离
+function calcDistance() {
+ measure.distance()
+}
+// 贴地距离
+function distanceSurface() {
+ measure.distanceSurface()
+}
+// 水平面积
+function calcArea(item) {
+ measure.area()
+}
+// 贴地面积
+function areaSurface() {
+ measure.areaSurface()
+}
+// 角度
+function calcAngle() {
+ measure.angle()
+}
+// 模型角度
+function calcModelAngle() {
+ measure.angle({
+ clampToModel: true
+ })
+}
+// 高度
+function calcHeight() {
+ measure.height()
+}
+// 贴物高度
+function calcModelHeight() {
+ measure.height({
+ clampToModel: true
+ })
+}
+// 航向
+function calcHeading() {
+ measure.heading()
+}
+// 模型航向
+function areaHeight() {
+ measure.areaHeight()
+}
+// 三角测量
+
+function calcTriangleHeight() {
+ measure.triangleHeight()
+}
+// 模型三角测量
+function calcModelTriangleHeight() {
+ measure.triangleHeight({
+ clampToModel: true
+ })
+}
+
+// 清空
+function deactivate() {
+ measure.deactivate()
+}
+
+const buttonList = [
+ {
+ label: '空间距离',
+ value: 'space',
+ imges: '../../../../../assets/images/add.png',
+ click: calcDistance
+ },
+ {
+ label: '贴地距离',
+ value: 'area',
+ imges: '../../../../../assets/images/add.png',
+ click: distanceSurface
+ },
+ // {
+ // label: '剖面',
+ // value: 'volume',
+ // imges: '../../../../../assets/images/add.png'
+ // },
+ {
+ label: '水平面积',
+ value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: calcArea
+ },
+ {
+ label: '贴地面积', value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: areaSurface
+
+ },
+ {
+ label: '角度',
+ value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: calcAngle
+ },
+ {
+ label: '高度差',
+ value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: calcAngle
+ },
+ {
+ label: '三角测量',
+ value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: calcModelTriangleHeight
+ },
+ {
+ label: '贴物高度',
+ value: 'volume',
+ imges: '../../../../../assets/images/add.png',
+ click: calcModelHeight
+ },
+]
+
+const flyTo = () => {
+ // window.$viewer.flyToPosition(new DC.Position(longitude.value, latitude.value, height.value, 0, -90, 0), () => { }, 3)
+}
+</script>
+
+<style lang="scss" >
+.container-box {
+ width: 230px;
+ display: flex;
+ flex-wrap: wrap;
+ font-size: 12px;
+}
+
+.icon_img {
+ width: 40px;
+ height: 40px;
+}
+
+.item {
+ width: 60px;
+ margin: 8px;
+ text-align: center;
+ padding: 3px;
+}
+
+.button-clear {
+ display: flex;
+ justify-content: center;
+ margin: 10px 0;
+}
+
+.button-clear button {
+ padding: 6px;
+ border: none;
+}
+
+.button-clear button:hover {
+ background-color: blue;
+ color: #fff;
+}
+
+.container-box .item:hover {
+ box-shadow: inset 0px 0px 30px 20px rgba(31, 139, 247, 0.949);
+ border-radius: 20%;
+}
+
+.text {
+ // color: pink;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/map/components/scomponents/toolList.vue b/src/pages/map/components/scomponents/toolList.vue
new file mode 100644
index 0000000..627db72
--- /dev/null
+++ b/src/pages/map/components/scomponents/toolList.vue
@@ -0,0 +1,134 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2024-10-29 14:20:49
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2024-11-27 15:34:16
+ * @FilePath: \bigScreen\src\pages\layout\components\scomponents\toolList.vue
+ * @Description:
+ *
+ * Copyright (c) 2024 by shuishen, All Rights Reserved.
+-->
+<template>
+ <ul v-show="moreToolShow" class="tool-list-box">
+ <li @click="showComponent(item.component)" v-for="(item, index) in components" :key="index">
+ <i :class="item.icon"></i> {{ item.title }}
+ </li>
+ </ul>
+
+ <component :is="currentComponent" v-if="currentComponent" @closeChild="closeComponent" />
+</template>
+
+<script setup>
+const { moreToolShow } = defineProps({
+ moreToolShow: {
+ type: Boolean, //参数类型
+ default: false, //默认值
+ required: true, //是否必须传递
+ }
+})
+import location from './tool/location.vue'
+import curtain from './tool/curtain.vue'
+import measure from './tool/measure.vue'
+import exportScene from './tool/exportScene.vue'
+import component from 'element-plus/es/components/tree-select/src/tree-select-option.mjs'
+const emit = defineEmits(['close'])
+
+let currentComponent = shallowRef(null)
+const components = [
+ {
+ icon: 'fa fa-calculator',
+ title: '图上量算',
+ component: measure,
+ },
+ // {
+ // icon: 'fa fa-bar-chart',
+ // title: '空间分析',
+ // },
+ {
+ name: 'location',
+ icon: 'fa fa-map-pin',
+ title: '坐标定位',
+ component: location
+ },
+ // {
+ // icon: 'fa fa-paper-plane',
+ // title: '地区导航',
+ // },
+ // {
+ // icon: 'fa fa-edit',
+ // title: '我的标记',
+ // },
+ // {
+ // icon: 'fa fa-tags',
+ // title: '视角书签',
+ // },
+ {
+ name: 'exportScene',
+ icon: 'fa fa-download',
+ title: '场景导出',
+ component: exportScene
+ },
+ // {
+ // icon: 'fa fa-object-group',
+ // title: '图上标绘',
+ // },
+ // {
+ // icon: 'fa fa-helicopter',
+ // title: '飞行漫游',
+ // },
+ // {
+ // icon: 'fa fa-level-up',
+ // title: '路线导航',
+ // },
+ // {
+ // icon: 'fa fa-columns',
+ // title: '卷帘对比',
+ // component: curtain
+ // },
+ // {
+ // icon: 'fa fa-window-restore',
+ // title: '分屏对比',
+ // },
+]
+
+const showComponent = (component) => {
+ currentComponent.value = component
+ emit('close', 'tool')
+}
+
+const closeComponent = () => {
+ currentComponent.value = null
+}
+</script>
+
+<style lang="scss" scoped>
+.tool-list-box {
+ position: absolute;
+ right: 540px;
+ z-index: 101;
+ top: 152px;
+ background: rgba(63, 72, 84, .7);
+ pointer-events: auto;
+
+ li {
+ padding: 6px 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: #fff;
+ cursor: pointer;
+
+ i {
+ margin-right: 5px;
+ }
+ }
+
+ li:hover {
+ background: #4db3ff;
+ }
+
+ li:first-child {
+ margin-top: 0;
+ }
+}
+</style>
diff --git a/src/pages/map/index.vue b/src/pages/map/index.vue
new file mode 100644
index 0000000..af33496
--- /dev/null
+++ b/src/pages/map/index.vue
@@ -0,0 +1,260 @@
+<template>
+ <div class="wrapper">
+ <map-container ref="MapContainer">
+ <template #content>
+ <div v-if="showContent" class="main-content" id="MainContent">
+ <main-search></main-search>
+ <main-tool></main-tool>
+
+ <div class="w100 h100 relative">
+ <div class="main-header">
+ <div class="title">吉水化工园区“一园一策一图”VR平台</div>
+
+ <div class="login-out" @click="signOut">
+ <img :src="loginOutBg" class="img" />
+ <span>退出</span>
+ </div>
+ </div>
+
+ <div class="main-container">
+ <!-- 地图区域 -->
+ <router-view></router-view>
+ </div>
+
+ <main-menu></main-menu>
+ </div>
+ </div>
+ </template>
+ </map-container>
+ </div>
+</template>
+
+<script setup>
+import { getAssetsFile } from 'utils/utils'
+const loginOutBg = getAssetsFile('login.png', '/images')
+import mainMenu from './components/mainMenu.vue'
+
+import { useRouter, useRoute } from 'vue-router'
+let router = useRouter()
+import mainSearch from './components/mainSearch.vue'
+import mainTool from './components/mainTool.vue'
+
+import { useLogin } from 'store/login'
+const loginStore = useLogin()
+import { useMap } from 'store/map'
+import { useRouterStore } from 'store/router'
+
+const store = useMap()
+const showContent = ref(false)
+
+const signOut = () => {
+ loginStore.LogOut().then(res => {
+ router.push({
+ path: '/login'
+ })
+ })
+}
+
+// onMounted(() => {
+// store.setLoadSub(false)
+// }),
+
+// 监听createB的变化
+watch(
+ [
+ () => store.loadMap,
+ ],
+ ([newLoadMap]) => {
+ showContent.value = newLoadMap
+ },
+ { immediate: true } // 设置immediate为true以便在组件挂载时立即检查createB的值
+)
+</script>
+
+<style lang="scss" scoped>
+$bg-blue: rgba(24, 33, 92, 0.9);
+
+.wrapper {
+ position: relative;
+ width: 100%;
+ height: 100%;
+
+ #MainContent,
+ #SingleMainContent {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 99;
+ }
+
+ .main-content {
+ height: 1080px;
+ background: url(/images/header.png) no-repeat center / 100% 100%,
+ url(/images/pro-bg.png) no-repeat center / 100% 100%;
+
+ pointer-events: none;
+
+ &.single-page {
+ background: url(/images/header.png) no-repeat center / 100% 100%,
+ url(/images/pro-bg.png) no-repeat center / 100% 100%,
+ rgba(0, 0, 0, 1);
+ }
+
+ .main-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ pointer-events: auto;
+
+ .title {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: 640px;
+ height: 40px;
+ font-size: 24px;
+ font-family: YouSheBiaoTiHei;
+ font-weight: 400;
+ color: #eff8fc;
+ line-height: 40px;
+ text-align: center;
+ letter-spacing: 8px;
+ font-weight: bolder;
+ background: linear-gradient(to bottom,
+ #e2eaf0 0%,
+ #aed1f1 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ // opacity: 0.89;
+ // text-shadow: 0px 4px 1px rgba(19, 80, 143, 0.66);
+
+ // background: linear-gradient(0deg, rgba(119, 186, 255, 0.45) 0%, rgba(233, 248, 255, 0.45) 73.3154296875%, rgba(255, 255, 255, 0.45) 100%);
+ // -webkit-background-clip: text;
+ // -webkit-text-fill-color: transparent;
+ }
+
+
+ .login-out {
+ position: absolute;
+ top: 10px;
+ right: 40px;
+ height: 36px;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 10px;
+ cursor: pointer;
+
+ .img {
+ width: 16px;
+ height: 16px;
+ margin-right: 5px;
+ }
+
+ span {
+ font-size: 13px;
+ }
+ }
+
+ .login-out:hover {
+ background-color: #3c5e8f;
+ border-radius: 20px;
+
+ }
+ }
+
+ .main-container {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ right: 40px;
+ bottom: 40px;
+ }
+ }
+}
+
+.main-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ pointer-events: auto;
+
+ .title {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: 640px;
+ height: 40px;
+ font-size: 24px;
+ font-family: YouSheBiaoTiHei;
+ font-weight: 400;
+ color: #eff8fc;
+ line-height: 40px;
+ text-align: center;
+ letter-spacing: 8px;
+ font-weight: bolder;
+ background: linear-gradient(to bottom,
+ #e2eaf0 0%,
+ #aed1f1 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ // opacity: 0.89;
+ // text-shadow: 0px 4px 1px rgba(19, 80, 143, 0.66);
+
+ // background: linear-gradient(0deg, rgba(119, 186, 255, 0.45) 0%, rgba(233, 248, 255, 0.45) 73.3154296875%, rgba(255, 255, 255, 0.45) 100%);
+ // -webkit-background-clip: text;
+ // -webkit-text-fill-color: transparent;
+ }
+
+
+ .login-out {
+ position: absolute;
+ top: 10px;
+ right: 40px;
+ height: 36px;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 10px;
+ cursor: pointer;
+
+ .img {
+ width: 16px;
+ height: 16px;
+ margin-right: 5px;
+ }
+
+ span {
+ font-size: 13px;
+ }
+ }
+
+ .login-out:hover {
+ background-color: #3c5e8f;
+ border-radius: 20px;
+
+ }
+}
+
+.main-container {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ right: 40px;
+ bottom: 40px;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/single/components/mainMenu.vue b/src/pages/single/components/mainMenu.vue
new file mode 100644
index 0000000..fad7483
--- /dev/null
+++ b/src/pages/single/components/mainMenu.vue
@@ -0,0 +1,120 @@
+<template>
+ <div class="page-mode">
+ <div @mouseenter="item.childrenFlag = true" :class="{ active: currentUrl.indexOf(item.path) != -1 }"
+ @mouseleave="item.childrenFlag = false" @click="goToPath(item)" v-for="(item, index) in menuList" :key="index">
+ {{ item.menuName }}
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, watch } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
+import { Search } from '@element-plus/icons-vue'
+import { getTime } from '@/utils/getTime.js'
+import { useRouterStore } from 'store/router'
+const store = useRouterStore()
+let router = useRouter()
+let currentUrl = ref('statistics')
+
+const menuList = ref(
+ [
+ {
+ menuName: '园区概况',
+ path: '/layout/map/survey'
+ },
+ {
+ menuName: '风险源',
+ path: '/layout/map/rs'
+ },
+ {
+ menuName: '应急空间',
+ path: '/layout/map/space'
+ },
+ {
+ menuName: '应急物资',
+ path: '/layout/single/supplies'
+ },
+ {
+ menuName: '三级防控',
+ path: '/layout/map/pac'
+ },
+ {
+ menuName: '救援队伍',
+ path: '/layout/single/rt'
+ },
+ {
+ menuName: '突发事件模拟',
+ path: '/layout/map/pd'
+ },
+ {
+ menuName: '作战图',
+ path: '/layout/single/ochart'
+ },
+ ]
+)
+
+const goToPath = (params) => {
+ if (params.children && params.children.length > 0) return
+
+ if (params.path) {
+ if (router.currentRoute.value.path == params.path) return
+ router.push({
+ path: params.path
+ })
+ } else {
+ params.childrenFlag = !params.childrenFlag
+ }
+}
+
+watch(
+ () => router.currentRoute.value,
+ (newValue, oldValue) => {
+
+ currentUrl.value = newValue.path
+
+ },
+ { immediate: true }
+)
+
+const userName = ref('管理员')
+</script>
+
+<style lang="scss" scoped>
+.page-mode {
+ position: absolute;
+ top: auto;
+ bottom: 55px;
+ left: 50%;
+ z-index: 99;
+ transform: translateX(-50%);
+ display: flex;
+ pointer-events: auto;
+
+ &>div {
+ background-image: url(/images/mode-tab.png);
+ background-size: cover;
+ width: 136px;
+ height: 50px;
+ font-size: 16px;
+ text-align: center;
+ font-weight: bold;
+ color: #BFD3E5;
+ line-height: 32px;
+ padding-top: 12px;
+ margin-right: -20px;
+ font-style: italic;
+ cursor: pointer;
+ box-sizing: border-box;
+
+ &:last-child {
+ margin-right: 0px;
+ }
+
+ &.active {
+ color: #F6FCFF;
+ background-image: url(/images/mode-tab-ac.png);
+ }
+ }
+}
+</style>
diff --git a/src/pages/single/index.vue b/src/pages/single/index.vue
new file mode 100644
index 0000000..711b4d3
--- /dev/null
+++ b/src/pages/single/index.vue
@@ -0,0 +1,223 @@
+<template>
+ <div class="wrapper">
+ <div class="w100 h100 relative main-content single-page" id="MainContent">
+ <div class="main-header">
+ <div class="title">吉水化工园区“一园一策一图”VR平台</div>
+
+ <div class="login-out" @click="signOut">
+ <img :src="loginOutBg" class="img" />
+ <span>退出</span>
+ </div>
+ </div>
+
+ <div class="main-container">
+ <!-- 地图区域 -->
+ <router-view></router-view>
+ </div>
+
+ <main-menu></main-menu>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { getAssetsFile } from 'utils/utils'
+const loginOutBg = getAssetsFile('login.png', '/images')
+import mainMenu from './components/mainMenu.vue'
+
+const signOut = () => {
+ loginStore.LogOut().then(res => {
+ router.push({
+ path: '/login'
+ })
+ })
+}
+</script>
+
+<style lang="scss" scoped>
+$bg-blue: rgba(24, 33, 92, 0.9);
+
+.wrapper {
+ position: relative;
+ width: 100%;
+ height: 100%;
+
+ #MainContent,
+ #SingleMainContent {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 99;
+ }
+
+ .main-content {
+ height: 1080px;
+ background: url(/images/header.png) no-repeat center / 100% 100%,
+ url(/images/pro-bg.png) no-repeat center / 100% 100%;
+
+ pointer-events: none;
+
+ &.single-page {
+ background: url(/images/header.png) no-repeat center / 100% 100%,
+ url(/images/pro-bg.png) no-repeat center / 100% 100%,
+ rgba(0, 0, 0, 1);
+ }
+
+ .main-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ pointer-events: auto;
+
+ .title {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: 640px;
+ height: 40px;
+ font-size: 24px;
+ font-family: YouSheBiaoTiHei;
+ font-weight: 400;
+ color: #eff8fc;
+ line-height: 40px;
+ text-align: center;
+ letter-spacing: 8px;
+ font-weight: bolder;
+ background: linear-gradient(to bottom,
+ #e2eaf0 0%,
+ #aed1f1 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ // opacity: 0.89;
+ // text-shadow: 0px 4px 1px rgba(19, 80, 143, 0.66);
+
+ // background: linear-gradient(0deg, rgba(119, 186, 255, 0.45) 0%, rgba(233, 248, 255, 0.45) 73.3154296875%, rgba(255, 255, 255, 0.45) 100%);
+ // -webkit-background-clip: text;
+ // -webkit-text-fill-color: transparent;
+ }
+
+
+ .login-out {
+ position: absolute;
+ top: 10px;
+ right: 40px;
+ height: 36px;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 10px;
+ cursor: pointer;
+
+ .img {
+ width: 16px;
+ height: 16px;
+ margin-right: 5px;
+ }
+
+ span {
+ font-size: 13px;
+ }
+ }
+
+ .login-out:hover {
+ background-color: #3c5e8f;
+ border-radius: 20px;
+
+ }
+ }
+
+ .main-container {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ right: 40px;
+ bottom: 40px;
+ }
+ }
+}
+
+.main-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ pointer-events: auto;
+
+ .title {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: 640px;
+ height: 40px;
+ font-size: 24px;
+ font-family: YouSheBiaoTiHei;
+ font-weight: 400;
+ color: #eff8fc;
+ line-height: 40px;
+ text-align: center;
+ letter-spacing: 8px;
+ font-weight: bolder;
+ background: linear-gradient(to bottom,
+ #e2eaf0 0%,
+ #aed1f1 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ // opacity: 0.89;
+ // text-shadow: 0px 4px 1px rgba(19, 80, 143, 0.66);
+
+ // background: linear-gradient(0deg, rgba(119, 186, 255, 0.45) 0%, rgba(233, 248, 255, 0.45) 73.3154296875%, rgba(255, 255, 255, 0.45) 100%);
+ // -webkit-background-clip: text;
+ // -webkit-text-fill-color: transparent;
+ }
+
+
+ .login-out {
+ position: absolute;
+ top: 10px;
+ right: 40px;
+ height: 36px;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 10px;
+ cursor: pointer;
+
+ .img {
+ width: 16px;
+ height: 16px;
+ margin-right: 5px;
+ }
+
+ span {
+ font-size: 13px;
+ }
+ }
+
+ .login-out:hover {
+ background-color: #3c5e8f;
+ border-radius: 20px;
+
+ }
+}
+
+.main-container {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ right: 40px;
+ bottom: 40px;
+}
+</style>
\ No newline at end of file
--
Gitblit v1.9.3