智慧园区前端大屏
shuishen
2024-11-14 e3a52e98105434d0be6a12a7db9ef1093c0c2ab2
突发事件模拟相关
7 files modified
9 files deleted
1 files added
987 ■■■■ changed files
src/hooks/initMap.js 4 ●●●● patch | view | raw | blame | history
src/pages/first/components/mainMenu.vue 2 ●●● patch | view | raw | blame | history
src/pages/layout/components/scomponents/layersControl.vue 12 ●●●● patch | view | raw | blame | history
src/router/index.js 2 ●●● patch | view | raw | blame | history
src/styles/base/dc-base.scss 93 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/dataContent.vue 158 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/fireContent.vue 25 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/fireSource.vue 25 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/fireTrend.vue 25 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/occurStatistics.vue 25 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/publicContent.vue 26 ●●●●● patch | view | raw | blame | history
src/views/pd/components/box/unitContent.vue 25 ●●●●● patch | view | raw | blame | history
src/views/pd/components/dynamicPanel.vue 373 ●●●●● patch | view | raw | blame | history
src/views/pd/components/leftContainer.vue 47 ●●●●● patch | view | raw | blame | history
src/views/pd/components/rightContainer.vue 86 ●●●●● patch | view | raw | blame | history
src/views/pd/index.vue 50 ●●●● patch | view | raw | blame | history
vite.config.js 9 ●●●● patch | view | raw | blame | history
src/hooks/initMap.js
@@ -2,7 +2,7 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2024-10-25 15:09:55
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2024-11-09 19:55:21
 * @LastEditTime: 2024-11-13 16:37:17
 * @FilePath: \bigScreen\src\hooks\initMap.js
 * @Description: 
 * 
