Newer
Older
securityFront / src / views / ctrl / overview.vue
TAN YUE on 23 Jan 2021 24 KB 20210123 运行总览ui调整
<template>
  <div class="main-page">
    <div class="main-header">
      <div class="main-title">
        <!-- <img src="@/assets/dashboard_images/icon-title.png"> -->
        <span>{{ title }}</span>
      </div>
    </div>

    <div class="home-icon">
      <a @click="backToIndex">
        <img src="@/assets/global_images/home-logo.png">
      </a>
    </div>
    <div class="exit-icon">
      <a href="#" @click="logout">
        <img src="@/assets/global_images/exit-logo.png">
      </a>
    </div>

    <!-- 左上角设备状态区域 -->
    <div class="dev-status-block">
      <el-row style="z-index: 99">
        <el-col :span="6" class="sub-data-block dev-normal">
          <div class="statis-block">
            <span v-text="dev.onLine"/>
          </div>
          <div class="sub-title">正常</div>
        </el-col>

        <el-col :span="6" class="sub-data-block dev-alarm">
          <div class="statis-block">
            <span v-text="dev.alarm"/>
          </div>
          <div class="sub-title">报警</div>
        </el-col>

        <el-col :span="6" class="sub-data-block dev-offline">
          <div class="statis-block">
            <span v-text="dev.offLine"/>
          </div>
          <div class="sub-title">离线</div>
        </el-col>

        <el-col :span="6" class="sub-data-block dev-closed">
          <div class="statis-block">
            <span v-text="dev.closed"/>
          </div>
          <div class="sub-title">关闭</div>
        </el-col>
      </el-row>
    </div>

    <!-- 左侧当前报警列表区域 -->
    <div v-show="alarmList.length > 0" class="alarm-now-block">
      <div class="map-alarm-div-header">报警列表
        <span class="icon-right" @click="tableShow=!tableShow">
          <i v-if="tableShow" class="el-icon-arrow-up"/>
          <i v-else class="el-icon-arrow-down"/>
        </span>
      </div>
      <transition name="el-collapse-transition">
        <el-scrollbar
          v-show="tableShow"
          :style="{ visibility: tableShow ? 'visible' : 'hidden'}"
          :class="{ moredatascollor: alarmList.length > 6 }"
          :native="false">
          <el-table
            :data="alarmList"
            class="alarm-list-table"
            border
            stripe
            @row-click="alarmRowClick">
            <el-table-column v-for="column in alarmColumns" :key="column.value" :label="column.text" :width="column.width" :align="column.align" show-overflow-tooltip>
              <template slot-scope="scope">
                {{ scope.row[column.value] }}
              </template>
            </el-table-column>
          </el-table>
        </el-scrollbar>
      </transition>
    </div>

    <!-- 中间平面图区域 -->
    <div class="map-overview">
      <img ref="bgImg" :src="bgImageSrc" height="100%" @load="getBgImageSize">

      <div v-for="item in devList" :id="item.id" :key="item.id" class="point" @click="detailDev(item, $event)" />
    </div>

    <!-- 平面图区域设备类型按钮 -->
    <el-row :gutter="30" :style="{ left: footLeft + 'px' }" class="dev-footer">
      <el-col ref="all" class="dev-icon dev-type-selected" @click.native="selectDevByType('all', $event)">
        <img v-if="false" src="@/assets/overview_images/icons/icon-all-checked.png">
        <img v-else src="@/assets/overview_images/icons/icon-all-unchecked.png">
        <span>全部</span>
      </el-col>

      <el-col ref="camera" class="dev-icon" @click.native="selectDevByType('camera', $event)">
        <img src="@/assets/overview_images/icons/icon-camera.png">
        <span>摄像头</span>
      </el-col>

      <el-col v-show="showFence" class="dev-icon" @click.native="selectDevByType('fence', $event)">
        <img src="@/assets/overview_images/icons/icon-fence.png">
        <span>电子围栏</span>
      </el-col>

      <el-col v-show="showTemp" class="dev-icon" @click.native="selectDevByType('temperature', $event)">
        <img src="@/assets/overview_images/icons/icon-temperature.png">
        <span>温湿度</span>
      </el-col>

      <el-col v-show="showSmoking" class="dev-icon" @click.native="selectDevByType('smoking', $event)">
        <img src="@/assets/overview_images/icons/icon-smoking.png">
        <span>烟感</span>
      </el-col>

      <el-col v-show="showSound" class="dev-icon" @click.native="selectDevByType('sound')">
        <img src="@/assets/overview_images/icons/icon-sound-checked.png">
        <span>声光报警</span>
      </el-col>
    </el-row>

    <!-- 右侧平面图索引切换区域 -->
    <div class="map-tab">
      <div class="tab-top" />
      <div class="map-index-button index-selected" @click="selectMapTab('main', $event)">营区总览</div>
      <div class="map-index-button" @click="selectMapTab('three', $event)">三号楼</div>
      <div class="map-index-button" @click="selectMapTab('four', $event)">四号楼</div>
      <div class="tab-bottom" />

      <div v-show="showSubTabGuider" ref="sub-tab" class="sub-tab-guider" />
      <div v-show="showSubTabGuider" ref="sub-tab-border" class="sub-tab-border" />
      <div v-show="showFloorThree" ref="sub-tab-floor-3" class="sub-tab-content" @click="changeMap('tg_3_1')">三号楼一层</div>
      <div v-show="showFloorFour" ref="sub-tab-floor-4-1" class="sub-tab-content" @click="changeMap('tg_4_1')">四号楼一层</div>
      <div v-show="showFloorFour" ref="sub-tab-floor-4-5" class="sub-tab-content" @click="changeMap('tg_4_5')">四号楼五层</div>
    </div>

    <!-- 右侧设备详情及操作区域 -->
    <div v-show="showDevDetail" ref="dev-detail-block" class="dev-detail-block">
      <span class="dev-detail-close" @click="showDevDetail=false" />
      <el-row style="margin-top: -25px;">
        <el-col :span="24">设备名称
          <span class="dev-detail-span">{{ dataForm.name }}</span>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">设备编号
          <span class="dev-detail-span">{{ dataForm.devcode }}</span>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">设备类型
          <span class="dev-detail-span">{{ dataForm.typeName }}</span>
        </el-col>
      </el-row>
      <el-row v-show="false" :gutter="20">
        <el-col :span="24">设备型号
          <span class="dev-detail-span">{{ dataForm.model }}</span>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">在线状态
          <span class="dev-detail-span">{{ dataForm.onlineStatusName }}</span>
        </el-col>
      </el-row>
      <el-row v-show="isFence">
        <el-col :span="24">是否开启
          <span class="dev-detail-span">{{ dataForm.deviceStatusName }}</span>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">安装日期
          <span class="dev-detail-span">{{ dataForm.installDate }}</span>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">安装位置
          <span class="dev-detail-span">{{ dataForm.position }}</span>
        </el-col>
      </el-row>
      <el-row v-show="isDoor">
        <el-col :span="24">
          <span class="dev-detail-span">{{ dataForm.inOutName }}</span>
        </el-col>
      </el-row>
    </div>

  </div>
