Browse Source

feat: 总览数据接口对接

TwoKe945 1 year ago
parent
commit
9a9a21fe43

+ 10 - 0
app/src/api/area.js

@@ -13,3 +13,13 @@ export function area(params) {
     params
   })
 }
+
+export function getChartMapData(str) {
+  return request({
+    url: '/system/map/interval',
+    method: 'GET',
+    params: {
+      str
+    }
+  })
+}

+ 5 - 5
app/src/api/hzfx.js

@@ -39,8 +39,8 @@ export function fireDistribution(params) {
 
 /**
  * 起火原因
- * @param {*} params 
- * @returns 
+ * @param {*} params
+ * @returns
  */
 export function fireReason(params) {
   return request({
@@ -52,8 +52,8 @@ export function fireReason(params) {
 
 /**
  * 关键指标统计信息
- * @param {*} params 
- * @returns 
+ * @param {*} params
+ * @returns
  */
 export function fireKeyIndexStaticis(params) {
   return request({
@@ -118,4 +118,4 @@ export function hzfxQhcs(params) {
     method: 'GET',
     params
   })
-}
+}

+ 3 - 3
app/src/components/BasicTotal.vue

@@ -20,13 +20,13 @@ export default {
 
 <template>
   <div class="layer">
-    <slot name="label" v-if="$slots.label"></slot>
-    <span v-else>
+    <slot name="label" v-if="$slots.label"  @click="$emit('click-label', label)"></slot>
+    <span v-else   @click="$emit('click-label', label)">
       {{ label }}
     </span>
 
     <span>
-      <span class="num">
+      <span class="num" @click="$emit('click-number', label)" >
         <linear-text :text="number" fontSize="16px"></linear-text> </span
       >{{ unit }}
     </span>

+ 69 - 0
app/src/components/MapChart3D/MapLegend.vue

@@ -0,0 +1,69 @@
+<script>
+
+export default {
+  props: {
+    legend: {
+      type: Array,
+      default: () => [
+        {name: '高风险', count: 0 },
+        {name: '较高风险', count: 0 },
+        {name: '中风险', count: 0 },
+        {name: '较低风险', count: 0 },
+        {name: '低风险', count: 0 },
+      ]
+    }
+  }
+}
+</script>
+
+<template >
+  <div class="legend">
+    <div  v-for="(item, index) in legend" :key="index"
+      class="legend-item1">
+      <div class="name">{{item.name}}</div>
+      <div :class="`color color-${index}`">
+      </div>
+      <div class="count">{{item.count}}个区县</div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang='less'>
+
+.legend {
+  position: absolute;
+  bottom: 30px;
+  right: 20px;
+}
+.legend-item1 {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  .count {
+    color: #fff;
+  }
+  .name {
+    width: 60px;
+    text-align: right;
+  }
+  .color {
+    width: 10px;
+    height: 40px;
+    &.color-0 {
+    background-color: #ff0b0b;
+    }
+    &.color-1 {
+      background-color: #ff833d;
+    }
+    &.color-2 {
+      background-color: #fbff3d;
+    }
+    &.color-3 {
+      background-color: #35c2ff;
+    }
+    &.color-4 {
+      background-color: #5aed9f;
+    }
+  }
+}
+</style>

+ 105 - 57
app/src/components/MapChart3D/index.vue

@@ -8,12 +8,15 @@ import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer
 import { Interaction } from 'three.interaction/src/index.js';
 import * as d3 from 'd3-geo'
 import gsap from 'gsap'
+import MapLegend from './MapLegend.vue'
 import { onMounted, ref, watch, nextTick } from 'vue';
-
 const BASE_URL = "/src/assets"
 
 export default {
   name: 'Map3DChart',
+  components: {
+    MapLegend
+  },
   props: {
     debugger: {
       type: Boolean,
@@ -35,7 +38,7 @@ export default {
     areaColor: {
       type: Function,
       default: function (params) {
-        return params ? params.meta.分区颜色 : ''
+        return params ? (params.meta ? params.meta.分区颜色 : params.color) : ''
       }
     }
   },
@@ -51,7 +54,6 @@ export default {
     let selectName = null;
     let selectPrevColor = null;
     var map = new THREE.Group();
-    let needReloadColor = []
     const COLOR_MAP = {
       "红色": 0xff4540,
       "橙色": 0xff8934,
@@ -62,7 +64,7 @@ export default {
 
 
     let textureLoader = new THREE.TextureLoader(); //纹理贴图加载器
-    const cacheMap = new Map()
+    let cacheMap = {}
     const mapData = ref(getHeatMapData(props.mapHeatData))
     function getHeatMapData(val) {
       return val.reduce((config, current) => {
@@ -80,22 +82,75 @@ export default {
 
     watch(() => props.mapHeatData, (val) => {
       mapData.value = getHeatMapData(val)
+      Object.keys( mapData.value ).forEach(key => {
+        const area = cacheMap[key];
+        area && area?.mesh.material[0].color.set(getAreaColor(key))
+      })
       nextTick(() => {
-        Object.keys( mapData.value ).forEach(key => {
-          const area = cacheMap.get(key);
-          area && area?.mesh.material[0].color.set(getAreaColor(key))
-        })
+        restart();
       })
     }, {
       deep: true
     })
     watch(() => props.qx, (val) => {
-      const area = cacheMap.get(val);
-      if (area && val !== selectName.element.innerHTML) {
+      const area = cacheMap[val];
+      if (area && (selectName === null || val !== selectName.element.innerHTML )) {
         clickArea(area.mesh, area.name)
       }
+      if (val === "重庆市" && selectName && selectMesh) {
+        clickArea(selectMesh, selectName)
+      }
     })
 
+    let timer = null;
+    let index = 0
+    // 定时任务刷新
+    function start() {
+      const keys = Object.keys(cacheMap)
+      const size = keys.length
+
+      function inc() {
+        index += 1
+      }
+      function get() {
+        return index
+      }
+      function loop() {
+        if (mapData.value) {
+          const idx = get() % size
+          const item = cacheMap[keys[idx]]
+          if (item) {
+            Object.values(cacheMap).forEach(key => {
+              key.info.element.style.opacity = 0;
+            })
+            item.info.element.innerHTML = props.formatter(mapData.value[keys[idx]])
+            item.info.element.style.opacity = 1;
+            inc();
+          }
+        }
+      }
+      loop()
+      timer = setInterval(() => {
+        loop()
+      }, 1500)
+    }
+
+    // 重启函数
+    function restart() {
+      stop();
+      start();
+    }
+
+    // 定制定时任务
+    function stop() {
+      if (timer) {
+        Object.values(cacheMap).forEach(key => {
+          // key.info.visible = false
+          key.info.element.style.opacity = 0;
+        })
+        clearInterval(timer)
+      }
+    }
 
     onMounted(() => {
       init()
@@ -113,20 +168,15 @@ export default {
 		  new Interaction(renderer, scene, camera);
       initGeoJson();
       initDebugger();
-      // 添加物体
-      // const cubeGeometry = new THREE.BoxGeometry(1,1,1)
-      // const material = new THREE.MeshBasicMaterial({
-      //   color: '#ffff00'
-      // })
-      // // 根据几何体和材质创建物体
-      // const cube =new THREE.Mesh(cubeGeometry, material)
-      // // 将几何体创建到场景当中
-      // scene.add(cube)
+      container.addEventListener('mouseleave', () => {
+        restart()
+      })
     }
 
     function initScene() {
       // 1、创建场景
       scene = new THREE.Scene()
+      scene.background = null
     }
     // 初始化灯光
     function initLights() {
@@ -165,7 +215,7 @@ export default {
       renderer = new THREE.WebGLRenderer({antialias: true, alpha: true})
       renderer.setPixelRatio(window.devicePixelRatio);
       renderer.setSize(WIDTH, HEIGHT)
-		  renderer.setClearColor(0x070b13, 1);
+		  renderer.setClearColor(0);
       container.appendChild(renderer.domElement)
 		  // 初始化CSS2DRenderer
       labelRenderer = new CSS2DRenderer();
@@ -210,21 +260,13 @@ export default {
       loader.load(`${BASE_URL}/json/cq.json`, function (data) {
         let jsonData = JSON.parse(data);
         initMap(jsonData);
-        
-        setTimeout(() => {
-          needReloadColor.forEach(item => {
-          item?.mesh.material[0].color.set(getAreaColor(item.name))
-          })
-          needReloadColor = []
-        })
       })
     }
 
     function clickArea(mesh, name) {
       if (selectMesh === null) {
-        selectPrevColor = mesh.material[0].color.getHexString();
         gsap.to(mesh.position, {
-          y: 8,
+          y: 5,
           duration: .3
         });
         gsap.to(name.element.style, {
@@ -232,7 +274,7 @@ export default {
           duration: .3
         })
         selectMesh = mesh;
-        selectName = name
+        selectName = name;
       } else if (selectMesh === mesh) {
         gsap.to(selectMesh.position, {
           y: 1.5,
@@ -251,7 +293,7 @@ export default {
           duration: .3
         });
         gsap.to(mesh.position, {
-          y: 8,
+          y: 5,
           duration: .3
         })
         if (selectName) {
@@ -266,17 +308,19 @@ export default {
         })
         prevMesh = selectMesh
         selectMesh = mesh;
-        selectPrevColor = mesh.material[0].color.getHexString();
         selectName = name
       }
       prevMesh && prevMesh.material[0].color.set(`#${selectPrevColor}`)
+      if (selectMesh && mesh.material[0].color.getHexString() !== 'ffffff') {
+        selectPrevColor = mesh.material[0].color.getHexString()
+      }
       selectMesh && selectMesh.material[0].color.set('#ffffff')
     }
   /**
 	 * 根据json生成地图
 	 * @param chinaJson
 	 */
-	function initMap(chinaJson) {
+	async function initMap(chinaJson) {
 		let textureMap=textureLoader.load(`${BASE_URL}/images/map/map_gray.jpg`);
 		let texturedispMap=textureLoader.load(`${BASE_URL}/images/map/map-disp.jpg`);
 		let texturefxMap=textureLoader.load(`${BASE_URL}/images/map/map-fx.jpg`);
@@ -304,11 +348,11 @@ export default {
 			dashed: false,
 			alphaToCoverage: true,
 		} );
-			// 新建一个省份容器:用来存放省份对应的模型和轮廓线
-			const meshArrs = new THREE.Object3D()
-      cacheMap.clear()
+    // 新建一个省份容器:用来存放省份对应的模型和轮廓线
+    const meshArrs = new THREE.Object3D()
+    cacheMap = {}
 			// d3-geo转化坐标
-		const projection = d3.geoMercator().center([107.70084090820312, 29.942008602258]).scale(1740).translate([0, 0]);
+		const projection = d3.geoMercator().center([107.70084090820312, 29.942008602258]).scale(2000).translate([0, 0]);
 		// 遍历省份构建模型
 		chinaJson.features.forEach(elem => {
 			const province = new THREE.Object3D()
@@ -341,6 +385,7 @@ export default {
 						map: textureMap,
 						displacementMap: texturedispMap,
 						displacementScale: .5,
+            color: getAreaColor(properties.name),
 						combine: THREE.MultiplyOperation,
 						transparent: true,
 						opacity: .9,
@@ -367,24 +412,25 @@ export default {
             }
 					})
 					mesh.on('mouseover', () => {
+            // 停止定时任务
+            stop();
+            // 刷新数据
             info.element.innerHTML = props.formatter(mapData.value[properties.name])
-						info.visible = true
+            // container
+            console.log(container, info.element)// 显示节点
+            // const parent = container.getBoundingClientRect()
+            // const sub = info.element.getBoundingClientRect();
+            info.element.style.opacity = 1;
 					})
 					mesh.on('mouseout', () => {
-						info.visible = false
+            info.element.style.opacity = 0;
 					})
 
-          if (material.color.getHexString() === 'ffffff') {
-            needReloadColor.push({
-              mesh,
-              name: properties.name
-            })
-          }
-          cacheMap.set(properties.name, {
+          cacheMap[properties.name] = {
             mesh,
             name,
             info
-          })
+          }
 					//Line2
 					linGeometry.setPositions( positions );
 					linGeometry.setColors( colors );
@@ -405,6 +451,9 @@ export default {
 			map.add(meshArrs)
 		})
 		scene.add(map)
+    return Promise.resolve({
+      cacheMap
+    })
 	}
 
 	function initLightPoint(properties,projection){
@@ -426,9 +475,7 @@ export default {
 	function createTextPoint(x,z,areaName){
 		let tag = document.createElement('div')
 		tag.innerHTML = areaName
-		// tag.className = className
 		tag.style.pointerEvents = 'none'
-		// tag.style.visibility = 'hidden'
 		tag.style.position = 'absolute'
 		tag.style.color = '#fff'
 		let label = new CSS2DObject(tag)
@@ -445,21 +492,20 @@ export default {
 		tag.innerHTML = areaName
 		tag.style.pointerEvents = 'none'
 		tag.style.position = 'absolute'
+    tag.style.top = '-120px'
 		tag.style.border = '1px solid rgba(61, 115, 255, 0.72)'
     tag.style.borderRadius = '4px'
 		tag.style.backgroundColor = '#000000'
 		tag.style.color = '#fff'
+    tag.style.opacity = 0;
 		let label = new CSS2DObject(tag)
-		label.element.innerHTML = ""
-		label.element.style.visibility = 'visible'
-		label.position.set(x,20,z)
-		label.position.z-=3
-		label.visible = false
+		// label.element.style.visibility = 'visible'
+		label.position.set(x,10,z)
+		// label.position.z-=3
+		// label.visible = false
 		scene.add(label)
 		return label;
 	}
-
-
     return {
       mapTestBox
     }
@@ -468,7 +514,9 @@ export default {
 </script>
 
 <template >
-  <div ref="mapTestBox" class="map-chart-3d"></div>
+  <div ref="mapTestBox" class="map-chart-3d">
+    <MapLegend />
+  </div>
 </template>
 
 <style scoped lang='less'>

+ 2 - 0
app/src/shared/index.js

@@ -0,0 +1,2 @@
+export * from './mapInfoTemplate.js'
+export * from './mapData.js'

+ 70 - 0
app/src/shared/mapData.js

@@ -0,0 +1,70 @@
+import { getDtskgzList } from "@/api/index.js";
+import { getChartMapData } from '@/api/area.js';
+import { formatCityData } from "@/utils";
+
+const LEGEND_COLOR = ['红色', '橙色', '黄色', '蓝色', '绿色']
+const DEFAULT_WORD_MAP = {
+  '红色': '高风险',
+  '橙色': '较高风险',
+  '黄色': '中风险',
+  '蓝色': '较低风险',
+  '绿色': '低风险'
+}
+const MAP_TYPE = {
+  红色: 90,
+  橙色: 70,
+  黄色: 50,
+  蓝色: 30,
+  绿色: 10,
+}
+
+export function loadMapData(selectMapType) {
+  return new Promise((resolve, reject) => {
+    if (selectMapType === 'DEFAULT') {
+      getDtskgzList({
+        pageNum: 1,
+        pageSize: 42,
+      }).then((res) => {
+        let tempData = res.data.rows;
+        const legendData = LEGEND_COLOR.map(color => {
+          const number = tempData.filter(item => item.分区颜色 === color).length
+          return {
+            name: DEFAULT_WORD_MAP[color],
+            count: number
+          }
+        })
+        const heatMap = formatCityData(
+          tempData.map((item) => ({
+            name: item.qx,
+            value: MAP_TYPE[item.分区颜色],
+            meta: item,
+          }))
+        );
+        resolve({
+          legendData,
+          heatMap
+        })
+      }).catch(err => reject(err));
+    } else {
+      getChartMapData(selectMapType).then(res => {
+        const legendData = LEGEND_COLOR.map(color => {
+            const a = res.data.list.find(i => i.color === color)
+            return {
+              name: `${a.interval}`,
+              count: a.number
+            }
+          })
+        const heatMap = formatCityData(res.data.qxList.map(item => ({
+          name: item.qx,
+          value: MAP_TYPE[item.color],
+          meta: item
+        })))
+
+        resolve({
+          legendData,
+          heatMap
+        })
+      }).catch(err => reject(err));
+    }
+  })
+}

+ 397 - 0
app/src/shared/mapInfoTemplate.js

@@ -0,0 +1,397 @@
+import { createMapChartWindowInfo } from "@/utils";
+
+/**
+ * 总览默认地图消息弹窗模板
+ * @param {*} params
+ * @returns
+ */
+function DEFAULT(params) {
+  const item = params.data.meta;
+  let res = `
+  <table>
+    <tr >
+      <td style="padding-bottom:8px;">${
+        item.区域
+      } 第<span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.区域排名 || 0
+  }</span>名</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>直接财产损失 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${Math.ceil(
+        (item.直接财产损失 || 0) / 10000
+      )}</span>万元</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>火灾起数 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.火灾起数 || 0
+      }</span>起</td>
+      <td>亡人数 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.亡人数 || 0
+      }</span>人</td>
+    </tr>
+    <tr>
+      <td>重大风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.重大风险 || 0
+      }</span>栋</td>
+      <td>较大风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.较大风险 || 0
+      }</span>栋</td>
+    </tr>
+    <tr>
+      <td>一般风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.一般风险 || 0
+      }</span>栋</td>
+      <td>低风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
+        item.低风险 || 0
+      }</span>栋</td>
+    </tr>
+  </table>
+  `;
+  return res;
+}
+
+/**
+ * 超高层建筑
+ * @param {*} params
+ * @returns
+ */
+function CGCJZ(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">超高层建筑 <span style="font-size: 24px;color:red;font-weight:bold;">${
+      item.sl || 0
+          }</span>栋</ps>`
+}
+
+/**
+ * 高层建筑
+ * @param {*} params
+ * @returns
+ */
+function GCJZ(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">高层建筑 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>栋</ps>`
+}
+
+
+/**
+ * 一般风险数
+ * @param {*} params
+ * @returns
+ */
+function YBFX(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">一般风险 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>个</ps>`
+}
+/**
+ * 重大风险数
+ * @param {*} params
+ * @returns
+ */
+function ZDFX(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">重大风险 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>栋</ps>`
+}
+/**
+ * 较大风险数
+ * @param {*} params
+ * @returns
+ */
+function JDFX(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">较大风险 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>栋</ps>`
+}
+
+/**
+ * 低风险数
+ * @param {*} params 
+ * @returns 
+ */
+function DFX(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">低风险 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>栋</ps>`
+}
+/**
+ * 未整改隐患数
+ * @param {*} params 
+ * @returns 
+ */
+function WZGYHS(params) {
+  const item = params.data.meta;
+  return  `<p style="color: #fff;">未整改隐患 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>个</ps>`
+}
+
+ /**
+ * 无管理主体
+ */
+ function WGLZT(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">无管理主体 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>个</ps>`
+ }
+ /**
+  * 无维保形式
+  */
+ function WWBXS(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">无维保形式 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>个</ps>`
+ }
+ /**
+  * 无大修基金(消防设施有问题)
+  */
+ function WDXJJ(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">无大修基金(消防设施有问题) <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>个</ps>`
+ }
+ /**
+  * 接入物联网建筑数
+  */
+ function WLWJZS(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">接入物联网建筑 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>栋</ps>`
+ }
+ /**
+  * 告警数
+  */
+ function GJS(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">告警数 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>个</ps>`
+ }
+ /**
+  * 火灾起数月
+  */
+ function HZQSY(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">(本月)火灾起数 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>起</ps>`
+ }
+ /**
+  * 火灾起数年
+  */
+ function HZQSN(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">(本年)火灾起数 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+  }</span>起</ps>`
+ }
+ /**
+  * 接入物联网楼栋数
+  */
+ function WLWLDS(params) {
+  const item = params.data.meta;
+  return `<p style="color: #fff;">接入物联网楼栋 <span style="font-size: 24px;color:red;font-weight:bold;">${
+    item.sl || 0
+          }</span>栋</ps>`
+ }
+
+const MAP_INFO_TEMPLATE = {
+  DEFAULT,
+  CGCJZ,
+  GCJZ,
+  YBFX,
+  ZDFX,
+  JDFX,
+  DFX,
+  WZGYHS,
+  /**
+ * 无管理主体
+ */
+  WGLZT,
+  /**
+   * 无维保形式
+   */
+  WWBXS,
+  /**
+   * 无大修基金(消防设施有问题)
+   */
+  WDXJJ,
+  /**
+   * 接入物联网建筑数
+   */
+  WLWJZS,
+  /**
+   * 告警数
+   */
+  GJS,
+  /**
+   * 火灾起数月
+   */
+  HZQSY,
+  /**
+   * 火灾起数年
+   */
+  HZQSN,
+  /**
+   * 接入物联网楼栋数
+   */
+  WLWLDS
+}
+
+
+
+export function createInfoWindow(templateType,params) {
+  return createMapChartWindowInfo({
+    title: params.name,
+  },
+  () => MAP_INFO_TEMPLATE[templateType](params)
+  )
+}
+
+
+export const TEMPLATE_TYPE = {
+  /**
+   * 总览默认
+   */
+  DEFAULT: 'DEFAULT',
+  /**
+   * 超高层建筑
+   */
+  CGCJZ: 'CGCJZ',
+  /**
+   * 高层建筑
+   */
+  GCJZ: 'GCJZ',
+  /**
+   * 一般风险
+   */
+  YBFX: 'YBFX',
+  /**
+   * 重大风险
+   */
+  ZDFX: 'ZDFX',
+  /**
+   * 较大风险
+   */
+  JDFX: 'JDFX',
+  /**
+   * 低风险
+   */
+  DFX: 'DFX',
+  /**
+   * 未整改隐患数
+   */
+  WZGYHS: 'WZGYHS',
+  /**
+   * 无管理主体
+   */
+  WGLZT: 'WGLZT',
+  /**
+   * 无维保形式
+   */
+  WWBXS: 'WWBXS',
+  /**
+   * 无大修基金(消防设施有问题)
+   */
+  WDXJJ: 'WDXJJ',
+  /**
+   * 接入物联网建筑数
+   */
+  WLWJZS: 'WLWJZS',
+  /**
+   * 告警数
+   */
+  GJS: 'GJS',
+  /**
+   * 火灾起数月
+   */
+  HZQSY: 'HZQSY',
+  /**
+   * 火灾起数年
+   */
+  HZQSN: 'HZQSN',
+  /**
+   * 接入物联网楼栋数
+   */
+  WLWLDS: 'WLWLDS'
+}
+
+
+export const TITLE_MAP = {
+  /**
+   * 总览默认
+   */
+  DEFAULT: 'DEFAULT',
+  /**
+   * 超高层建筑
+   */
+  CGCJZ: '超高层建筑数分布',
+  /**
+   * 高层建筑
+   */
+  GCJZ: '高层建筑数分布',
+  /**
+   * 一般风险
+   */
+  YBFX: '一般风险楼栋数分布',
+  /**
+   * 重大风险
+   */
+  ZDFX: '重大风险楼栋数分布',
+  /**
+   * 较大风险
+   */
+  JDFX: '较大风险楼栋数分布',
+  /**
+   * 低风险
+   */
+  DFX: '低风险楼栋数分布',
+  /**
+   * 未整改隐患数
+   */
+  WZGYHS: '未整改隐患数分布',
+  /**
+   * 无管理主体
+   */
+  WGLZT: '无管理主体楼栋数分布',
+  /**
+   * 无维保形式
+   */
+  WWBXS: '无维保形式栋数分布',
+  /**
+   * 无大修基金(消防设施有问题)
+   */
+  WDXJJ: '无大修基金(消防设施有问题)栋数分布',
+  /**
+   * 接入物联网建筑数
+   */
+  WLWJZS: '接入物联网建筑数分布',
+  /**
+   * 告警数
+   */
+  GJS: '接入物联网告警数分布',
+  /**
+   * 火灾起数月
+   */
+  HZQSY: '本月火灾起数分布',
+  /**
+   * 火灾起数年
+   */
+  HZQSN: '年火灾起数分布',
+  /**
+   * 接入物联网楼栋数
+   */
+  WLWLDS: '接入物联网楼栋数分布'
+}

+ 3 - 1
app/src/utils/index.js

@@ -95,7 +95,9 @@ export const formatCityData = (data) =>  {
     let temp = data.find(i => i.name === item)
     return temp ? temp : {
       name: item,
-      value: 0
+      value: 0,
+      分区颜色: '绿色',
+      color: '绿色'
     }
   })
 }

+ 2 - 1
app/src/views/Home/components/AutonomousManagement/Maintenance3D.vue

@@ -393,7 +393,8 @@ function getPie3D(pieData, internalDiameterRatio) {
     <ul class="legend">
       <li v-for="(legend,idx) in legendItems"  @click="$emit('click-item', legend.name)" :style="{
         '--bg': legend.color
-      }"  :key="idx">{{ legend.name }}
+      }"  :key="idx">
+      <span @click.stop="$emit('click-label', legend.name)" >{{ legend.name }}</span>
       <span style="color:rgb(68, 241, 255); font-size: 13px;">{{ showValue(legend.name) }}</span>
     </li>
     </ul>

+ 2 - 1
app/src/views/Home/components/AutonomousManagement/Overhaul3D.vue

@@ -386,7 +386,8 @@ function getPie3D(pieData, internalDiameterRatio) {
     <ul class="legend">
       <li v-for="(legend,idx) in legendItems" @click="$emit('click-item', legend.name)" :style="{
         '--bg': legend.color
-      }"  :key="idx">{{ legend.name }}
+      }"  :key="idx">
+      <span @click.stop="$emit('click-label', legend.name)" >{{ legend.name }}</span>
       <span style="color:rgb(68, 241, 255); font-size: 13px;">{{ showValue(legend.name) }}</span>
     </li>
     </ul>

+ 2 - 1
app/src/views/Home/components/AutonomousManagement/PieChart3D.vue

@@ -396,7 +396,8 @@ function getPie3D(pieData, internalDiameterRatio) {
     <ul class="legend" >
       <li v-for="(legend,idx) in legendItems"  @click="$emit('click-item', legend.name)" :style="{
         '--bg': legend.color
-      }"  :key="idx">{{ legend.name }}
+      }"  :key="idx">
+      <span @click.stop="$emit('click-label', legend.name)" >{{ legend.name }}</span>
       <span style="color:rgb(68, 241, 255); font-size: 13px;">{{ showValue(legend.name) }}</span>
     </li>
     </ul>

+ 7 - 3
app/src/views/Home/components/AutonomousManagement/index.vue

@@ -123,15 +123,19 @@ export default {
       </button-group>
     </div>
     <div>
-      <PieChart3D  @click-item="value => $emit('click-item', {
+      <PieChart3D  @click-label="e => e === '无管理主体' && $emit('click-label', 'WGLZT')"  @click-item="value => $emit('click-item', {
         index: 0,
         value
       })" v-if="flag == 0" :glxsList="glxsList" />
-      <Maintenance3D @click-item="value => $emit('click-item', {
+      <Maintenance3D 
+      @click-label="e => e === '无维保' && $emit('click-label', 'WWBXS')"
+      @click-item="value => $emit('click-item', {
         index: 1,
         value
       })" v-if="flag == 1" :wbxsList="wbxsList" />
-      <Overhaul3D @click-item="value => $emit('click-item', {
+      <Overhaul3D 
+      @click-label="e => e === '无(消防设施有问题)' && $emit('click-label', 'WDXJJ')" 
+      @click-item="value => $emit('click-item', {
         index: 2,
         value
       })"   v-if="flag == 2" :dxjjList="dxjjList" />

+ 8 - 4
app/src/views/Home/components/BasicInfo.vue

@@ -46,7 +46,6 @@ export default {
               this.allNum = item.gyjz + item.zzjz + item.ggjz;
             });
             this.listGids=res.data.rows[0]
-       
           }
         }
       );
@@ -57,6 +56,9 @@ export default {
     showModlus(name) {
       this.$emit("showTc", name);
     },
+    onClickLabel(label) {
+      this.$emit('click-label', label)
+    }
   },
   created() {
     this.BasicInfo();
@@ -67,7 +69,7 @@ export default {
 <template>
   <div class="basic-info">
     <div class="__left">
-      <FirstHight :BasicLsit="BasicLsit" :allNum="allNum" />
+      <FirstHight @click-chart="onClickLabel('GCJZ')" :BasicLsit="BasicLsit" :allNum="allNum" />
       <ul style="display: flex; flex-wrap: wrap; justify-content: space-between; font-size: 14px;">
         <li @click="showModlus('住宅建筑')">
           <span
@@ -128,13 +130,14 @@ export default {
         fontSize="16px"
       />
       <div class="basic-total">
-        <div   @click="ToType('超高层建筑总数(栋)')">
+        <div >
           <BasicTotal
             style="width: 187px"
             :number="Number(this.unitcNum)"
             label="超高层建筑"
             unit="栋"
-          
+            @click-label="onClickLabel('CGCJZ')"
+            @click-number="ToType('超高层建筑总数(栋)')"
           />
         </div>
         <div @click="ToType('2000年底前老旧住宅建筑总数(栋)')">
@@ -143,6 +146,7 @@ export default {
             :number="Number(this.unitgNum)"
             label=""
             unit="栋"
+          
           >
             <template #label>
               <span class="label">

+ 1 - 1
app/src/views/Home/components/FireIndex/index.vue

@@ -8,7 +8,7 @@
           <span class="fire-num">{{ tbData.hzqs }}</span>
           <span>起</span>
         </div>
-        <div>火灾总数</div>
+        <div @click.stop="$emit('click-label')" style="cursor: pointer;">火灾总数</div>
       </div>
       <div>
         <img v-if="tbData.hzqstb > 0" src="../../../../assets/images/Vector (1).png" alt="" />

+ 1 - 1
app/src/views/Home/components/FirstHight.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div @click="$emit('click-chart')" >
     <div ref="chart" class="item" style="width: 220px; height: 200px" />
   </div>
 </template>

+ 1 - 0
app/src/views/Home/components/HiddenDangerDetection/index.vue

@@ -10,6 +10,7 @@
           :wzgsNum="wzgsNum"
           :yzgsNum="yzgsNum"
           :qy="qy"
+          @click-label="e => $emit('click-label', e)"
         />
       </div>
       <div class="item">

+ 5 - 3
app/src/views/Home/components/HiddenDangerDetection/pcNum.vue

@@ -16,9 +16,11 @@
           <span>已整改数</span>
           <hidden-danger-total :number="yzgsNum" label="" unit="栋/条"  />
         </div>
-        <div class="hidden-danger-detection_top_inner" @click="openModal(['待计划', '待整改'])" style="cursor: pointer;">
-          <span>未整改数</span>
-          <hidden-danger-total :number="wzgsNum" label="" unit="栋/条" />
+        <div class="hidden-danger-detection_top_inner" style="cursor: pointer;">
+          <span @click="$emit('click-label', 'WZGYHS')">未整改数</span>
+          <div @click="openModal(['待计划', '待整改'])" >
+            <hidden-danger-total :number="wzgsNum" label="" unit="栋/条" />
+          </div>
         </div>
       </div>
     </div>

+ 23 - 7
app/src/views/Home/components/NewMapChartsCategory.vue

@@ -1,14 +1,16 @@
 <template>
-  <div style="position: relative; width: 100%; height: 95%;">
+  <div style="position: relative; width: 100%; height: 632px;">
     <div class="map-box" ref="map"></div>
-    <img class="imgs" src="../../../assets/images/dd_wh.png" alt="" @click="getShoeInfo('whFxModal')">
     <basic-modal top="30px" ref="whFxModal" name="区域高层建筑消防安全风险分色判定标准" width="90%">
 
         <div style="display: flex; justify-content: center;">
           <img  src="../../../assets/images/map-tip.png" />
         </div>
+        <!-- <div v-html="textInfo"></div> -->
     </basic-modal>
-    <div class="legend">
+    <div class="legend" :style="{
+      right: `${right}px`
+    }">
       <div  v-for="(item, index) in legend" :key="index"
       class="legend-item1">
       <div class="name">{{item.name}}</div>
@@ -17,8 +19,10 @@
       <div class="count">{{item.count}}个区县</div>
     </div>
     </div>
+    <img v-if="showTip" class="imgs" src="../../../assets/images/dd_wh.png" alt="" @click="getShoeInfo('whFxModal')">
   </div>
   <!-- 风险问号弹窗 -->
+  
 </template>
 
 <script>
@@ -44,6 +48,14 @@ export default {
         return res;
       }
     },
+    showTip: {
+      type: Boolean,
+      default: false
+    },
+    right: {
+      type: Number,
+      default: 50
+    },
     legend: {
       type: Array,
       default: () => [
@@ -253,7 +265,7 @@ export default {
       ],
       mapChart: null,
       mapType: {
-        '红色': '#ff0b0ba0',
+        '红色': '#ff0b0b',
         '橙色': '#ff833d',
         '黄色': '#fbff3d',
         '蓝色': '#35c2ff',
@@ -583,17 +595,20 @@ export default {
 };
 </script>
 <style scoped>
+
+
 .legend {
   position: absolute;
   bottom: 30px;
   right: 20px;
 }
-.legend-item1 {
+.legend-item1{
   display: flex;
   align-items: center;
   gap: 5px;
   .count {
     color: #fff;
+    width: 50px;
   }
   .name {
     width: 60px;
@@ -619,6 +634,7 @@ export default {
     }
   }
 }
+
 .map-box {
   width: 100%;
   /* height: 98%; */
@@ -627,8 +643,8 @@ export default {
 }
 .imgs{
  position: absolute;
- right: 63px;
- bottom: 0px;
+ right: 70px;
+ bottom: 5px;
  cursor: pointer;
 }
 </style>

+ 5 - 5
app/src/views/Home/components/RiskWarning.vue

@@ -92,8 +92,8 @@
       <div
         style="display: flex; flex-wrap: wrap; justify-content: space-around"
       >
-        <div class="card">
-          <div class="left-card">
+        <div class="card" >
+          <div class="left-card" @click="$emit('click-label', 'ZDFX')">
             <div class="card-item">重大风险</div>
           </div>
           <div class="right-card" @click="showStice('重大风险')">
@@ -101,7 +101,7 @@
           </div>
         </div>
         <div class="card">
-          <div class="left-card" style="background: #ff833d">
+          <div class="left-card" @click="$emit('click-label', 'JDFX')" style="background: #ff833d">
             <div class="card-item">较大风险</div>
           </div>
           <div class="right-card" @click="showStice('较大风险')">
@@ -109,7 +109,7 @@
           </div>
         </div>
         <div class="card">
-          <div class="left-card" style="background: #fbff3d">
+          <div class="left-card" @click="$emit('click-label', 'YBFX')" style="background: #fbff3d">
             <div class="card-item">一般风险</div>
           </div>
           <div class="right-card" @click="showStice('一般风险')">
@@ -117,7 +117,7 @@
           </div>
         </div>
         <div class="card">
-          <div class="left-card" style="background: #35c2ff">
+          <div class="left-card" @click="$emit('click-label', 'DFX')" style="background: #35c2ff">
             <div class="card-item">低风险</div>
           </div>
           <div class="right-card" @click="showStice('低风险(蓝色)')">

+ 5 - 2
app/src/views/Home/components/WisdomFire.vue

@@ -5,8 +5,9 @@
       <div class="build-num">
         <div class="build-all">
           <span
+          @click="$emit('click-label', 'WLWJZS')" style="cursor: pointer;"
             ><img src="@/assets/images/Vector (3).png" alt="" />
-            <span>已接入物联网建筑数</span>
+            <span >已接入物联网建筑数</span>
           </span>
           <span class="num">{{ iotList?.wlwlds }}</span>
           <span class="build-line">栋</span>
@@ -25,7 +26,9 @@
               >个
             </span>
             <span
-              >告警
+              >
+              <span  @click="$emit('click-label', 'GJS')" style="cursor: pointer;">告警</span>
+
               <span class="warning">{{
                 iotList?.jrsbgjgs ? iotList?.jrsbgjgs : 0
               }}</span

+ 62 - 87
app/src/views/Home/index.vue

@@ -5,12 +5,11 @@
         height="302px"
         style="margin-bottom: 6px; cursor: pointer"
         title="基础信息"
-        @click="openBasicModal"
       >
-        <BasicInfo :qy="qy" @showTc="showTc" @UnitType="UnitType" />
+        <BasicInfo :qy="qy" @click-label="reloadMap"  @showTc="showTc" @UnitType="UnitType" />
       </border-panel>
       <border-panel height="346px" style="margin-bottom: 6px" title="隐患排查">
-        <HiddenDangerDetection :qy="qy" />
+        <HiddenDangerDetection @click-label="reloadMap" :qy="qy" />
       </border-panel>
       <border-panel
         height="293px"
@@ -19,6 +18,7 @@
         @click-header="openAutoManageModal"
       >
         <AutonomousManagement
+          @click-label="reloadMap"
           @click-item="onClickAutonomousManagementItemHandler"
           :qy="qy"
         />
@@ -26,24 +26,31 @@
     </div>
     <div class="display: flex;">
       <div class="map" style="position: relative">
-        <!-- <MapChartsCategory
+        <MapChartsCategory
           :mapHeatData="heatMap"
           :formatter="showLabel"
           :qx="qy"
+          :legend="legendData"
           @selectArea="(area) => (qy = area)"
-        /> -->
-        <div style="position: relative; width: 100%; height: 632px;">
+          :right="20"
+          showTip
+        />
+        <!-- <div style="position: relative; width: 100%; height: 632px;">
           <MapChart3D
             :mapHeatData="heatMap"
             :formatter="showLabel"
             :qx="qy"
             @selectArea="(area) => (qy = area)"
           />
-        </div>
+        </div> -->
         <div style="position: absolute; top: 10px; width: 500px">
-          <SearchBox :area="qy" @update:area="e => qy = e" />
+          <SearchBox :area="qy"  @update:area="e => qy = e" />
         </div>
         <div class="tips" @click="getShoeInfo('smsMsgModal')">提示</div>
+        <div class="title" v-if="selectMapType !== 'DEFAULT'">
+          <div class="back-btn" @click="reloadMap('DEFAULT')">{{ '<' }}</div>
+          <div class="select-title">{{selectMapTitle}}</div>
+        </div>
       </div>
       <div>
         <border-panel
@@ -52,7 +59,7 @@
           title="火灾指数"
           :header-type="1"
         >
-          <FireIndex :type="fireIndexType" :qx="qy" />
+          <FireIndex @click-label="onClockFireIndex" :type="fireIndexType" :qx="qy" />
           <template #ext-header>
             <button-block
               :items="['月', '年']"
@@ -76,6 +83,7 @@
           :qy="qy"
           :monthData="monthData"
           :typeList="typeList"
+          @click-label="reloadMap"
         />
         <template #ext-header>
           <img
@@ -90,7 +98,7 @@
         style="margin-bottom: 6px; cursor: pointer"
         title="物联感知"
       >
-        <WisdomFire :frieList="frieList" :iotList="iotList" :qy="qy" />
+        <WisdomFire @click-label="reloadMap" :frieList="frieList" :iotList="iotList" :qy="qy" />
         <ZhxfModalHeader slot="title" />
       </border-panel>
       <border-panel title="警情动态" height="298px" :header-type="1">
@@ -135,17 +143,17 @@ import BasicInfoModalContent from "./components/BasicInfoModalContent.vue";
 import SearchBox from "@/components/SearchBox.vue";
 import zzglModul from "./components/zzglModul.vue";
 import { getSxzbListToatl,getFhzdType } from "@/api/index.js";
+import { getSxzbListToatl } from "@/api/index.js";
+
 import {
   totaldata,
   getJqdt,
   getZxgjtj,
-  getJrjzsbs,
-  getDtskgzList,
+  getJrjzsbs
 } from "@/api/index.js";
-import { fxfb } from "@/api/risk";
-import { formatCityData, createMapChartWindowInfo } from "@/utils";
 import MessageTipModalContent from "@/components/MessageTipModalContent.vue";
 import MapChart3D from '@/components/MapChart3D/index.vue'
+import { createInfoWindow, TEMPLATE_TYPE, loadMapData, TITLE_MAP } from '@/shared'
 
 export default {
   name: "HomePage",
@@ -182,21 +190,22 @@ export default {
       heatMap: [],
       defaultModel: {},
       monthData: [],
-      mapType: {
-        红色: 90,
-        橙色: 70,
-        黄色: 50,
-        蓝色: 30,
-        绿色: 10,
-      },
       queryParams: {
         glxs: "", //管理形式
         wbxs: "", //维保形式
         dxjj: "", //大修基金
       },
+      selectMapType: TEMPLATE_TYPE.DEFAULT,
+      legendData: [],
+      TEMPLATE_TYPE,
       typeList:[]
     };
   },
+  computed: {
+    selectMapTitle() {
+      return TITLE_MAP[this.selectMapType]
+    }
+  },
   watch: {
     qy() {
       this.getList();
@@ -206,6 +215,14 @@ export default {
     },
   },
   methods: {
+    onClockFireIndex() {
+      this.reloadMap(["HZQSY", "HZQSN"][this.fireIndexType])
+    },
+    reloadMap(type) {
+      if (this.selectMapType === type) return;
+      this.selectMapType = type;
+      this.loadData()
+    },
     onCloseModal() {
       this.closeModal("smsMsgModal");
     },
@@ -230,57 +247,7 @@ export default {
       this.showModal("autoManageModal");
     },
     showLabel(params) {
-      return createMapChartWindowInfo(
-        {
-          title: params.name,
-        },
-        () => {
-          const item = params.meta;
-          let res = `
-          <table>
-            <tr >
-              <td style="padding-bottom:8px;">${
-                item.区域
-              } 第<span style="font-size: 24px;color:red;font-weight:bold;">${
-            item.区域排名 || 0
-          }</span>名</td>
-              <td></td>
-            </tr>
-            <tr>
-              <td>直接财产损失 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${Math.ceil(
-                (item.直接财产损失 || 0) / 10000
-              )}</span>万元</td>
-              <td></td>
-            </tr>
-            <tr>
-              <td>火灾起数 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.火灾起数 || 0
-              }</span>起</td>
-              <td>亡人数 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.亡人数 || 0
-              }</span>人</td>
-            </tr>
-            <tr>
-              <td>重大风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.重大风险 || 0
-              }</span>栋</td>
-              <td>较大风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.较大风险 || 0
-              }</span>栋</td>
-            </tr>
-            <tr>
-              <td>一般风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.一般风险 || 0
-              }</span>栋</td>
-              <td>低风险 <span style="font-size: 24px;color:#ffb800;font-weight:400;">${
-                item.低风险 || 0
-              }</span>栋</td>
-            </tr>
-          </table>
-          `;
-          return res;
-        }
-      );
+      return createInfoWindow(this.selectMapType, params);
     },
     showTc(val) {
       if (val) {
@@ -372,20 +339,11 @@ export default {
       openAutoManageModal() {
       this.showModal("autoManageModal");
     },
-    loadMapData() {
-      getDtskgzList({
-        pageNum: 1,
-        pageSize: 42,
-      }).then((res) => {
-        let tempData = res.data.rows;
-        this.heatMap = formatCityData(
-          tempData.map((item) => ({
-            name: item.qx,
-            value: this.mapType[item.分区颜色],
-            meta: item,
-          }))
-        );
-      });
+    loadData() {
+      loadMapData(this.selectMapType).then(res => {
+        this.legendData = res.legendData
+        this.heatMap = res.heatMap
+      })
     },
     // 火灾预测
     loadHzzbSxzbYoy() {
@@ -445,7 +403,7 @@ export default {
     this.getStaic();
     this.getFireList();
     this.getIotList();
-    this.loadMapData();
+    this.loadData();
     this.loadHzzbSxzbYoy();
     this.zdType()
   },
@@ -487,4 +445,21 @@ export default {
   padding: 10px 20px;
   cursor: pointer;
 }
+
+.title {
+  position: absolute;
+  top: 60px;
+  left: 5px;
+  box-sizing: border-box;
+  padding: 10px 20px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  font-size: 20px;
+  .back-btn {
+    margin-right: 10px;
+  }
+  .select-title {
+  }
+}
 </style>