Parcourir la source

大屏项目级工具栏更新

xieqy il y a 3 ans
Parent
commit
1c27a0644c

Fichier diff supprimé car celui-ci est trop grand
+ 134 - 129
package-lock.json


+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "animate.css": "^4.1.1",
     "axios": "^0.27.2",
     "babel-loader": "^8.2.4",
+    "canvas2image": "^1.0.5",
     "core-js": "^2.6.11",
     "cross-env": "^7.0.3",
     "echarts": "^5.2.0",

+ 8 - 8
src/directives.ts

@@ -10,7 +10,7 @@ Vue.directive('dialogDrag', {
     dragDom.style.cssText += ';top:0px;'
 
     // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
-    const sty = (function() {
+    const sty = (function () {
       //@ts-ignore
       if (window.document.currentStyle) {
         return (dom, attr) => dom.currentStyle[attr]
@@ -50,7 +50,7 @@ Vue.directive('dialogDrag', {
         styT = +styT.replace(/\px/g, '')
       }
 
-      document.onmousemove = function(e) {
+      document.onmousemove = function (e) {
         // 通过事件委托,计算移动的距离
         let left = e.clientX - disX
         let top = e.clientY - disY
@@ -72,7 +72,7 @@ Vue.directive('dialogDrag', {
         dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
       }
 
-      document.onmouseup = function(e) {
+      document.onmouseup = function (e) {
         document.onmousemove = null
         document.onmouseup = null
       }
@@ -85,14 +85,14 @@ Vue.directive('drag', {
     const oDiv = el // 当前元素
     const self = this // 上下文
     // 禁止选择网页上的文字
-    document.onselectstart = function() {
+    document.onselectstart = function () {
       return false
     }
-    oDiv.onmousedown = function(e) {
+    oDiv.onmousedown = function (e) {
       // 鼠标按下,计算当前元素距离可视区的距离
       const disX = e.clientX - oDiv.offsetLeft
       const disY = e.clientY - oDiv.offsetTop
-      document.onmousemove = function(e) {
+      document.onmousemove = function (e) {
         // 通过事件委托,计算移动的距离
         const l = e.clientX - disX
         const t = e.clientY - disY
@@ -100,12 +100,12 @@ Vue.directive('drag', {
         oDiv.style.left = l + 'px'
         oDiv.style.top = t + 'px'
       }
-      document.onmouseup = function(e) {
+      document.onmouseup = function (e) {
         document.onmousemove = null
         document.onmouseup = null
       }
       // return false不加的话可能导致黏连,就是拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
-      return false
+      // return false
     }
   }
 })

+ 101 - 0
src/utils/mapCommon/CesiumViewTool.js

@@ -0,0 +1,101 @@
+/**
+ * GetViewExtent获取当前视图范围
+ * GetViewCenter获取当前视图中心点
+ */
+var CesiumViewTool = (function () {
+    function _() {
+    }
+    _.GetViewExtent = function (viewer) {
+        var extent = {};
+        var scene = viewer.scene;
+        var ellipsoid = scene.globe.ellipsoid;
+        var canvas = scene.canvas;
+        var car3_lt = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(0, 0), ellipsoid);// canvas左上角
+        var car3_rb = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(canvas.width, canvas.height), ellipsoid); // canvas右下角
+        // 当canvas左上角和右下角全部在椭球体上
+        if (car3_lt && car3_rb) {
+            var carto_lt = ellipsoid.cartesianToCartographic(car3_lt);
+            var carto_rb = ellipsoid.cartesianToCartographic(car3_rb);
+            extent.xmin = Cesium.Math.toDegrees(carto_lt.longitude);
+            extent.ymax = Cesium.Math.toDegrees(carto_lt.latitude);
+            extent.xmax = Cesium.Math.toDegrees(carto_rb.longitude);
+            extent.ymin = Cesium.Math.toDegrees(carto_rb.latitude);
+        } else if (!car3_lt && car3_rb) { // 当canvas左上角不在但右下角在椭球体上
+            var car3_lt2 = null;
+            var yIndex = 0;
+            var xIndex = 0;
+            do {
+                // 这里每次10像素递加,一是10像素相差不大,二是为了提高程序运行效率
+                yIndex <= canvas.height ? yIndex += 10 : canvas.height;
+                xIndex <= canvas.width ? xIndex += 10 : canvas.width;
+                car3_lt2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(xIndex, yIndex), ellipsoid);
+            } while (!car3_lt2);
+            var carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt2);
+            var carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb);
+            extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
+            extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
+            extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
+            extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
+        }
+        else if (car3_lt && !car3_rb) { // 当canvas左上角在但右下角不在椭球体上
+            var car3_rb2 = null;
+            var yIndex = canvas.height;
+            var xIndex = canvas.width;
+            do {
+                // 这里每次10像素递加,一是10像素相差不大,二是为了提高程序运行效率
+                yIndex >= 10 ? yIndex -= 10 : 10;
+                xIndex >= 10 ? xIndex -= 10 : 10;
+                car3_rb2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(yIndex, yIndex), ellipsoid);
+            } while (!car3_rb2);
+            var carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt);
+            var carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb2);
+            extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
+            extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
+            extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
+            extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
+        } else if (!car3_lt && !car3_rb) {
+            var car3_lt2 = null;
+            var yIndex = 0;
+            var xIndex = 0;
+            do {
+                // 这里每次10像素递加,一是10像素相差不大,二是为了提高程序运行效率
+                yIndex <= canvas.height ? yIndex += 10 : canvas.height;
+                xIndex <= canvas.width ? xIndex += 10 : canvas.width;
+                car3_lt2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(xIndex, yIndex), ellipsoid);
+            } while (!car3_lt2);
+            var car3_rb2 = null;
+            var yIndex = canvas.height;
+            var xIndex = canvas.width;
+            do {
+                // 这里每次10像素递加,一是10像素相差不大,二是为了提高程序运行效率
+                yIndex >= 10 ? yIndex -= 10 : 10;
+                xIndex >= 10 ? xIndex -= 10 : 10;
+                car3_rb2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(yIndex, yIndex), ellipsoid);
+            } while (!car3_rb2);
+            var carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt2);
+            var carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb2);
+            extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
+            extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
+            extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
+            extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
+        }
+        // 获取高度
+        extent.height = Math.ceil(viewer.camera.positionCartographic.height);
+        return extent;
+    }
+    _.GetViewCenter = function (viewer) {
+        var result = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2));
+        if (result) { } else { return null; }
+        var curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(result);
+        var lon = curPosition.longitude * 180 / Math.PI;
+        var lat = curPosition.latitude * 180 / Math.PI;
+        var height = viewer.camera.positionCartographic.height;
+        return {
+            lon: lon,
+            lat: lat,
+            height: height
+        };
+    }
+    return _;
+})();
+export default CesiumViewTool

+ 70 - 10
src/views/groupPage/baseMap/components/ProjectMap.vue

@@ -110,6 +110,9 @@ export default {
       scene.postProcessStages.fxaa.enabled = true
       //显示天空
       scene.skyBox.show = false
+      // scene.shadowMap.darkness = 1.275 //设置第二重烘焙纹理的效果(明暗程度)
+      scene.sun.show = true //关闭太阳
+      scene.fog.enabled = false //关闭雾气
       //隐藏大气圈
       scene.skyAtmosphere.show = false
       //地形深度测试
@@ -146,9 +149,13 @@ export default {
       for (let name in source) {
         if (mapList.indexOf(name) > -1) {
           const config = source[name].config
-          for (let i = 0; i < config.length; i++) {
-            const item = config[i]
-            baseLayer.push({ name: item.key, type: name, show: item.isDisplay === '0' ? false : true })
+          for (let key in config) {
+            const item = config[key]
+            baseLayer.push({
+              name: key,
+              type: name,
+              show: item.isDisplay === '0' ? false : true
+            })
           }
         }
       }
@@ -158,9 +165,9 @@ export default {
     initBaseMap() {
       this.baseMapConfig()
       let layerInfo = this.baselayer
-      layerInfo.forEach((item, index) => {
+      layerInfo.forEach((item) => {
         if (item.show) {
-          const gisItem = this.mapConfig.gisResource[item.type].config[index]
+          const gisItem = this.mapConfig.gisResource[item.type].config[item.name]
           if (!gisItem) {
             return true
           }
@@ -184,13 +191,66 @@ export default {
     //加载初始化场景
     addInitScene() {
       var scenes = this.mapConfig.gisResource[this.baseScene]
-      if (scenes && scenes.config.length > 0) {
+      if (scenes && scenes.config) {
         this.scenesIndex = 0
-        scenes.config.forEach(
-          function (item, index) {
+        Object.keys(scenes.config).forEach(
+          function (keyName, index) {
+            const item = scenes.config[keyName]
             var promise = this.viewer.scene.open(item.url, undefined, {
               autoSetView: false
             })
+            Cesium.when(
+              promise,
+              function (layers) {
+                this.scenesIndex += 1
+                for (var i = 0; i < layers.length; i++) {
+                  var ly = layers[i]
+                  ly.selectEnabled = false
+                  ly.clearMemoryImmediately = false
+                  ly.cullEnabled = false
+                  //ly.lodRangeScale=0.01
+                  var model = BaseConfig.layers[ly.name]
+                  if (BaseConfig.sjpipeLayers.indexOf(ly.name) > -1) {
+                    let style3d = new Cesium.Style3D()
+                    style3d.altitudeMode = 0
+                    style3d.bottomAltitude = 0 - this.mapConfig.downDepth
+                    ly.style3D = style3d
+                    //ly.visibleDistanceMax=800;
+                    ly.maxVisibleAltitude = BaseConfig.pipeMaxVisibel
+                  }
+                  //普查管线初始隐藏
+                  if (BaseConfig.pcpipeLayers.indexOf(ly.name) > -1) {
+                    let style3d = new Cesium.Style3D()
+                    style3d.altitudeMode = 0
+                    style3d.bottomAltitude = 0 - this.mapConfig.downDepth
+                    ly.style3D = style3d
+                    ly.visible = false
+                    ly.maxVisibleAltitude = BaseConfig.pipeMaxVisibel
+                  }
+                  if (BaseConfig.pipeSelectLayers.indexOf(ly.name) > -1) {
+                    ly.selectedColor = Cesium.Color.DARKRED
+                    ly.selectColorType = 1
+                  }
+                  if (BaseConfig.pipeLineLayer.indexOf(ly.name) > -1) {
+                    ly.lodRangeScale = 20
+                  }
+                  if (model) {
+                    let style3d = new Cesium.Style3D()
+                    style3d.altitudeMode = 0
+                    style3d.bottomAltitude = model.bottomAltitude
+                    ly.visible = model.visible
+                    ly.style3D = style3d
+                  }
+                  ly.refresh()
+                }
+                // if (!this.AppX.runtimeConfig.activeView.scene.pickPositionSupported) {
+                //   console.error('不支持深度纹理,无法拾取位置!')
+                // }
+              }.bind(this),
+              function (e) {
+                console.error('加载SCP失败,请检查网络连接状态或者url地址是否正确?')
+              }
+            )
           }.bind(this)
         )
       }
@@ -200,8 +260,8 @@ export default {
       var viewer = this.viewer
       var configItem = this.mapConfig.gisResource[this.baseTerrain]
       var type = configItem.type
-      var url = configItem.config[0].url
-      var layerTitle = configItem.config[0].name
+      var url = configItem.config[this.terrain].url
+      var layerTitle = configItem.config[this.terrain].name
       switch (type) {
         case 'ext_terrain':
           viewer.terrainProvider = new Cesium.CesiumTerrainProvider({

+ 20 - 4
src/views/groupPage/components/ComInfoBox.vue

@@ -1,12 +1,15 @@
 <template>
   <!-- 工具框 -->
   <div v-if="panelVisible" class="widget-ComInfoBox" v-drag>
-    <div class="header">
+    <!-- <div class="header">
       <div class="title">工具集</div>
       <span class="close" @click="handelClose()"><i class="el-icon-close" /></span>
-    </div>
+    </div> -->
+    <span class="close" @click="handelClose()">
+      <i class="el-icon-close" />
+    </span>
     <el-tabs :tab-position="tabPosition" :value="activeName" closable @tab-remove="removeTab">
-      <el-tab-pane v-for="item in panels" :key="item.com" :label="item.name" :name="item.name">
+      <el-tab-pane v-for="item in panels" :key="item.name" :label="item.name" :name="item.name">
         <component :is="item.com" class="content"></component>
       </el-tab-pane>
     </el-tabs>
@@ -73,10 +76,23 @@ export default class ComInfoBox extends Vue {
       }
     }
   }
+  .close {
+    position: absolute;
+    top: 0.015625rem /* 3/192 */;
+    right: 0.015625rem /* 3/192 */;
+    color: #a3d3ff;
+    font-size: 0.083333rem /* 16/192 */;
+    z-index: 10;
+    cursor: pointer;
+  }
   >>> .el-tabs {
-    height: calc(100% - 0.177083rem /* 34/192 */);
+    height: calc(100% - 0.052083rem /* 10/192 */);
     width: 100%;
     font-family: Source Han Sans CN;
+    padding: 0.052083rem /* 10/192 */;
+    // .el-tabs__header {
+    //   margin: 0px 0.104167rem /* 20/192 */ 0.078125rem /* 15/192 */ !important;
+    // }
     .el-tabs__item {
       font-size: 0.072917rem /* 14/192 */;
       font-weight: 500;

+ 4 - 2
src/views/groupPage/districtPageModules/commonModules/CustomToolBox.vue

@@ -22,12 +22,14 @@
 <script lang="ts">
 import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
 import pbsTree from '@/views/groupPage/districtPageModules/customTools/pbsTree.vue'
+import monitorTree from '@/views/groupPage/districtPageModules/customTools/monitorTree.vue'
+import layerControl from '@/views/groupPage/districtPageModules/customTools/layerControl.vue'
 //自定义工具栏
 @Component({ name: 'CustomToolBox', components: {} })
 export default class CustomToolBox extends Vue {
   toolList: Array<any> = [
-    { name: '图层控制', com: null },
-    { name: '设备监测树', com: null },
+    { name: '图层控制', com: layerControl },
+    { name: '设备监测树', com: monitorTree },
     { name: '工程结构树', com: pbsTree },
     { name: '进度查看', com: null }
   ]

+ 1 - 0
src/views/groupPage/districtPageModules/commonModules/SearchBox.vue

@@ -100,6 +100,7 @@ export default class SearchBox extends Vue {
     style3D.bottomAltitude = height
     gLayerList.forEach((item) => {
       var layer = this.viewer.scene.layers.find(item)
+      console.log(layer)
       if (layer) {
         layer.style3D = style3D
         layer.refresh()

+ 24 - 2
src/views/groupPage/districtPageModules/commonModules/ToolBox.vue

@@ -21,12 +21,16 @@
           <img :src="unfoldUrl" />
         </div>
       </div>
+      <div class="roam-panel" v-show="isRoaming">
+        <ViewManagement :show="isRoaming" />
+      </div>
     </div>
   </transition>
 </template>
 
 <script lang="ts">
 import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+import ViewManagement from '@/views/groupPage/districtPageModules/customTools/viewManagement.vue'
 const Cesium = (window as any).Cesium
 const viewMemoryType = {
   none: 'none',
@@ -34,7 +38,7 @@ const viewMemoryType = {
   after: 'after'
 } //记录视图
 //工具栏
-@Component({ name: 'ToolBox' })
+@Component({ name: 'ToolBox', components: { ViewManagement } })
 export default class ToolBox extends Vue {
   toolList: Array<any> = [
     { imgUrl: require('@/views/groupPage/images/工具栏/基础地图.png'), name: '基础地图' },
@@ -42,12 +46,13 @@ export default class ToolBox extends Vue {
     { imgUrl: require('@/views/groupPage/images/工具栏/俯视.png'), name: '俯视' },
     { imgUrl: require('@/views/groupPage/images/工具栏/左视图.png'), name: '上一视图' },
     { imgUrl: require('@/views/groupPage/images/工具栏/右视图.png'), name: '下一视图' },
-    { imgUrl: require('@/views/groupPage/images/工具栏/场景漫游.png'), name: '漫游' }
+    { imgUrl: require('@/views/groupPage/images/工具栏/漫游.png'), name: '漫游' }
     // { imgUrl: require('@/views/groupPage/images/工具栏/图片.png'), name: '截图' },
     // { imgUrl: require('@/views/groupPage/images/工具栏/鹰眼.png'), name: '鹰眼' }
   ]
   unfoldUrl = require('@/views/groupPage/images/工具栏/展开.png')
   isFold: boolean = false
+  isRoaming: boolean = false //漫游面板
   g_preViews = [] //前一视图
   g_afterViews = [] //后一视图
   g_viewType = viewMemoryType.none //前或后视图
@@ -82,6 +87,9 @@ export default class ToolBox extends Vue {
       case '俯视':
         this.lookDown()
         break
+      case '漫游':
+        this.roaming()
+        break
     }
   }
   //初始位置
@@ -198,6 +206,7 @@ export default class ToolBox extends Vue {
       this.g_viewType = viewMemoryType.none
     })
   }
+  //俯视
   lookDown() {
     const camera = this.viewer.camera
     camera.flyTo({
@@ -210,6 +219,10 @@ export default class ToolBox extends Vue {
       }
     })
   }
+  //漫游面板操作
+  roaming() {
+    this.isRoaming = true
+  }
 }
 </script>
 
@@ -260,5 +273,14 @@ export default class ToolBox extends Vue {
       background: rgba(7, 51, 84, 1);
     }
   }
+  .roam-panel {
+    position: absolute;
+    width: 1.354167rem /* 260/192 */;
+    height: 1.546875rem /* 297/192 */;
+    border: 1px solid rgba(43, 174, 253, 0.34);
+    background: rgba(43, 174, 253, 0.34);
+    right: 0.416667rem /* 80/192 */;
+    bottom: 0.026042rem /* 5/192 */;
+  }
 }
 </style>

+ 66 - 0
src/views/groupPage/districtPageModules/customTools/common.scss

@@ -0,0 +1,66 @@
+/deep/.el-tabs {
+  height: 100%;
+  width: 100%;
+  padding: 0;
+
+  .el-tabs__item {
+    font-size: 0.072917rem;
+    font-weight: 500;
+    color: #fff;
+  }
+
+  .el-tabs__item.is-active {
+    color: #0ea7ff;
+    background: transparent;
+  }
+
+  .el-tabs__item:hover {
+    color: #0ea7ff;
+  }
+
+  .el-tabs__content {
+    height: calc(100% - 42px);
+    color: #8eb2ce;
+  }
+
+  .el-tab-pane {
+    height: 100%;
+    width: 100%;
+  }
+
+  .el-tabs__nav-wrap::after {
+    background-color: rgba(14, 167, 255, 0.2);
+  }
+}
+
+/deep/ .el-tree {
+  background: transparent;
+  color: #8eb2ce;
+  font-size: 0.083333rem;
+
+  .el-tree-node>.el-tree-node__children {
+    overflow: unset;
+    background-color: transparent;
+  }
+
+  .el-tree-node__content {
+    background-color: transparent;
+  }
+
+  .el-tree-node__content:hover {
+    background-color: rgb(62, 70, 112);
+  }
+
+  .el-tree-node.is-current>.el-tree-node__content {
+    background: rgba(22, 119, 255, 0.1);
+    color: #4b95fe;
+
+    /deep/ .el-tree-node__expand-icon {
+      color: rgb(0, 112, 255);
+    }
+
+    /deep/ .is-leaf {
+      color: rgba(0, 0, 0, 0);
+    }
+  }
+}

+ 616 - 0
src/views/groupPage/districtPageModules/customTools/layerControl.vue

@@ -0,0 +1,616 @@
+<template>
+  <div class="widget-LayerList">
+    <el-tabs v-model="activeName" @tab-click="tabClick">
+      <el-tab-pane label="基础图层" name="baselayer">
+        <el-tree
+          ref="baseTree"
+          @check="checkLayer"
+          :data="baselayers"
+          node-key="id"
+          :props="defaultProps"
+          show-checkbox
+          :default-expanded-keys="baseDefaultExpand"
+          :default-checked-keys="baseDefaultCheck"
+        >
+        </el-tree>
+      </el-tab-pane>
+      <el-tab-pane label="专题图" name="themelayer">
+        <el-tree
+          ref="themeTree"
+          @check="checkLayer"
+          :data="themelayers"
+          node-key="id"
+          :props="defaultProps"
+          show-checkbox
+          :default-expanded-keys="themeDefaultExpand"
+          :default-checked-keys="themeDefaultCheck"
+        >
+        </el-tree>
+      </el-tab-pane>
+      <el-tab-pane label="设计管线" name="sjpipelayer">
+        <el-tree
+          ref="sjTree"
+          @check="checkLayer"
+          :data="sjlayers"
+          node-key="id"
+          :props="defaultProps"
+          show-checkbox
+          :default-expanded-keys="sjDefaultExpand"
+          :default-checked-keys="sjDefaultCheck"
+        >
+        </el-tree>
+      </el-tab-pane>
+      <el-tab-pane label="普查管线" name="pcpipelayer">
+        <el-tree
+          ref="pcTree"
+          @check-change="checkLayer"
+          :data="pclayers"
+          node-key="id"
+          :props="defaultProps"
+          show-checkbox
+          :default-expanded-keys="pcDefaultExpand"
+          :default-checked-keys="pcDefaultCheck"
+        >
+        </el-tree>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+<script>
+// import Config from './config.json'
+// import $ from 'jquery'
+const LayerType = {
+  S3M: 'S3M',
+  Imagery: 'Imagery',
+  Terrain: 'Terrain',
+  Mvt: 'Mvt'
+}
+export default {
+  name: 'LayerList',
+  data() {
+    return {
+      activeName: 'baselayer',
+      defaultProps: {
+        label: 'label',
+        children: 'children'
+      },
+      currentLayer: 'sjpipelayer',
+      currentRef: '',
+      layer: {
+        pclayer: 'pcpipelayer',
+        yllayer: 'ylpipelayer',
+        jglayer: 'jgpipelayer',
+        baselayer: 'baselayer',
+        sjlayer: 'sjpipelayer',
+        themelayer: 'themelayer'
+      },
+
+      baselayers: [],
+      themelayers: [],
+      sjlayers: [],
+      pclayers: [],
+      baseDefaultExpand: ['baselayer_0'],
+      baseDefaultCheck: [],
+      themeDefaultExpand: ['themelayer_0'],
+      themeDefaultCheck: [],
+      sjDefaultExpand: ['sjpipelayer_0'],
+      sjDefaultCheck: [],
+      pcDefaultExpand: ['pcpipelayer_0'],
+      pcDefaultCheck: []
+    }
+  },
+  computed: {
+    AppX() {
+      return this.$store.state.bigScreen.mapConfig
+    }
+  },
+  mounted() {
+    this.currentRef = this.$refs.baseTree
+    // if (window.viewer) {
+    //   this.viewer = window.viewer;
+    //   this.initMapConfig();
+    //   this.initLayers();
+    // } else {
+    //   console.error('viewer未初始化');
+    // }
+  },
+  methods: {
+    tabClick(data) {
+      switch (data.name) {
+        case this.layer.pclayer:
+          this.currentRef = this.$refs.pcTree
+          break
+        case this.layer.baselayer:
+          this.currentRef = this.$refs.baseTree
+          break
+        case this.layer.sjlayer:
+          this.currentRef = this.$refs.sjTree
+          break
+        case this.layer.themelayer:
+          this.currentRef = this.$refs.themeTree
+          break
+      }
+    },
+    /**
+     *该方法用于生成图层管理配置
+     */
+    initMapConfig() {
+      const themeLayer = []
+      const baseLayer = []
+      const gisSource = this.AppX.appConfig.gisResource
+      const themeConfig = gisSource[Config.themeMap].config
+      const themegroup = this.initThemelayers(themeConfig)
+      // for (let i = 0; i < themeConfig.length; i++) {
+      //     const themeitem = themeConfig[i];
+      //     themeLayer.push({ label: themeitem.name, name: themeitem.key, type: "img", add: true, dic: Config.themeMap, sort: themeitem.sort ? themeitem.sort : 1000 });
+      // }
+      // //排序
+      // themeLayer.sort((a, b) => { return a.sort - b.sort; })
+      Config.themelayer[0].data = themegroup
+      const mapService = Config.mapService
+      for (let j = 0; j < mapService.length; j++) {
+        const keyName = mapService[j]
+        const config = gisSource[mapService[j]].config
+        for (let k = 0; k < config.length; k++) {
+          const item = config[k]
+          baseLayer.push({
+            label: item.name,
+            name: item.key,
+            type: 'img',
+            add: true,
+            dic: keyName,
+            sort: item.sort ? item.sort : 1000
+          })
+        }
+      }
+      //排序
+      baseLayer.sort((a, b) => {
+        return a.sort - b.sort
+      })
+      Config.baselayer[0].data = Config.baselayer[0].data.concat(baseLayer)
+    },
+    /**
+     * 该方法用于专题图分组组合
+     */
+    initThemelayers(themeConfig) {
+      const group = []
+      for (let layerkey in themeConfig) {
+        const themeitem = themeConfig[layerkey]
+        const groupLayer = _.find(group, (item) => {
+          return item.label === themeitem.sourceGroup
+        })
+        if (!groupLayer && themeitem.sourceGroup) {
+          //新建分组
+          group.push({
+            label: themeitem.sourceGroup,
+            data: [
+              {
+                label: themeitem.name,
+                name: layerkey,
+                type: 'img',
+                add: true,
+                dic: Config.themeMap,
+                sort: themeitem.sort ? themeitem.sort : 1000
+              }
+            ],
+            sort: 1000
+          })
+        } else if (groupLayer && themeitem.sourceGroup) {
+          //现有分组增加
+          groupLayer.data.push({
+            label: themeitem.name,
+            name: layerkey,
+            type: 'img',
+            add: true,
+            dic: Config.themeMap,
+            sort: themeitem.sort ? themeitem.sort : 1000
+          })
+        } else if (!themeitem.sourceGroup) {
+          //现有分组增加
+          group.push({
+            label: themeitem.name,
+            name: layerkey,
+            type: 'img',
+            add: true,
+            dic: Config.themeMap,
+            sort: themeitem.sort ? themeitem.sort : 1000
+          })
+        }
+      }
+      //组内分组排序
+      group.forEach((item) => {
+        if (item.data) {
+          item.data.sort((a, b) => {
+            return a.sort - b.sort
+          })
+          item.sort = item.data[0].sort
+        }
+      })
+      //分组排序
+      group.sort((a, b) => {
+        return a.sort - b.sort
+      })
+      return group
+    },
+    /**
+     * 加载图层列表
+     */
+    initLayers() {
+      //树状数据处理
+      this.loadLayerList()
+    },
+    /**
+     * 加载图层信息
+     */
+    loadLayerList() {
+      let initlayer = null
+      for (let layertype in this.layer) {
+        switch (this.layer[layertype]) {
+          case this.layer.pclayer:
+            initlayer = Config.pcpipelayer
+            break
+          case this.layer.baselayer:
+            initlayer = Config.baselayer
+            break
+          case this.layer.sjlayer:
+            initlayer = Config.sjpipelayer
+            break
+          case this.layer.themelayer:
+            initlayer = Config.themelayer
+            break
+        }
+        this.currentLayer = this.layer[layertype]
+        let layerConfig = []
+        this.getNode(initlayer, this.layer[layertype], layerConfig)
+        switch (this.layer[layertype]) {
+          case this.layer.pclayer:
+            this.pclayers = layerConfig
+            break
+          case this.layer.baselayer:
+            this.baselayers = layerConfig
+            break
+          case this.layer.sjlayer:
+            this.sjlayers = layerConfig
+            break
+          case this.layer.themelayer:
+            this.themelayers = layerConfig
+            break
+        }
+      }
+    },
+    /**
+     * 处理图层配置
+     *
+     * */
+    getNode(data, pid, parentLayer) {
+      let num = 0
+      let checkednum = 0
+      let isExitNum = 0
+      data.forEach((item, i) => {
+        if (item.data) {
+          let parentConfig = { label: item.label, children: [], id: pid + '_' + num }
+          let checked = this.getNode(item.data, pid + '_' + num, parentConfig.children)
+          if (checked && checked != 'NoExit') {
+            checkednum++
+          }
+          if (checked && checked == 'NoExit') {
+            isExitNum++
+          }
+          let open = false
+          if (pid.split('_').length == 1) {
+            open = true
+          }
+          if (checked != 'NoExit') {
+            parentLayer.push(parentConfig)
+          }
+        } else {
+          let checked = false
+          let type = null
+          let Exit = false
+          //判断是否属于layers图层
+          if (item.name) {
+            let data_item = item.name.split(',')
+            if (data_item.length > 0) {
+              $.each(
+                data_item,
+                function (i, item2) {
+                  let item_search1 = this.viewer.scene.layers.find(item2)
+                  if (item_search1) {
+                    type = LayerType.S3M
+                    checked = item_search1.visible
+                    Exit = true
+                  }
+                }.bind(this)
+              )
+            }
+          }
+          //判断是否属于影像图层
+          if (type == null) {
+            //添加影像,不勾选
+            if (item.type === 'img' && item.add) {
+              checked = !item.add
+              type = LayerType.Imagery
+              Exit = true
+            }
+
+            $.each(this.viewer.imageryLayers._layers, function (index, item_s) {
+              if (item_s.imageryProvider.credit && item.name == item_s.imageryProvider.credit.html) {
+                checked = item_s.show
+                type = LayerType.Imagery
+                Exit = true
+              }
+            })
+          }
+          //判断是否属于地形图层
+          if (type == null && item.label == '地形') {
+            if (this.viewer.terrainProvider._credit) {
+              if (
+                this.AppX.runtimeConfig.terrain === this.viewer.terrainProvider &&
+                this.viewer.terrainProvider._credit.html == item.label
+              ) {
+                checked = true
+                Exit = true
+              } else {
+                checked = false
+              }
+            } else {
+              checked = false
+            }
+            type = LayerType.Terrain
+          }
+          //判断是否属于切片图层
+          if (type == null && item.type == 'mvt') {
+            //添加影像,不勾选
+            if (item.add) {
+              checked = !item.add
+              type = LayerType.Mvt
+              Exit = true
+            }
+            let layer = this.viewer.scene.getVectorTilesLayer(item.name)
+            if (layer) {
+              if (layer.show) {
+                checked = true
+                Exit = true
+              } else {
+                checked = false
+              }
+            } else {
+              checked = false
+            }
+          }
+          if (checked) {
+            checkednum++
+            //设置树组件默认选中节点
+            switch (this.currentLayer) {
+              case this.layer.pclayer:
+                this.pcDefaultCheck.push(pid + '_' + num)
+                break
+              case this.layer.baselayer:
+                this.baseDefaultCheck.push(pid + '_' + num)
+                break
+              case this.layer.sjlayer:
+                this.sjDefaultCheck.push(pid + '_' + num)
+                break
+              case this.layer.themelayer:
+                this.themeDefaultCheck.push(pid + '_' + num)
+                break
+            }
+          }
+          if (Exit) {
+            parentLayer.push({
+              id: pid + '_' + num,
+              dic: item.dic,
+              label: item.label,
+              layer_name: item.name,
+              type: type,
+              name_2d: item.name_2d ? item.name_2d : ''
+            })
+          } else {
+            isExitNum++
+          }
+        }
+        num++
+      })
+      if (isExitNum == data.length) {
+        return 'NoExit'
+      }
+      if (checkednum == data.length - isExitNum) {
+        return true
+      }
+    },
+    /**
+     * 图层勾选控制
+     * @param data node对象
+     * @param checked 选中状态
+     */
+    checkLayer(data, checkedkeys) {
+      const checkednodes = this.currentRef.getCheckedKeys()
+      const checked = !(checkednodes.indexOf(data.id) === -1)
+      this.onAndClose(data, checked)
+    },
+    /**
+     * 图层的关闭和打开
+     *
+     */
+    onAndClose(clickNode, checked) {
+      let layer = undefined
+      const that = this
+      if (!clickNode) {
+        return
+      }
+      if (clickNode.children) {
+        $.each(
+          clickNode.children,
+          function (i, item) {
+            this.onAndClose(item, checked)
+          }.bind(this)
+        )
+      } else {
+        let data = null
+        if (clickNode.name_2d != '') {
+          $.each(this.maplayer, function (i, item) {
+            let names = clickNode.name_2d.split(',')
+            if (names.length > 1) {
+              $.each(names, function (i2, item2) {
+                if (item.name == item2) {
+                  item.visible = checked
+                }
+              })
+            } else {
+              if (item.name == clickNode.name_2d) {
+                item.visible = checked
+              }
+            }
+          })
+        }
+        switch (clickNode.type) {
+          case LayerType.S3M:
+            data = clickNode.layer_name.split(',')
+            if (data.length > 0) {
+              $.each(
+                data,
+                function (i, item) {
+                  layer = this.viewer.scene.layers.find(item)
+                  if (layer) {
+                    layer.visible = checked
+                  }
+                }.bind(this)
+              )
+            }
+            break
+          case LayerType.Imagery:
+            const imageLayers = this.viewer.imageryLayers
+            data = clickNode.layer_name.split(',')
+            if (data.length > 0) {
+              $.each(data, function (i, item) {
+                that.imageLayerControl(item, clickNode.dic, checked)
+              })
+            }
+            break
+          case LayerType.Terrain:
+            if (checked) {
+              this.viewer.terrainProvider = this.AppX.runtimeConfig.terrain
+            } else {
+              this.viewer.scene.terrainProvider = new Cesium.EllipsoidTerrainProvider() //无法控制地形显隐,替换一个简单地形
+            }
+            break
+          case LayerType.Mvt:
+            data = clickNode.layer_name.split(',')
+            if (data.length > 0) {
+              $.each(data, function (i, item) {
+                that.mvtLayerControl(item, checked)
+              })
+            }
+            break
+        }
+      }
+    },
+    /**
+     * 该方法用于增加
+     * @param key 影像服务key,同时也是credit
+     * @param dic 影像服务字典编码
+     * @param checked 是否打开
+     */
+    imageLayerControl(key, dic, checked) {
+      if (checked) {
+        const gisitem = this.AppX.appConfig.gisResource[dic].config[key]
+        if (gisitem) {
+          const url = gisitem.url
+          this.viewer.imageryLayers.addImageryProvider(
+            new Cesium.SuperMapImageryProvider({
+              url: url,
+              credit: key
+            })
+          )
+        }
+      } else {
+        const imageLayers = this.viewer.imageryLayers
+        for (let i = 0; i < imageLayers.length; i++) {
+          const img = imageLayers.get(i)
+          if (img.imageryProvider.credit && img.imageryProvider.credit.html === key) {
+            imageLayers.remove(img, true)
+          }
+        }
+      }
+    },
+    /**
+     * 切片图层得打开关闭
+     * @param key 服务key,同时也是credit
+     * @param checked 是否打开
+     */
+    mvtLayerControl(key, checked) {
+      if (checked) {
+        const url = this.AppX.appConfig.gisResource['img'].config[key].url
+        this.AppX.runtimeConfig.viewer.scene.addVectorTilesMap({
+          url: url,
+          name: key
+        })
+      } else {
+        this.AppX.runtimeConfig.viewer.scene.removeVectorTilesMap(key)
+      }
+    },
+    /**
+     * 缩放到图层
+     */
+    zoomToLayer(event, treeId, clickNode) {
+      let searchNode = null
+      if (!clickNode) {
+        return
+      }
+      if (clickNode.type == undefined || clickNode.type == null) {
+        return
+      }
+      const layerType = clickNode.type
+      switch (layerType) {
+        case LayerType.S3M:
+          const id = clickNode.layer_name
+          const clickLayer = _.find(this.viewer.scene.layers.layerQueue, (layer) => {
+            return layer.name === clickNode.layer_name.split(',')[0]
+          })
+          this.viewer.camera.flyTo({
+            destination: clickLayer.layerBounds,
+            orientation: {
+              heading: 0,
+              pitch: Cesium.Math.toRadians(-90),
+              roll: 0
+            }
+          })
+          break
+        case LayerType.Imagery:
+          const length = this.viewer.imageryLayers.length
+          for (let i = 0; i < length; i++) {
+            const item = this.viewer.imageryLayers.get(i).imageryProvider
+            if (item.credit && item.credit.html === clickNode.layer_name) {
+              this.viewer.camera.flyTo({
+                destination: item.rectangle,
+                orientation: {
+                  heading: 0,
+                  pitch: Cesium.Math.toRadians(-90),
+                  roll: 0
+                }
+              })
+            }
+          }
+          break
+        case LayerType.Terrain:
+          const bound = this.AppX.runtimeConfig.terrain.tilingScheme.rectangle
+          this.viewer.camera.flyTo({
+            destination: bound,
+            orientation: {
+              heading: 0,
+              pitch: Cesium.Math.toRadians(-90),
+              roll: 0
+            }
+          })
+          break
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.widget-LayerList {
+  color: white;
+  @import './common.scss';
+}
+</style>

+ 246 - 0
src/views/groupPage/districtPageModules/customTools/monitorTree.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="widget-monitorTree" ref="widget-monitorTree">
+    <div class="content">
+      <div class="header">
+        <div class="title">设备监测树</div>
+        <el-input placeholder="设备名称搜索" v-model="filterText" size="mini" clearable>
+          <el-button slot="append" icon="el-icon-search"></el-button>
+        </el-input>
+      </div>
+      <div class="statistic">
+        <!-- <div class="deviceStatus">
+          <div class="statusItem" v-for="item of statusList" :key="item.type">
+            <div class="itemIcon" :style="setStatusIconColor(item.type)"></div>
+            <div class="itemText" :title="item.num + '个'">{{ item.type }}:{{ item.num }}个</div>
+          </div>
+        </div> -->
+        <div class="deviceTypeGroup">
+          <el-tree
+            class="filter-tree"
+            show-checkbox
+            :data="treeData"
+            :props="defaultProps"
+            default-expand-all
+            node-key="id"
+            :default-checked-keys="[0, 1]"
+            :filter-node-method="filterNode"
+            @check="getCheckList()"
+            @node-click="handleTreeNodeClick"
+            ref="tree"
+          >
+            <span slot-scope="{ node }">
+              {{ node.label }}
+              <img v-if="setNodeImg(node)" :src="`${setNodeImg(node)}`" style="width: 16px; height: 16px" />
+            </span>
+          </el-tree>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+import axios from '@/utils/request'
+//设备监测树
+@Component({ name: 'monitorTree' })
+export default class monitorTree extends Vue {
+  @Watch('filterText')
+  onChangeMethod(val) {
+    let target = this.$refs.tree as any
+    target.filter(val)
+  }
+  //参数
+  deviceCheckList = []
+  filterText = ''
+  treeData = []
+  defaultProps = { children: 'children', label: 'name' }
+  statusList = [
+    { code: 'normalNum', type: '正常', num: 20 },
+    { code: 'warnNum', type: '报警', num: 20 },
+    { code: 'offlineNum', type: '离线', num: 20 }
+  ]
+  mounted() {
+    this.getData()
+  }
+  //获取监测设备数据
+  getData() {
+    let params = { typeCode: 'deviceTree' }
+    axios.request({ url: '/panoramic/commonData/list', method: 'get', params }).then((res) => {
+      let result = res.result
+      Object.keys(result).forEach((item, index) => {
+        this.treeData.push({ id: index, name: item, children: result[item] })
+      })
+    })
+  }
+  setStatusIconColor(type) {
+    let color = type === '在线' ? '#2BA7FF' : type === '离线' ? 'grey' : type === '正常' ? '#2BA7FF' : 'red'
+    return 'background-color:' + color
+  }
+  //节点过滤
+  filterNode(value, data) {
+    if (!value) return true
+    return data.name.indexOf(value) !== -1
+  }
+  setNodeImg(node) {
+    let iconSrc
+    return iconSrc
+  }
+  handleTreeNodeClick(data) {
+    if (!data.coordiateX || !data.coordiateY) return
+    let position = [data.coordiateX, data.coordiateY]
+    // this.zoomCenter(position)
+  }
+  getCheckList() {
+    // this.resetLayerSource()
+    // this.deviceCheckList = this.$refs.tree.getCheckedNodes().filter((item) => !item.children)
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.animate__flipInX,
+.animate__flipOutX {
+  animation-duration: 3s; //动画持续时间
+  animation-delay: 0s; //动画延迟时间
+}
+.widget-monitorTree {
+  width: 100%;
+  height: 100%;
+  color: #eee;
+  //font
+  font-family: Source Han Sans CN;
+  .content {
+    margin-top: 0.026042rem /* 5/192 */;
+    // width: 1.979167rem /* 380/192 */;
+    width: 2.1875rem /* 420/192 */;
+    height: 1.979167rem /* 380/192 */;
+    //   background: linear-gradient(0deg, rgba(2, 20, 37, 0.56) 0%, #072643 100%);
+    .header {
+      height: 0.208333rem /* 40/192 */;
+      margin: 0.052083rem /* 10/192 */ 0.052083rem 0 0.052083rem;
+      padding: 0.026042rem /* 5/192 */;
+      border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      .title {
+        font-size: 0.083333rem /* 16/192 */;
+        font-weight: 500;
+        color: #2ba7ff;
+        white-space: nowrap;
+      }
+      .close {
+        display: flex;
+        align-items: center;
+        height: 100%;
+        color: rgba(138, 211, 253, 1);
+        font-size: 0.09375rem /* 18/192 */;
+        cursor: pointer;
+      }
+      .el-input {
+        width: 1.041667rem /* 200/192 */;
+      }
+      /deep/ .el-input__inner {
+        background-color: rgb(9, 48, 84);
+        border: none;
+        color: #eee;
+        height: 0.145833rem /* 28/192 */;
+      }
+      /deep/ .el-input-group__append {
+        background-color: rgb(9, 48, 84);
+        border: none;
+      }
+      /deep/ .el-icon-search:before {
+        color: rgba(138, 211, 253, 0.3);
+        font-size: 0.09375rem /* 18/192 */;
+      }
+    }
+    .statistic {
+      display: flex;
+      flex-flow: column;
+      width: 100%;
+      height: calc(100% - 0.208333rem /* 40/192 */);
+      .deviceStatus {
+        width: 100%;
+        height: 0.104167rem /* 20/192 */;
+        display: flex;
+        justify-content: center;
+        margin: 0.052083rem /* 10/192 */ 0;
+        color: #8eb2ce;
+        .statusItem {
+          height: 100%;
+          width: 30%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          font-size: 0.083333rem /* 16/192 */;
+          .itemIcon {
+            border-radius: 50%;
+            height: 0.052083rem /* 10/192 */;
+            width: 0.052083rem /* 10/192 */;
+            margin-right: 0.026042rem /* 5/192 */;
+          }
+          .itemText {
+            white-space: nowrap;
+            // flex: 1;
+            text-overflow: ellipsis;
+            overflow: hidden;
+          }
+        }
+      }
+      .deviceTypeGroup {
+        width: 100%;
+        height: calc(100% - 0.104167rem /* 20/192 */);
+        overflow: auto;
+        /deep/ .el-tree {
+          background: transparent;
+          color: #8eb2ce;
+          font-size: 0.083333rem /* 16/192 */;
+          .el-tree-node__content {
+            background-color: transparent;
+          }
+          .el-tree-node__content:hover {
+            background-color: rgb(62, 70, 112);
+          }
+          div[role='group'] > .el-tree-node {
+            width: 50%;
+            float: left;
+          }
+          .el-tree-node.is-current > .el-tree-node__content {
+            background: rgba(22, 119, 255, 0.1);
+            border-right: 3px solid #1677ff;
+            color: #4b95fe;
+            /deep/ .el-tree-node__expand-icon {
+              color: rgb(0, 112, 255);
+            }
+            /deep/ .is-leaf {
+              color: rgba(0, 0, 0, 0);
+            }
+          }
+        }
+        .el-checkbox {
+          color: #fff;
+          margin: 0.052083rem /* 10/192 */ 0;
+        }
+        /deep/ .el-checkbox__inner {
+          background: #0a1525;
+          border-color: rgba(3, 109, 190, 1);
+        }
+        /deep/ .el-checkbox__inner::after {
+          border: 2px solid rgba(17, 156, 255, 1);
+          border-left: 0;
+          border-top: 0;
+        }
+        /deep/ .el-checkbox__input.is-checked .el-checkbox__inner {
+          background: #0a1525;
+          border-color: rgba(3, 109, 190, 1);
+        }
+        /deep/ .el-checkbox__input.is-checked + .el-checkbox__label {
+          color: #fff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 32 - 40
src/views/groupPage/districtPageModules/customTools/pbsTree.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="PbsTreeManagement">
+  <div class="widget-pbsTreeManagement">
     <el-tabs v-model="activeName">
       <el-tab-pane label="设计" name="design">
         <div class="designSearch">
@@ -45,7 +45,7 @@ import { pbsTreeList_api, pbsTreeSearch_api, pbsTreeMinimum_api, createPdfByType
 // import Vue from "vue";
 // import PipeUnitInfo from "@/views/widgets/PipeUnitInfo/index.vue";
 export default {
-  name: 'PbsTreeManagement',
+  name: 'widget-pbsTreeManagement',
   data() {
     return {
       activeName: 'design',
@@ -67,31 +67,32 @@ export default {
         isLeaf: 'leaf'
       },
       viewer: window.viewer,
-      pipeInfo: null
+      pipeInfo: null,
+      prjId: 45
     }
   },
   methods: {
     //懒加载树状下层
     async loadNode(node, resolve) {
-      //   if (node.level == 0) {
-      //     return this.loadtreeData(resolve)
-      //   }
-      //   if (node.level >= 1 && node.data) {
-      //     if (node.data.levelname == '部件类型') {
-      //       let id = node.data.id
-      //       let res = await this.minimumNodesResult(id)
-      //       if (res) {
-      //         return resolve(res)
-      //       }
-      //     } else {
-      //       return resolve(node.data.children)
-      //     }
-      //   }
+      if (node.level == 0) {
+        return this.loadtreeData(resolve)
+      }
+      if (node.level >= 1 && node.data) {
+        if (node.data.levelname == '部件类型') {
+          let id = node.data.id
+          let res = await this.minimumNodesResult(id)
+          if (res) {
+            return resolve(res)
+          }
+        } else {
+          return resolve(node.data.children)
+        }
+      }
     },
     // 获取树状结构列表
     async loadtreeData(resolve) {
-      let res = await pbsTreeList_api()
-      let { result } = res.data
+      let res = await pbsTreeList_api({ prjId: this.prjId })
+      let { result } = res
       this.fatherNodesData = this.getPbsTree(result)
       resolve(this.fatherNodesData)
       this.originalData = result
@@ -103,8 +104,8 @@ export default {
     },
     //获取树状结构列表的最小单元
     async getTreeMinimum(val) {
-      let res = await pbsTreeMinimum_api({ id: val })
-      let { result } = res.data
+      let res = await pbsTreeMinimum_api({ prjId: this.prjId, id: val })
+      let { result } = res
       result.forEach((item) => {
         item.value = item.code
         item.name = `${item.code}(${item.pipeId})`
@@ -164,13 +165,13 @@ export default {
     },
     renderContent(h, { node, data, store }) {
       if (data.pressureType == '1') {
-        return <span style="font-size:14px;">{node.label}</span>
+        return <span>{node.label}</span>
       } else if (data.pressureType == '2') {
-        return <span style="color:#0076FF;font-size:14px;">{node.label}</span>
+        return <span style="color:#0076FF;">{node.label}</span>
       } else if (data.pressureType == '3') {
-        return <span style="color:#009100;font-size:14px;">{node.label}</span>
+        return <span style="color:#009100;">{node.label}</span>
       } else {
-        return <span style="font-size:14px;">{node.label}</span>
+        return <span>{node.label}</span>
       }
     },
     // 树结构子项点击调用
@@ -222,7 +223,7 @@ export default {
       const downloadUrl = '/tofly-sxgk/commonFile/download'
       const data = { stdId: this.treeNodeId }
       let res = await createPdfByType_api(data)
-      const { code, result } = res.data
+      const { code, result } = res
       if (code === 1) {
         const pdf = this.$store.state.apiRoot + downloadUrl + '?fileName=' + result
         window.open(pdf)
@@ -269,10 +270,11 @@ export default {
     //搜索功能
     async searchPBS(value, size) {
       let res = await pbsTreeSearch_api({
+        prjId: this.prjId,
         pbs: value,
         pageSize: size
       })
-      let { result, code } = res.data
+      let { result, code } = res
       if (code === 1 && result) {
         if (result.length >= size) {
           this.$notify({
@@ -335,9 +337,8 @@ export default {
   }
 }
 </script>
-
 <style lang="scss" scoped>
-.PbsTreeManagement {
+.widget-pbsTreeManagement {
   width: 100%;
   height: 100%;
   padding: 0 !important;
@@ -348,7 +349,7 @@ export default {
     }
   }
   .designTree {
-    height: 700px;
+    height: calc(100% - 0.260417rem /* 50/192 */);
     overflow-y: auto;
     margin-top: 10px;
     position: relative;
@@ -358,15 +359,6 @@ export default {
       width: 50px;
     }
   }
-  /deep/ .el-tab-pane {
-    color: #eee;
-  }
-  /deep/ .el-tree {
-    background: transparent;
-    .el-tree-node > .el-tree-node__children {
-      overflow: unset;
-      background-color: transparent;
-    }
-  }
+  @import './common.scss';
 }
 </style>

+ 337 - 0
src/views/groupPage/districtPageModules/customTools/viewManagement.vue

@@ -0,0 +1,337 @@
+<template>
+  <div class="widget-viewManagement">
+    <div class="header">
+      <div class="title">漫游</div>
+      <div class="close" @click="closePanel()"><i class="el-icon-close" /></div>
+      <div class="edit">
+        <span class="icon" @click="playRoamingView()"
+          ><img :src="require('@/views/groupPage/images/工具栏/播放.png')"
+        /></span>
+        <span class="icon" @click="addScreenShot()">
+          <el-popover placement="top" width="200" v-model="tipVisible">
+            <el-input placeholder="请输入视点名称" v-model="viewName" size="small" clearable ref="viewNameInput">
+            </el-input>
+            <div style="text-align: right; margin: 0">
+              <el-button size="mini" type="text" @click="resetRoamingViewAdd()">取消</el-button>
+              <el-button type="primary" size="mini" @click="submitRoamingView()">确定</el-button>
+            </div>
+            <img :src="require('@/views/groupPage/images/工具栏/添加.png')" slot="reference" />
+          </el-popover>
+        </span>
+        <span class="icon" @click="deleteRoamingView()"
+          ><img :src="require('@/views/groupPage/images/工具栏/删除.png')"
+        /></span>
+      </div>
+    </div>
+    <div class="img-content" id="myBtn">
+      <!-- 在HTML5标准中,为了使元素可拖动,把draggable属性设置为true。
+    文本、图片和链接是默认可以拖放的,它们的draggable属性自动被设置成了true。
+    图片和链接按住鼠标左键选中,就可以拖放。文本只有在被选中的情况下才能拖放。
+    如果显示设置文本的draggable属性为true,按住鼠标左键也可以直接拖放。 -->
+      <div class="img-item" v-for="(item, i) in roamViewImageList" :key="i">
+        <img :src="item.src" :id="i" :class="{ isActive: currentViewIndex == i }" @click="clickToView(item, i)" />
+        <el-checkbox v-model="item.checked">{{ item.name }}</el-checkbox>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
+import Canvas2Image from 'canvas2image'
+import axios from '@/utils/request'
+import CesiumViewTool from '@/utils/mapCommon/CesiumViewTool'
+const Cesium = (window as any).Cesium
+const getViewListApi = '/tofly-sxgk/views/get' //获取视图接口
+const addViewInfoApi = '/tofly-sxgk/views/save' //添加视图接口
+const deleteViewApi = '/tofly-sxgk/views/' //删除视图接口
+@Component({ name: 'viewManagement' })
+export default class viewManagement extends Vue {
+  viewer
+  get isInitViewer() {
+    return this.$store.state.bigScreen.isInitViewer
+  }
+  @Watch('isInitViewer')
+  onChangeViewerMethod() {
+    this.viewer = (window as any).viewer
+  }
+  //漫游数据
+  isRoaming: boolean = false //漫游面板
+  viewName = ''
+  tipVisible = false
+  cameraTemp: {} //相机位置
+  roamingViewSrc = '' //屏幕图片
+  roamViewImageList = [] //视点列表
+  currentViewIndex = null //当前视图
+  @Prop({ type: Boolean, default: false }) show!: Boolean
+  @Watch('show')
+  onChangeMethod(val) {
+    if (val) this.init()
+  }
+  init() {
+    this.imgDrag()
+    this.getRoamingView()
+  }
+  //图片拖拽
+  imgDrag() {
+    let btn = document.getElementById('myBtn') as any
+    let that = this
+    this.addHandler(btn, 'dragstart', function (e) {
+      btn.dragStartEle = that.getTarget(e)
+    })
+    this.addHandler(btn, 'dragover', function (e) {
+      that.preventDefault(e)
+      btn.dragEndEle = that.getTarget(e)
+    })
+    this.addHandler(btn, 'dragenter', function (e) {
+      that.preventDefault(e)
+    })
+    this.addHandler(btn, 'drop', function (e) {
+      let target = that.getTarget(e)
+      that.preventDefault(e)
+      // 拖动元素,放置目标
+      if (btn.dragStartEle && target) {
+        if (target.nodeName === 'IMG' && btn.dragStartEle.nodeName === 'IMG') {
+          // 根据id索引交换数据
+          let startI = btn.dragStartEle.id
+          let endI = btn.dragEndEle.id
+          let temp = that.roamViewImageList[startI]
+          that.$set(that.roamViewImageList, startI, that.roamViewImageList[endI])
+          that.$set(that.roamViewImageList, endI, temp)
+        }
+      }
+    })
+  }
+  addHandler(element, type, handler) {
+    //  这里是兼容代码,不需要兼容的可以不加
+    if (element.addEventListener) {
+      element.addEventListener(type, handler, false)
+    } else if (element.attachEvent) {
+      element.attachEvent('on' + type, handler)
+    } else {
+      element['on' + type] = handler
+    }
+  }
+  getTarget(event) {
+    return event.target || event.srcElement
+  }
+  preventDefault(event) {
+    if (event.preventDefault) {
+      event.preventDefault()
+    } else {
+      event.returnValue = false
+    }
+  }
+  //获取漫游视点
+  getRoamingView() {
+    this.isRoaming = true
+    let params = {}
+    axios.request({ url: getViewListApi, method: 'get', params }).then((res) => {
+      // console.log(res)
+    })
+  }
+  //添加
+  addScreenShot() {
+    ;(this.$refs['viewNameInput'] as any).focus()
+    this.viewName = ''
+    let canvas = this.viewer.scene.canvas
+    let screenShot = Canvas2Image.convertToImage(canvas, 400, (400 * canvas.height) / canvas.width, 'png')
+    this.roamingViewSrc = screenShot.src
+    this.cameraTemp = JSON.stringify({
+      direction: this.viewer.camera.direction,
+      up: this.viewer.camera.up,
+      position: this.viewer.camera.position
+    })
+  }
+  //添加保存漫游视点
+  submitRoamingView() {
+    this.roamViewImageList = [
+      ...this.roamViewImageList,
+      {
+        name: this.viewName,
+        src: this.roamingViewSrc,
+        checked: true,
+        camera: this.cameraTemp
+      }
+    ]
+    //视点图片
+    // let scanvas = this.viewer.scene.canvas
+    // let screenShot = Canvas2Image.convertToImage(scanvas, 400, (400 * scanvas.height) / scanvas.width, 'png')
+    // this.roamingViewSrc = screenShot.src
+    // //
+    // var canvas = document.createElement('CANVAS')
+    // var ctx = (<any>canvas).getContext('2d')
+    // var img = new Image()
+    // img.src = this.roamingViewSrc
+    // img.onload = function (e) {
+    //   ;(<any>canvas).width = img.width
+    //   ;(<any>canvas).height = img.height
+    //   ctx.drawImage(img, 0, 0)
+    //   ;(<any>canvas).toBlob(
+    //     function (blob) {
+    //       var extent = JSON.stringify(CesiumViewTool.GetViewExtent(this.viewer))
+    //       var cameraTemp = {
+    //         direction: this.viewer.camera.direction,
+    //         up: this.viewer.camera.up,
+    //         position: this.viewer.camera.position
+    //       }
+    //       var camera = JSON.stringify(cameraTemp)
+    //       var option = new FormData()
+    //       if (this.viewName == '') {
+    //         this.$message('请填写视点名称')
+    //         return
+    //       }
+    //       option.append('markName', this.viewName)
+    //       option.append('camera', camera)
+    //       option.append('extent', extent)
+    //       option.append('file', blob, this.viewName + '.png')
+    //       axios.request({ url: addViewInfoApi, method: 'post', data: option }).then((res) => {
+    //         console.log(res)
+    //       })
+    //     }.bind(this),
+    //     'image/png'
+    //   )
+    // }.bind(this)
+    this.tipVisible = false
+  }
+  //取消添加漫游视点
+  resetRoamingViewAdd() {
+    this.viewName = ''
+    this.roamingViewSrc = ''
+    this.tipVisible = false
+  }
+  //删除视点
+  deleteRoamingView() {
+    let deleteList = this.roamViewImageList.filter((item) => item.checked)
+    if (deleteList.length < 1) {
+      this.$message('请选择至少一个视点')
+      return
+    }
+    this.roamViewImageList = this.roamViewImageList.filter((item) => !item.checked)
+  }
+  //播放视点
+  playRoamingView() {
+    var playList = this.roamViewImageList.filter((item) => item.checked)
+    var that = this
+    if (playList.length > 0) {
+      var i = 0
+      var camera = JSON.parse(playList[i].camera)
+      fly(camera)
+      function fly(camera) {
+        that.currentViewIndex = i
+        that.viewer.camera.flyTo({
+          destination: new Cesium.Cartesian3(camera.position.x, camera.position.y, camera.position.z),
+          orientation: {
+            direction: new Cesium.Cartesian3(camera.direction.x, camera.direction.y, camera.direction.z),
+            up: new Cesium.Cartesian3(camera.up.x, camera.up.y, camera.up.z)
+          },
+          complete: () => {
+            setTimeout(() => {
+              if (i < playList.length - 1) {
+                i += 1
+                fly(JSON.parse(playList[i].camera))
+              } else {
+                that.currentViewIndex = null
+              }
+            }, 200)
+          }
+        })
+      }
+    } else {
+      this.$message('当前暂无视点')
+    }
+  }
+  //单击定位至视点
+  clickToView(data, index) {
+    this.currentViewIndex = index
+    let camera = JSON.parse(data.camera)
+    this.viewer.camera.flyTo({
+      destination: new Cesium.Cartesian3(camera.position.x, camera.position.y, camera.position.z),
+      orientation: {
+        direction: new Cesium.Cartesian3(camera.direction.x, camera.direction.y, camera.direction.z),
+        up: new Cesium.Cartesian3(camera.up.x, camera.up.y, camera.up.z)
+      },
+      complete: () => {
+        this.currentViewIndex = null
+      }
+    })
+    console.log('视点数据', data)
+  }
+  //关闭面板
+  closePanel() {
+    this.isRoaming = false
+    ;(this.$parent as any).isRoaming = false
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+.widget-viewManagement {
+  height: 100%;
+  width: 100%;
+  .header {
+    width: 100%;
+    height: 0.208333rem /* 40/192 */;
+    border-bottom: 1px solid rgba(43, 174, 253, 0.34);
+    padding: 0.067708rem /* 13/192 */;
+    .title {
+      float: left;
+      font-size: 0.072917rem /* 14/192 */;
+      font-family: Source Han Sans CN-HEAVY;
+      font-weight: bold;
+      color: #0ea7ff;
+      background: linear-gradient(0deg, #a3d3ff 0%, #e4f3ff 100%);
+      background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+    .edit {
+      float: right;
+      margin-right: 0.0625rem /* 12/192 */;
+      position: relative;
+      width: 0.427083rem /* 82/192 */;
+      height: 0.098958rem /* 19/192 */;
+      display: flex;
+      justify-content: space-around;
+      align-items: center;
+      span {
+        cursor: pointer;
+      }
+    }
+    .edit::before {
+      content: '';
+      position: absolute;
+      width: 1px;
+      height: 20px;
+      background: rgba(43, 167, 255, 0.5);
+      right: 0;
+      top: 0;
+      bottom: 0;
+      margin: auto 0;
+    }
+    .close {
+      float: right;
+      color: rgba(163, 211, 255, 1);
+      font-size: 0.083333rem /* 16/192 */;
+      cursor: pointer;
+    }
+  }
+  .img-content {
+    width: 100%;
+    padding: 10px;
+    height: calc(100% - 0.208333rem /* 40/192 */);
+    overflow: auto;
+    .img-item {
+      float: left;
+      height: 0.489583rem /* 94/192 */;
+      width: 50%;
+      img {
+        width: 104px;
+        height: 70px;
+      }
+      .isActive {
+        border: 1px solid #0ea7ff;
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
src/views/groupPage/districtPageModules/projectPanoramic/ProjectIndexStatistic.vue

@@ -74,9 +74,9 @@ export default class ProjectIndexStatistic extends Vue {
 .widget-ProjectIndexStatistic {
   bottom: 0.052083rem /* 10/192 */;
   left: 50%;
-  margin-left: -1.822917rem /* 350/192 */;
+  margin-left: -1.276042rem /* 245/192 */;
   height: 0.416667rem /* 80/192 */;
-  width: 3.645833rem /* 700/192 */;
+  width: 2.552083rem /* 490/192 */;
   overflow: hidden;
   position: absolute;
   font-family: Source Han Sans CN;

BIN
src/views/groupPage/images/工具栏/删除.png


BIN
src/views/groupPage/images/工具栏/场景漫游.png


BIN
src/views/groupPage/images/工具栏/播放.png


BIN
src/views/groupPage/images/工具栏/添加.png


BIN
src/views/groupPage/images/工具栏/漫游.png


+ 1 - 1
src/views/widgets/cesiumMap.vue

@@ -45,7 +45,7 @@ export default {
       baseTerrain: 'terrain',
       terrain: 'dixing',
       isInit: false, //当前的地图容器对象
-      baselayer: [],
+      baselayer: []
     }
   },
   computed: {