@@ -30,7 +30,7 @@
      }).then(() => {
        viewer = new DC.Viewer('viewer-container')
        viewer.locationBar.enable = true
        window.$viewer = viewer
        window.$viewer.zoomToPosition(new DC.Position(
src/pages/first/components/mainMenu.vue
@@ -44,7 +44,7 @@
      path: '/layout/first/rt'
    },
    {
      menuName: '污染物处理',
      menuName: '突发事件模拟',
      path: '/layout/first/pd'
    },
  ]
src/pages/layout/components/scomponents/layersControl.vue
@@ -2,7 +2,7 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2024-10-31 10:47:29
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2024-11-12 18:15:54
 * @LastEditTime: 2024-11-13 19:20:17
 * @FilePath: \bigScreen\src\pages\layout\components\scomponents\layersControl.vue
 * @Description:
 *
@@ -463,7 +463,7 @@
          addTileLayers[item.layerName] = new DC.VectorLayer(item.layerName)
          window.$viewer.addLayer(addTileLayers[item.layerName])
          function computeCircle(radius) {
          function computeCircle (radius) {
            var positions = []
            for (var i = 0; i < 1080; i++) {
              var radians = DC.Math.toRadians(i)
@@ -506,7 +506,7 @@
  })
}
function findObjectById(data, id) {
function findObjectById (data, id) {
  // 遍历数据数组
  for (let i = 0; i < data.length; i++) {
    const item = data[i]
@@ -558,7 +558,7 @@
  handleCheckChange(data.filter(i => indexPoint.value.includes(i.id)))
})
const sharedData = computed(() => pointStore.sharedData);
const sharedData = computed(() => pointStore.sharedData)
// 
watch(sharedData, (newValue) => {
  let companyInfo = JSON.parse(localStorage.getItem('companyInfo'))
@@ -576,13 +576,13 @@
    return
  }
  // 处理切换到应急空间页面,把图标显示
  console.log('sharedData changed to:', newValue);
  console.log('sharedData changed to:', newValue)
  // 获取缓存里面的企业id
  indexPoint.value.includes(newValue) ? '' : indexPoint.value.push(newValue)
  let checkList = data.filter(i => indexPoint.value.includes(i.id))
  treeRef.value?.setCheckedNodes(checkList)
  handleCheckChangeTwo(checkList, companyInfo.id)
});
})
const handleCheckChangeTwo = (data, firmId) => {
  let options = treeRef.value?.getCheckedNodes()
src/router/index.js
@@ -85,7 +85,7 @@
          {
            path: 'pd',
            meta: {
              title: '污染物处理'
              title: '突发事件模拟'
            },
            component: () => import('@/views/pd/index.vue')
          },
src/styles/base/dc-base.scss
@@ -70,4 +70,97 @@
      height: 24px;
    }
  }
}
@keyframes pulse-glow {
  0% {
    box-shadow: 0 0 4px red, inset 0 0 4px red;
  }
  50% {
    box-shadow: 0 0 8px red, inset 0 0 8px red;
  }
  100% {
    box-shadow: 0 0 4px red, inset 0 0 4px red;
  }
}
.dynamic-map-popup {
  position: absolute;
  right: 100%;
  bottom: 0;
  width: 320px;
  color: #fff;
  background: rgba(255, 0, 0, 0.2);
  font-weight: bold;
  font-style: italic;
  &::after {
    content: '';
    position: absolute;
    top: -0.8px;
    /* 调整以匹配所需的发光区域 */
    left: 0px;
    /* 同上 */
    right: 0px;
    bottom: calc(100% - 0.8px);
    background: white;
    box-shadow: 0 0 8px red, inset 0 0 8px red;
    animation: pulse-glow 3s infinite;
  }
  &::before {
    content: '';
    position: absolute;
    top: calc(100% - 0.8px);
    /* 调整以匹配所需的发光区域 */
    left: 0px;
    /* 同上 */
    right: 0px;
    bottom: -0.8px;
    background: white;
    box-shadow: 0 0 8px red, inset 0 0 8px red;
    animation: pulse-glow 3s infinite;
  }
  .title {
    position: relative;
    height: 30px;
    line-height: 30px;
    font-size: 18px;
    &::before {
      content: '';
      position: absolute;
      top: calc(100% - 0.8px);
      /* 调整以匹配所需的发光区域 */
      left: 0px;
      /* 同上 */
      right: 40%;
      bottom: -0.8px;
      background: white;
      box-shadow: 0 0 8px red, inset 0 0 8px red;
      animation: pulse-glow 3s infinite;
    }
  }
  .content {
    text-indent: 2em;
    line-height: 28px;
  }
}
.widget.location-bar {
  position: absolute;
  left: 620px !important;
  bottom: 120px !important;
  font-size: 14px;
  color: #fff;
  background: #0009;
  padding: 2px 5px;
  border-radius: 2px;
  user-select: none;
  display: flex;
}
src/views/pd/components/box/dataContent.vue
File was deleted
src/views/pd/components/box/fireContent.vue
File was deleted
src/views/pd/components/box/fireSource.vue
File was deleted
src/views/pd/components/box/fireTrend.vue
File was deleted
src/views/pd/components/box/occurStatistics.vue
File was deleted
src/views/pd/components/box/publicContent.vue
File was deleted
src/views/pd/components/box/unitContent.vue
File was deleted
src/views/pd/components/dynamicPanel.vue
New file
@@ -0,0 +1,373 @@
<!--
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2024-11-09 15:41:35
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2024-11-14 16:58:49
 * @FilePath: \bigScreen\src\views\pd\components\dynamicPanel.vue
 * @Description:
 *
 * Copyright (c) 2024 by shuishen, All Rights Reserved.