</template>

<script>
import { getProject } from '@/utils/baseConfig'
import { overviewDeviceList, overviewDeviceStatus, getDetailDevice } from '@/api/device'
import { alarmListOverview } from '@/api/alarm'
import DeviceDetail from '@/views/deviceManage/deviceDetail'
import tg_main from '../../assets/overview_images/tg/mapOverviewTg.jpg'
import tg_3_1 from '../../assets/overview_images/tg/mapOverviewTg-3-1.jpg'
import tg_4_1 from '../../assets/overview_images/tg/mapOverviewTg-4-1.jpg'
import tg_4_5 from '../../assets/overview_images/tg/mapOverviewTg-4-5.jpg'
export default {
  name: 'CtrlOverview',
  components: { DeviceDetail },
  data() {
    return {
      title: getProject().title,
      bgImageSrc: tg_main,
      devListParams: {
        picture: '1'
      },
      dev: {
        alarm: 0,
        onLine: 0,
        closed: 0,
        offLine: 0
      },
      imgSizeOriginal: {
        width: 2245,
        height: 1586
      }, // 图片原尺寸
      imgSize: {
        width: 2245,
        height: 1586
      },
      winSize: {
        width: 1440,
        height: 789
      }, // 屏幕窗口尺寸
      footLeft: 10,
      showFence: true,
      showTemp: false,
      showSmoking: false,
      showSound: false,
      showSubTabGuider: false,
      showFloorThree: false,
      showFloorFour: false,
      showDevDetail: false,
      alarmList: [],
      alarmColumns: [
        {
          text: '设备编号',
          value: 'devcode',
          align: 'center'
        },
        {
          text: '报警内容',
          value: 'alarmContent',
          align: 'center'
        },
        {
          text: '报警时间',
          value: 'alarmTime',
          align: 'center',
          width: 165
        }
      ], // 显示列
      tableShow: true, // 是否显示告警列表
      devList: [],
      dataForm: {
        id: '', // id
        name: '', // 设备名
        devcode: '', // 设备编号
        typeName: '', // 设备类型
        model: '', // 设备型号
        onlineStatusName: '', // 在线状态
        deviceStatusName: '', // 设备状态
        position: '', // 安装位置
        installDate: '', // 安装日期
        inOutName: '' // 进出营
      }, // 表单
      isFence: false,
      isDoor: false
    }
  },
  mounted() {
    this.initWindowSize()

    this.fetchData()
    this.fetchAlarmNowData()

    const that = this
    window.onresize = function() {
      that.reDrawDevs()
    }
  },
  methods: {
    initWindowSize() {
      // 获取窗体尺寸
      this.winSize = {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
      }
    },
    getBgImageSize() {
      // 获取图片尺寸
      this.imgSize = {
        width: this.$refs['bgImg'].width,
        height: this.$refs['bgImg'].height
      }
      // this.changeMap('tg_main')
      // this.reDrawDevs()
    },
    reDrawDevs() {
      const halfLeft = (this.winSize.width - this.imgSize.width) / 2

      // 调整球机的设备位置
      const that = this
      this.devList.forEach(function(item) {
        const point = document.getElementById(item.id)

        if (point !== null) {
          if (item.x !== '' && item.y !== '') {
            point.style.position = 'absolute'
            point.style.top = item.y * that.imgSize.height / that.imgSizeOriginal.height + 'px'
            point.style.left = (item.x * that.imgSize.width / that.imgSizeOriginal.width + halfLeft) + 'px'
          } else {
            point.style.display = 'none'
          }
        }
      })
    },
    // 获取设备状态
    fetchData() {
      overviewDeviceStatus().then(response => {
        if (response.code === 200) {
          this.dev.alarm = response.data.alarm.length
          this.dev.onLine = response.data.onLine.length
          this.dev.closed = response.data.closed.length
          this.dev.offLine = response.data.offLine.length
        }
      })
    },
    fetchDeviceData() {
      overviewDeviceList(this.devListParams).then(response => {
        if (response.code === 200) {
          this.devList = response.data
          this.reDrawDevs()
        }
      })
    },
    fetchAlarmNowData() {
      alarmListOverview().then(response => {
        if (response.code === 200) {
          this.alarmList = response.data
        } else {
          this.$message.error(response.message)
        }
      })
    },
    logout() {
      this.$store.dispatch('LogOut').then(() => {
        location.reload() // 为了重新实例化vue-router对象 避免bug
      })
    },
    backToIndex() {
      this.$router.push('/ctrl')
    },
    selectDevByType(type, event) {
      // 遍历所有的设备类型
      const devTypes = document.querySelectorAll('.dev-icon')
      for (let i = 0; i < devTypes.length; i++) {
        if (devTypes[i].className.indexOf('dev-type-selected') > -1) {
          devTypes[i].className = 'dev-icon el-col el-col-24'
        }
      }

      // 添加选中的样式
      event.currentTarget.className += ' dev-type-selected'

      console.log(event.currentTarget)
    },
    selectMapTab(tab, event) {
      // 遍历所有的地图
      const mapTabs = document.querySelectorAll('.map-index-button')
      for (let i = 0; i < mapTabs.length; i++) {
        if (mapTabs[i].className.indexOf('index-selected') > -1) {
          mapTabs[i].className = 'map-index-button'
        }
      }

      // 添加选中的样式
      event.currentTarget.className += ' index-selected'

      // 选中三层
      if (tab === 'three') {
        this.showSubTabGuider = true
        this.showFloorThree = true
        this.showFloorFour = false

        this.$refs['sub-tab'].style.position = 'absolute'
        this.$refs['sub-tab'].style.right = '290px'
        this.$refs['sub-tab'].style.top = '135px'

        this.$refs['sub-tab-border'].style.position = 'absolute'
        this.$refs['sub-tab-border'].style.right = '335px'
        this.$refs['sub-tab-border'].style.top = '185px'

        this.$refs['sub-tab-floor-3'].style.position = 'absolute'
        this.$refs['sub-tab-floor-3'].style.right = '340px'
        this.$refs['sub-tab-floor-3'].style.top = '220px'
      } else if (tab === 'four') {
        this.showSubTabGuider = true
        this.showFloorThree = false
        this.showFloorFour = true

        this.$refs['sub-tab'].style.position = 'absolute'
        this.$refs['sub-tab'].style.right = '290px'
        this.$refs['sub-tab'].style.top = '210px'

        this.$refs['sub-tab-border'].style.position = 'absolute'
        this.$refs['sub-tab-border'].style.right = '335px'
        this.$refs['sub-tab-border'].style.top = '260px'

        this.$refs['sub-tab-floor-4-1'].style.position = 'absolute'
        this.$refs['sub-tab-floor-4-1'].style.right = '340px'
        this.$refs['sub-tab-floor-4-1'].style.top = '300px'

        this.$refs['sub-tab-floor-4-5'].style.position = 'absolute'
        this.$refs['sub-tab-floor-4-5'].style.right = '340px'
        this.$refs['sub-tab-floor-4-5'].style.top = '350px'
      } else {
        this.showSubTabGuider = false
        this.showFloorThree = false
        this.showFloorFour = false
        this.changeMap('tg_main')
      }
    },
    changeMap(index) {
      this.bgImageSrc = tg_main
      this.imgSizeOriginal = { width: 2245, height: 1586 }
      this.showFence = true
      this.showTemp = false
      this.showSound = false
      this.showSmoking = false

      this.footLeft = (this.winSize.width - 3 * 210) / 2
      this.devListParams.picture = '1'

      if (index === 'tg_3_1') {
        this.bgImageSrc = tg_3_1

        this.showFence = false
        this.showTemp = false
        this.showSmoking = false
        this.showSound = false
        this.footLeft = (this.winSize.width - 2 * 210) / 2

        this.devListParams.picture = '2'
      } else if (index === 'tg_4_1') {
        this.bgImageSrc = tg_4_1
        this.imgSizeOriginal = { width: 2218, height: 2169 }

        this.showFence = false
        this.showTemp = true
        this.showSmoking = true
        this.showSound = true
        this.footLeft = (this.winSize.width - 5 * 210) / 2

        this.devListParams.picture = '3'
      } else if (index === 'tg_4_5') {
        this.bgImageSrc = tg_4_5

        this.showFence = false
        this.showTemp = false
        this.showSmoking = false
        this.showSound = false
        this.footLeft = (this.winSize.width - 2 * 210) / 2

        this.devListParams.picture = '4'
      }

      // 将二级菜单的指引区隐藏
      this.showSubTabGuider = false
      this.showFloorThree = false
      this.showFloorFour = false

      this.fetchDeviceData()
    },
    detailDev(dev, event) {
      getDetailDevice(dev.id).then(response => {
        if (response.code === 200) {
          this.dataForm = {
            id: dev.id,
            name: dev.name,
            devcode: dev.devcode,
            typeName: response.data.typeName,
            model: dev.model,
            onlineStatusName: response.data.onlineStatusName,
            position: dev.position,
            installDate: dev.installDate,
            inOutName: response.data.inOutName,
            deviceStatusName: response.data.deviceStatusName
          }

          // 电子围栏设备有开启字段
          if (dev.typeName.indexOf('电子围栏') >= 0) {
            this.isFence = true
          }

          // 营门设备有进出营门的标志位
          if (dev.areaId === '1') {
            this.isDoor = true
          }
        } else {
          this.$message.error(response.message)
        }
      })

      // 弹窗显示设备详情
      const targetDev = event.currentTarget // 取到点击到的设备图标div

      this.showDevDetail = true
      let top = parseInt(targetDev.style.top.substring(0, targetDev.style.top.length - 2))
      top = top + 100
      this.$refs['dev-detail-block'].style.position = 'absolute'
      this.$refs['dev-detail-block'].style.top = top + 'px'
      this.$refs['dev-detail-block'].style.left = targetDev.style.left
    },
    alarmRowClick(dev, column, event) {

    }
  }
}
</script>

