独墅湖高教创新区危化品智慧管控平台(新危化品)
马宇豪
2025-04-28 e1d380a930e73d8355a4695ca5f5b91f471c2394
src/views/hazardousChemicals/bigScreen/components/midTop.vue
@@ -1,34 +1,74 @@
<template>
  <div class="charts-container">
    <div class="table-wrapper">
      <table class="scrollable-table">
        <thead>
        <tr>
          <th>排名</th>
          <th>企业名称</th>
          <th>危化品仓库</th>
          <th>预警信息</th>
        </tr>
        </thead>
      </table>
      <div class="scroll-viewport" ref="viewport">
        <div class="scroll-content" :style="contentStyle">
          <table class="scrollable-table">
            <tbody>
            <tr v-for="item in companyData" :key="item.id">
              <td>{{ item.rank }}</td>
              <td>{{ item.company }}</td>
              <td>{{ item.warehouse }}</td>
              <td :class="{'warning': item.warning}">{{ item.warning || '无' }}</td>
            </tr>
            <tr v-for="item in loopData" :key="`loop-${item.id}`">
              <td>{{ item.rank }}</td>
              <td>{{ item.company }}</td>
              <td>{{ item.warehouse }}</td>
              <td :class="{'warning': item.warning}">{{ item.warning || '无' }}</td>
            </tr>
            </tbody>
          </table>
    <div class="container-left">
      <div class="filter">
        <el-select
            clearable
            :teleported="false"
            v-model="companyType"
            filterable
            placeholder="请选择企业类型"
            style="flex: 1"
            remote
            remote-show-suffix
            :remote-method="getList"
        >
          <el-option
              v-for="item in typeList"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
        <el-select
            clearable
            :teleported="false"
            v-model="warningType"
            filterable
            placeholder="请选择风险等级"
            style="flex: 1"
            remote
            remote-show-suffix
            :remote-method="getList"
        >
          <el-option
              v-for="item in warningList"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
      </div>
      <div class="table-wrapper">
        <table class="scrollable-table">
          <thead>
          <tr>
            <th>序号</th>
            <th>企业名称</th>
            <th>危化品仓库</th>
            <th>预警信息</th>
          </tr>
          </thead>
        </table>
        <div class="scroll-viewport" ref="viewport">
          <div class="scroll-content" :style="contentStyle">
            <table class="scrollable-table">
              <tbody>
              <tr v-for="(item,index) in companyData" :key="item.id">
                <td>{{ index + 1 }}</td>
                <td>{{ item.companyName }}</td>
                <td>{{ item.warehouseCount }}</td>
                <td>{{ item.warningCount }}</td>
              </tr>
              <tr v-for="(item,index) in loopData" :key="`loop-${item.id}`">
                <td>{{ index + 1 }}</td>
                <td>{{ item.companyName }}</td>
                <td>{{ item.warehouseCount }}</td>
                <td>{{ item.warningCount }}</td>
              </tr>
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
@@ -37,34 +77,24 @@
</template>
<script setup>
import * as echarts from 'echarts';
import {onMounted,onBeforeUnmount,ref,computed} from "vue";
import {onMounted, onBeforeUnmount, ref, computed, reactive} from "vue";
import SUZHOU from './map.json'
import {getAvoidList} from "@/api/hazardousChemicals/avoid";
import {ElMessage} from "element-plus";
import {getCompanyMessage} from "@/api/monitor/screenCharts";
// 表格数据
const companyData = [
  { id: 1, rank: 1, company: '化工企业A', warehouse: '仓库1', warning: '相忌预警' },
  { id: 2, rank: 2, company: '化工企业B', warehouse: '仓库2', warning: '' },
  { id: 3, rank: 3, company: '化工企业C', warehouse: '仓库3', warning: '超期预警' },
  { id: 4, rank: 4, company: '化工企业D', warehouse: '仓库4', warning: '' },
  { id: 5, rank: 5, company: '化工企业E', warehouse: '仓库5', warning: '' },
  { id: 6, rank: 6, company: '化工企业F', warehouse: '仓库6', warning: '超期预警' },
  { id: 7, rank: 7, company: '化工企业G', warehouse: '仓库7', warning: '' },
  { id: 8, rank: 8, company: '化工企业H', warehouse: '仓库8', warning: '' },
  { id: 9, rank: 9, company: '化工企业I', warehouse: '仓库9', warning: '' },
  { id: 10, rank: 10, company: '化工企业J', warehouse: '仓库10', warning: '' },
  { id: 11, rank: 11, company: '化工企业K', warehouse: '仓库11', warning: '' },
  { id: 12, rank: 12, company: '化工企业L', warehouse: '仓库12', warning: '' },
]
const companyData = ref([])
// 配置参数
const visibleRows = 8 // 显示的行数
const scrollSpeed = 1 // 每次滚动的像素数
const visibleRows = 10 // 显示的行数
const scrollSpeed = 0.5 // 每次滚动的像素数
const rowHeight = 40 // 行高,与CSS一致
const viewport = ref(null)
const scrollPosition = ref(0)
let animationFrame = null
onMounted(()=>{
  initChart()
  getList()
  // initChart()
  // 设置视口高度
  if (viewport.value) {
    viewport.value.style.height = `${visibleRows * rowHeight}px`
@@ -81,9 +111,63 @@
  }
})
const companyType = ref('')
const warningType = ref('')
const typeList = [
  {
    id: 0,
    name: '研发类'
  },
  {
    id: 1,
    name: '生产类'
  },
  {
    id: 2,
    name: '中试类'
  }
]
const warningList = [
  {
    id: 1,
    name: '红'
  },
  {
    id: 2,
    name: '橙'
  },
  {
    id: 3,
    name: '黄'
  },
  {
    id: 4,
    name: '蓝'
  }
]
const getList = async () => {
  const res = await getCompanyMessage(companyType.value)
  if(res.code == 200){
    if(res.data && Array.isArray(res.data) && res.data.length>0){
      companyData.value = res.data
      const mapData = companyData.value.map(i=>{
        return {
          name: i.companyName + '\n' + i.warningCount,
          value: [i.longitude,i.latitude]
        }
      })
      initChart(mapData)
    }
  }else{
    ElMessage.warning(res.message)
  }
}
// 复制前几行数据用于循环
const loopData = computed(() => {
  return companyData.slice(0, visibleRows)
  return companyData.value.slice(0, visibleRows)
})
// 内容区域样式
@@ -95,7 +179,7 @@
// 滚动动画
const scrollAnimation = () => {
  const totalHeight = companyData.length * rowHeight
  const totalHeight = companyData.value.length * rowHeight
  const loopHeight = loopData.value.length * rowHeight
  // 更新滚动位置
  scrollPosition.value += scrollSpeed
@@ -106,24 +190,10 @@
  animationFrame = requestAnimationFrame(scrollAnimation)
}
const initChart =()=>{
const initChart =(mapData)=>{
  //获取echart对象
  let dom = document.getElementById('areaMap')
  if (dom) {
    let data = [
      {
        name: "姑苏区",
        value: Math.round(Math.random() * 100)
      },
      {
        name: "虎丘区",
        value: Math.round(Math.random() * 100)
      },
      {
        name: "吴中区",
        value: Math.round(Math.random() * 100)
      },
    ]
    //初始化
    let myEchart = echarts.init(dom)
    //注册地图
@@ -131,6 +201,7 @@
    let option = {
      geo: {
        map: '苏州市',
        roam: 'scale',
        aspectScale: 0.8,
        layoutCenter: ['50%', '50%'], //地图位置
        layoutSize: '75%',
@@ -195,16 +266,15 @@
              }
            }
          },
          data: data
        },
        // 区域散点图
        {
          type: 'effectScatter',
          coordinateSystem: 'geo',
          symbolSize: 10,
          symbolSize: 4,
          rippleEffect: {
            period: 3,
            scale: 10,
            period: 2,
            scale: 6,
            brushType: 'fill'
          },
          label: {
@@ -213,20 +283,16 @@
              position: 'right',
              formatter: '{b}',
              color: 'yellow',
              fontSize: 12
              fontSize: 14
            }
          },
          data: [
              { name: '斜塘街道 11', value: [120.697614, 31.288664] },
            { name: '桑田岛 12', value: [120.807510, 31.350300] },
            { name: '车坊 2', value: [120.627614, 31.338664] }
          ],
          data: mapData,
          itemStyle: {
            //坐标点颜色
            normal: {
              show: true,
              color: 'skyblue',
              shadowBlur: 20,
              color: 'orange',
              shadowBlur: 6,
              shadowColor: '#fff'
            },
            emphasis: {
@@ -251,11 +317,49 @@
  height: 100%;
  display: flex;
  align-items: flex-start;
  gap: 10px
}
.container-left{
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.filter{
  width: 100%;
  display: flex;
  align-items: center;
}
:deep(.el-input__wrapper){
  height: 28px;
  box-shadow: none;
  border: 1px solid #11FEEE;
  background: rgba(6,24,88,.6);
  color: #fff;
}
:deep(.el-input__inner){
  color: #02CDE6;
}
:deep(.el-input .el-select__caret){
  color: #02CDE6
}
:deep(.el-popper.is-light){
  background: rgb(8,44,97);
  .el-select-dropdown__item{
    color: #fff;
    &:hover{
      background: #015fb0;
    }
  }
}
.table-wrapper {
  position: relative;
  width: 300px;
  margin-top: 30px;
  width: 100%;
  margin-top: 10px;
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 2px;
  overflow: hidden;
@@ -296,8 +400,12 @@
    .scroll-content {
      will-change: transform; /* 优化性能 */
    }
    .danger {
      color: #ff2f2f;
      animation: blink 1s infinite;
    }
    .warning {
      color: #ff0000;
      color: yellow;
      animation: blink 1s infinite;
    }
  }
@@ -305,12 +413,18 @@
@keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0.7; }
  50% { opacity: 0.8; }
  100% { opacity: 1; }
}
  #areaMap{
    flex: 1;
    height: 500px;
  }
#areaMap{
  flex: 2;
  height: 100%;
}
:deep(.BMap_cpyCtrl) {
  display: none !important;
}
:deep(.anchorBL) {
  display: none !important;
}
</style>