-->
<script setup>
const emit = defineEmits(['closePanel'])
import { onUnmounted } from 'vue'
const panelData = reactive({
  data: [
    {
      key: 1,
      title: '典型案例1',
      content: '南片区松节油储罐区泄漏事故: 南片区某企业松节油储罐泄漏,如不采取措施,将造成污染事故,影响到赣江下游水质。',
      specificPollutantPosition: {
        lng: 115.10038440,
        lat: 27.27207956
      },
      specificPollutant: '松节油,无色至淡黄色油状液体,具有松香气味。 熔点:/ 沸点:154~170℃相对密度(水=1):0.85~0.87 饱和蒸气压(kPa):2.67(51.4℃)溶解性:不溶于水,溶于乙醇、氯仿、醚等多数有机溶剂。',
      transitPointPosition: {
        lng: 115.10595711,
        lat: 27.26963563
      },
      wastewaterTreatmentPosition: {
        lng: 115.10815397,
        lat: 27.27212251
      },
      wastewaterTreatment: '事故应急结束后,应急指挥部组织专家评估组指导企业对受污染的废水进入废水处理中站进行处理,对公共应急池的事故废水进行水质监测,分析水质达标情况,并研判处理处置方式,在确保安全的情况下转转输至绿源污水处理厂处理。'
    },
    {
      key: 2,
      title: '典型案例2',
      content: '北片区碱类腐蚀性物质泄漏事故: 北片区某企业(位于吉兴路以北)在生产过程中操作失误,大量含碱废水泄漏,如不采取措施,将造成污染事故,影响到赣江下游水质。',
      specificPollutantPosition: {
        lng: 115.10038440,
        lat: 27.27207956
      },
      specificPollutant: '液碱,无色透明液体。是重要的化工基础原料,用途极广。化学工业用于制造甲酸、草酸、硼砂、苯酚、氰化钠及肥皂、合成脂肪酸、合成洗涤剂等,呈碱性。',
      transitPointPosition: {
        lng: 115.10595711,
        lat: 27.26963563
      },
      wastewaterTreatmentPosition: {
        lng: 115.10815397,
        lat: 27.27212251
      },
      wastewaterTreatment: '将拦截废水从应急池中通过北区污水提升泵站转移至绿源污水处理厂进行处置,同时在排口下游展开应急监测,确保废水没有进入周边水系。'
    },
    {
      key: 3,
      title: '典型案例3',
      content: '危险化学品运输事故: 化工集中区北区(吉兴路以南)某企业的危化品运输车辆金工大道危化品运专用运输道上发生侧翻,大量盐酸流至路面,如不采取措施,将造成污染事故,影响到赣江下游水质。',
      specificPollutantPosition: {
        lng: 115.10038440,
        lat: 27.27207956
      },
      specificPollutant: '盐酸是无色液体(工业用盐酸会因有杂质三价铁盐而略显黄色),为氯化氢的水溶液,具有刺激性气味。',
      transitPointPosition: {
        lng: 115.10595711,
        lat: 27.26963563
      },
      wastewaterTreatmentPosition: {
        lng: 115.10815397,
        lat: 27.27212251
      },
      wastewaterTreatment: '对转输至企业应急空间的事故废水进行水质监测,分析水质达标情况,并研判处理处置方式,在确保安全的情况下加药处理或者排入企业废水处理站处理'
    },
  ]
})
let timeO = null
let timeT = null
const dynamicVectorLayer = new DC.VectorLayer('dynamicVectorLayer').addTo(window.$viewer)
const dynamicHtmlLayer = new DC.HtmlLayer('dynamicHtmlLayer').addTo(window.$viewer)
const schemeStart = (item) => {
  emit('closePanel')
  clearAll()
  let center = DC.Position.fromObject(item.specificPollutantPosition)
  let circle = new DC.Circle(center, 20)
  circle.setStyle({
    material: new DC.CircleDiffuseMaterialProperty({
      color: DC.Color.RED.withAlpha(0.2),
      speed: 2.0
    })
  })
  dynamicVectorLayer.addOverlay(circle)
  window.$viewer.flyToPosition(new DC.Position(item.specificPollutantPosition.lng, item.specificPollutantPosition.lat, 400, 0, -90, 0), () => { }, 3)
  let divIcon = new DC.DivIcon(
    new DC.Position(item.specificPollutantPosition.lng, item.specificPollutantPosition.lat, 0),
    `<div class="dynamic-map-popup">
          <div class="title">特征污染物</div>
          <div class="content">
            ${item.specificPollutant}
          </div>
      </div>`
  )
  dynamicHtmlLayer.addOverlay(divIcon)
  timeO = setTimeout(() => {
    window.$viewer.flyToPosition(new DC.Position(item.transitPointPosition.lng, item.transitPointPosition.lat, 400, 0, -90, 0), () => {
      let centerT = DC.Position.fromObject(item.transitPointPosition)
      let circleT = new DC.Circle(centerT, 20)
      circleT.setStyle({
        material: new DC.CircleWaveMaterialProperty({
          color: DC.Color.fromRandom(),
          speed: 20,
          count: 5,
          gradient: 0.5
        })
      })
      dynamicVectorLayer.addOverlay(circleT)
    }, 3)
  }, 5000)
  timeT = setTimeout(() => {
    window.$viewer.flyToPosition(new DC.Position(item.wastewaterTreatmentPosition.lng, item.wastewaterTreatmentPosition.lat, 400, 0, -90, 0), () => {
      let centerThree = DC.Position.fromObject(item.wastewaterTreatmentPosition)
      let circleThree = new DC.Circle(centerThree, 30)
      circleThree.setStyle({
        classificationType: 0,
        material: new DC.CircleSpiralMaterialProperty({
          color: DC.Color.BLUE.withAlpha(0.2),
          speed: 8.0
        })
      })
      dynamicVectorLayer.addOverlay(circleThree)
      let divIconT = new DC.DivIcon(
        new DC.Position(item.wastewaterTreatmentPosition.lng, item.wastewaterTreatmentPosition.lat, 0),
        `<div class="dynamic-map-popup">
              <div class="title">绿源进水口</div>
              <div class="content">
                ${item.wastewaterTreatment}
              </div>
          </div>`
      )
      dynamicHtmlLayer.addOverlay(divIconT)
    }, 3)
  }, 10000)
}
const clearAll = () => {
  clearTimeout(timeO)
  clearTimeout(timeT)
  dynamicVectorLayer.clear()
  dynamicHtmlLayer.clear()
}
onUnmounted(() => {
  clearAll()
  window.$viewer.removeLayer(dynamicVectorLayer)
  window.$viewer.removeLayer(dynamicHtmlLayer)
})
</script>
<template>
  <div class="panel-container no-select">
    <el-carousel :autoplay="false" :interval="4000" type="card" height="360px">
      <el-carousel-item v-for="item, index in panelData.data" :key="index">
        <template #>
          <div class="content-box flex f-d-c">
            <div class="title">
              {{ item.title }}
            </div>
            <div class="content h0 flex-1">
              <div class="bg-box">
              </div>
              <div class="describe-box">
                {{ item.content }}
              </div>
            </div>
            <div class="footer-btn">
              <div class="start-btn" @click="schemeStart(item)">
                开始模拟
              </div>
            </div>
          </div>
        </template>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>