<style lang="scss" scoped>

  .main-page {
    background-size: cover;
    background-color: #023d83;
    height: 100vh;
  }

  .main-header {
    width: 100vw;
  }
  .main-title {
    height: 90px;
    text-align: center;
    padding-top: 20px;
    background: url("../../assets/overview_images/title-background-1920.png");
  }

  .main-title img {
    display: inline-block;
    margin-right: 15px;
    width: 52px;
    height: 32px;
    vertical-align: text-bottom;
  }

  .home-icon {
    width: 26px;
    height: 26px;
    position: fixed;
    left: 20px;
    top: 20px;
  }
  .exit-icon {
    width: 26px;
    height: 26px;
    position: fixed;
    right: 20px;
    top: 20px;
  }
  .home-icon img, .exit-icon img {
    width: 26px;
    height: 26px;
  }

  .main-title span {
    color: #FFFFFF;
    font-size: 32px;
    font-weight: bold;
    font-family: 'Microsoft YaHei';
  }

  .map-overview {
    margin-top: 50px;
    /*width: 1100px;*/
    height: calc(90vh - 200px);
    text-align: center;
    position: relative;
  }

  .statis-block {
    text-align: center;
    margin-top: 20px;
    font-size: 48px;
  }
  .sub-title {
    text-align: center;
    font-size: 32px;
  }
  .sub-data-block {
    width: 122px;
    height: 155px;
  }
  .dev-normal {
    background: url("../../assets/overview_images/normal.png");
    background-size: contain;
    color: #00ff0c;
  }
  .dev-alarm {
    background: url("../../assets/overview_images/alarm.png");
    background-size: contain;
    color: #ff0000;
  }
  .dev-offline {
    background: url("../../assets/overview_images/offline.png");
    background-size: contain;
    color: #fff000;
  }
  .dev-closed {
    background: url("../../assets/overview_images/closed.png");
    background-size: contain;
    color: #00fff6;
  }

  .dev-status-block {
    position: absolute;
    top: 100px;
    left: 20px;
    color: #ffffff;
  }

  .alarm-now-block {
    position: absolute;
    z-index: 500;
    top: 300px;
    left: 20px;
    width: 480px;
    .map-alarm-div-header {
      line-height: 40px;
      padding-left: 10px;
      color: #00fff6;
      font-size: 24px;
      .icon-right {
        cursor: pointer;
        margin-left: 20px;
      }
    }
    .el-scrollbar {
      /*height: 200px;*/
      width: 100%;
    }
    .moredatascollor {
      height: 200px;
    }
    .el-scrollbar__wrap {
      overflow-y: auto;
      overflow-x: hidden;
      margin-bottom: 0px !important;
    }
    .el-table {
      font-size: 12px;
    }
    .transition-box {
      margin-bottom: 10px;
      width: 200px;
      height: 100px;
      border-radius: 4px;
      background-color: #409EFF;
      text-align: center;
      color: #fff;
      padding: 40px 20px;
      box-sizing: border-box;
      margin-right: 20px;
    }
  }

  .alarm-now-block /deep/ .el-table th {
    background-color: #0757A0;
    padding: 12px 0px;
    font-size: 16px;
    color: #00fff6;
    font-weight: normal;
  }

  .alarm-now-block /deep/ .el-table td {
    /*background-color: #0757A0;*/
    padding: 10px 0px;
    font-size: 15px;
    color: #FFFFFF;
    font-weight: normal;
  }

  .alarm-now-block /deep/ .el-table__row td {
    background-color: #023D83;
  }
  .alarm-now-block /deep/ .el-table__body tr:hover > td {
    background-color: #0757A0;
  }
  .alarm-now-block /deep/ tr.el-table__row--striped td {
    background-color: #0757A0;
  }

  .map-tab {
    position: absolute;
    right: 20px;
    top: 100px;
    width: 300px;
    button {
      margin: 5px 0px;
    }
  }

  .tab-top {
    position: relative;
    width: 284px;
    height: 24px;
    background: url("../../assets/overview_images/tab-top-bg.png");
  }
  .tab-bottom {
    position: relative;
    width: 284px;
    height: 24px;
    background: url("../../assets/overview_images/tab-bottom-bg.png");
  }
  .map-index-button {
    position: relative;
    width: 284px;
    height: 74px;
    background: url("../../assets/overview_images/tab-index-unchecked.png");
    font-size: 32px;
    line-height: 74px;
    text-align: center;
    color: #FFFFFF;
    cursor: pointer;
  }
  .index-selected {
    background: url("../../assets/overview_images/tab-index-checked.png");
  }
  .sub-tab-guider {
    width: 149px;
    height: 50px;
    background: url("../../assets/overview_images/sub-tab-guider.png");
  }
  .sub-tab-border {
    width: 204px;
    height: 253px;
    background: url("../../assets/overview_images/sub-tab-border.png");
  }
  .sub-tab-content {
    text-align: center;
    color: #FFFFFF;
    font-size: 28px;
    cursor: pointer;
    width: 200px;
  }

  .dev-detail-block {
    /*position: absolute;*/
    /*right: 20px;*/
    /*bottom: 100px;*/
    width: 520px;
    height: 335px;
    color: #00FFFF;
    font-size: 24px;
    font-family: "Microsoft YaHei";
    padding: 45px 60px;
    line-height: 35px;
    background: url("../../assets/overview_images/dev-info.png");
    .dev-detail-span {
      margin-left: 20px;
    }
    .dev-detail-close::before {
      content: "\2716";
      position: relative;
      top: -20px;
      right: -410px;
      cursor: pointer;
    }
  }

  .dev-footer {
    position: absolute;
    bottom: 25px;
  }

  .dev-icon {
    width: 195px;
    height: 105px;
    vertical-align: middle;
    line-height: 65px;
    padding: 20px 30px !important;
    margin-left: 15px;
    cursor: pointer;
    background: url("../../assets/overview_images/dev-type-border-unchecked.png");
  }

  .dev-icon img {
    height: 40px;
    vertical-align:middle;
  }
  .dev-icon span {
    font-size: 20px;
    color: #00D2FF;
    line-height: 65px;
    height: 65px;
    vertical-align:middle;
    float: right;
  }

  .dev-type-selected {
    background: url("../../assets/overview_images/dev-type-border-checked.png");
  }
  .dev-type-selected span {
    color: #f58a88 !important;
  }

  @media(max-width: 1440px) {
    .main-title {
      height: 68px;
      padding-top: 20px;
      background: url("../../assets/overview_images/title-background-1440.png");
    }
    .main-title span {
      font-size: 24px;
    }
    .main-title img {
      margin-right: 15px;
      width: 32px;
      height: 32px;
    }

    .home-icon {
      left: 18px;
      width: 18px;
      height: 18px;
    }
    .exit-icon {
      right: 18px;
      width: 18px;
      height: 18px;
    }

    .home-icon img, .exit-icon img {
      width: 18px;
      height: 18px;
    }

    .dev-icon span {
      font-size: 12px;
    }
  }

  @media(max-width: 1366px) {
    .main-title {
      height: 65px;
      padding-top: 16px;
      background: url("../../assets/overview_images/title-background-1366.png");
    }
    .main-title span {
      font-size: 24px;
    }
    .main-title img {
      margin-right: 15px;
      width: 32px;
      height: 32px;
    }

    .home-icon {
      left: 16px;
      width: 16px;
      height: 16px;
    }
    .exit-icon {
      right: 16px;
      width: 16px;
      height: 16px;
    }

    .home-icon img, .exit-icon img {
      width: 20px;
      height: 20px;
    }

    .dev-icon span {
      font-size: 12px;
    }
  }

</style>

<style lang="scss" scoped>
  .point {
    width: 16px;
    height: 16px;
    position: relative;
    display: inline-block;
    cursor: pointer;
    background: url("../../assets/overview_images/icons/icon-camera-point.png");
    background-size: contain;
  }
</style>