<style scoped lang="scss">
.panel-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  width: 960px;
  height: 440px;
  pointer-events: all;
  ::v-deep(.el-carousel) {
    .el-carousel__item {
      background: #2E4274;
      .content-box {
        padding: 10px 0;
        width: 100%;
        height: 100%;
        color: #fff;
        .title {
          padding-left: 40px;
          height: 80px;
          line-height: 80px;
          font-size: 44px;
          font-weight: bold;
          font-style: initial;
          background: #3a7bd5;
          /* fallback for old browsers */
          background: -webkit-linear-gradient(to right, #3a7bd5, rgba(255, 255, 255, 0.1));
          /* Chrome 10-25, Safari 5.1-6 */
          background: linear-gradient(to right, #3a7bd5, rgba(255, 255, 255, 0.1));
          /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
        }
        .content {
          margin-top: 20px;
          padding: 0 20px;
          .describe-box {
            line-height: 36px;
          }
        }
        .footer-btn {
          margin-bottom: 40px;
          height: 40px;
          line-height: 40px;
          text-align: center;
        }
      }
    }
  }
}
.no-select {
  user-select: none;
  /* Standard syntax */
  -webkit-user-select: none;
  /* Safari/Chrome */
  -moz-user-select: none;
  /* Firefox */
  -ms-user-select: none;
  /* Internet Explorer/Edge */
}
.start-btn,
.start-btn:focus,
.start-btn:hover {
  display: inline-block;
  position: relative;
  min-width: 96px;
  border: none;
  border-radius: 8px;
  background: #491cc5;
  /* fallback for old browsers */
  background: -webkit-linear-gradient(to bottom, #491cc5, #5f80f5);
  /* Chrome 10-25, Safari 5.1-6 */
  background: linear-gradient(to bottom, #491cc5, #5f80f5);
  /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  color: #fff;
  font-size: 1rem;
  font-weight: bold;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
  transition: transform ease-in 0.1s, box-shadow ease-in 0.25s;
  transform: skewX(8deg);
}
.start-btn:before,
.start-btn:after {
  content: "";
  display: block;
  position: absolute;
  width: 140%;
  height: 100%;
  left: -20%;
  z-index: -1000;
  transition: all ease-in-out 0.5s;
  background-repeat: no-repeat;
}
.start-btn:before {
  display: none;
  top: -75%;
  background-image: radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, transparent 20%, #3E56B2 20%, transparent 30%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, transparent 10%, #3E56B2 15%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%);
  background-size: 10% 10%, 20% 20%, 15% 15%, 20% 20%, 18% 18%, 10% 10%, 15% 15%, 10% 10%, 18% 18%;
}
.start-btn:after {
  display: none;
  bottom: -75%;
  background-image: radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, transparent 10%, #3E56B2 15%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%), radial-gradient(circle, #3E56B2 20%, transparent 20%);
  background-size: 15% 15%, 20% 20%, 18% 18%, 20% 20%, 15% 15%, 10% 10%, 20% 20%;
}
.start-btn:active {
  transform: scale(0.9);
  background-color: #5e7ae9;
  box-shadow: 0 2px 25px rgba(94, 122, 233, .2);
}
.start-btn:active:before {
  display: block;
  animation: anim-top ease-in-out 0.75s forwards;
}
.start-btn:active:after {
  display: block;
  animation: anim-bottom ease-in-out 0.75s forwards;
}
@keyframes anim-top {
  0% {
    background-position: 5% 90%, 10% 90%, 10% 90%, 15% 90%, 25% 90%, 25% 90%, 40% 90%, 55% 90%, 70% 90%;
  }
  50% {
    background-position: 0% 80%, 0% 20%, 10% 40%, 20% 0%, 30% 30%, 22% 50%, 50% 50%, 65% 20%, 90% 30%;
  }
  100% {
    background-position: 0% 70%, 0% 10%, 10% 30%, 20% -10%, 30% 20%, 22% 40%, 50% 40%, 65% 10%, 90% 20%;
    background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
  }
}
@keyframes anim-bottom {
  0% {
    background-position: 10% -10%, 30% 10%, 55% -10%, 70% -10%, 85% -10%, 70% -10%, 70% 0%;
  }
  50% {
    background-position: 0% 80%, 20% 80%, 45% 60%, 60% 100%, 75% 70%, 95% 60%, 105% 0%;
  }
  100% {
    background-position: 0% 90%, 20% 90%, 45% 70%, 60% 110%, 75% 80%, 95% 70%, 110% 10%;
    background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
  }
}
</style>
src/views/pd/components/leftContainer.vue
File was deleted
src/views/pd/components/rightContainer.vue
File was deleted
src/views/pd/index.vue
@@ -2,29 +2,59 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2023-03-10 15:27:59
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2023-03-13 16:02:07
 * @FilePath: \forest-fire\src\views\statistics\index.vue
 * @LastEditTime: 2024-11-12 20:02:05
 * @FilePath: \bigScreen\src\views\pd\index.vue
 * @Description: 综合设计
 * 
 * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved. 
-->
<script setup>
import leftContainer from './components/leftContainer.vue'
import rightContainer from './components/rightContainer.vue'
import dynamicPanel from './components/dynamicPanel.vue'
import { CaretLeft, CaretRight } from '@element-plus/icons-vue'
const showPanel = ref(true)
const showPanelChange = () => {
  showPanel.value = !showPanel.value
}
</script>
<template>
    <div class="container page-container">
        <left-container></left-container>
        <!-- <right-container></right-container> -->
  <div class="container page-container">
    <div class="telescopic-panel" @click="showPanelChange">
      <el-icon v-show="showPanel">
        <CaretLeft />
      </el-icon>
      <el-icon v-show="!showPanel">
        <CaretRight />
      </el-icon>
    </div>
    <dynamic-panel v-show="showPanel" @closePanel="showPanelChange"></dynamic-panel>
  </div>
</template>
<style lang="scss" scoped>
.container {
  position: absolute;
  width: 100%;
  height: 100%;
  .telescopic-panel {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    width: 100%;
    height: 100%;
    top: 50%;
    left: 0;
    width: 20px;
    height: 60px;
    border-radius: 0 6px 6px 0;
    box-shadow: inset 0 0 40px #409eff;
    pointer-events: all;
    color: #fff;
    transform: translate(0, -50%);
    cursor: pointer;
  }
}
</style>
vite.config.js
@@ -2,7 +2,7 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2024-10-25 10:56:27
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2024-11-12 14:02:19
 * @LastEditTime: 2024-11-13 19:15:01
 * @FilePath: \bigScreen\vite.config.js
 * @Description: 
 * 
@@ -85,6 +85,13 @@
      //   overlay:false
      // },
      proxy: {
        '/zhyq3Dtile': {
          // target: 'http://localhost',
          target: 'https://wrj.shuixiongit.com/zhyq3Dtile',
          changeOrigin: true,
          rewrite: path => path.replace(/^\/zhyq3Dtile/, ''),
        },
        '/panorama': {
          // target: 'http://localhost',
          target: 'http://vr.jxpskj.com:180',