quanyawei
2024-02-01 17e751b24202b92c1fc59486741293ce199d6089
fix:断线监控
3 files added
1 files modified
823 ■■■■■ changed files
src/assets/icon/back.png patch | view | raw | blame | history
src/router/dynamicRouter.js 7 ●●●●● patch | view | raw | blame | history
src/views/onlineRate/detailBox.vue 462 ●●●●● patch | view | raw | blame | history
src/views/onlineRate/index.vue 354 ●●●●● patch | view | raw | blame | history
src/assets/icon/back.png
src/router/dynamicRouter.js
@@ -161,6 +161,12 @@
  component: () => import('@/views/levelStatistic/index'),
  meta: { title: '城市优良天统计', icon: 'example' }
}
const onlineRate = {
  path: 'analyse/onlineRate',
  name: 'onlineRate',
  component: () => import('@/views/onlineRate/index'),
  meta: { title: '断线统计', icon: 'example' }
}
const industryContributionRate = {
  path: 'analyse/industryContributionRate',
@@ -236,6 +242,7 @@
  showGovHourData: showGovHourData,
  cityAirRank: cityAirRank,
  levelStatistic: levelStatistic,
  onlineRate: onlineRate,
  heatmap: heatmap,
  hexagon: hexagon,
  airPollutionCalendar: airPollutionCalendar,
src/views/onlineRate/detailBox.vue
New file
@@ -0,0 +1,462 @@
<template>
  <div>
    <el-dialog
      :title="title"
      :visible.sync="visible"
      top="30px"
      width="1000px"
      center
      :before-close="close"
      @closed="close"
    >
      <div>
        <el-form
          :inline="true"
          style="text-align: center;"
          :model="formInline"
        >
          <el-form-item>
            <el-radio-group
              v-model="time"
              @change="changeDay"
            >
              <el-radio-button label="天" />
              <el-radio-button label="小时" />
              <el-radio-button label="分钟" />
            </el-radio-group>
          </el-form-item>
          <el-form-item label="时间:">
            <el-date-picker
              v-model="selectTime"
              type="datetimerange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd HH:mm"
              :default-date="[macDate.startTime, macDate.endTime]"
              :picker-options="pickerOptions"
              @change="changeDay"
            />
          </el-form-item>
        </el-form>
      </div>
      <div>
        <div class="tit">
          <p style="font-size:16px">
            {{ macOnlineDetailData.code }}%
          </p>
          <div id="myPieChart" />
        </div>
        <div class="echartsBox">
          <div class="myLineChartBox">
            <div id="myLineChart" />
            <div class="backIcon">
              <img
                v-if="lineType==='minute'"
                src="../../assets/icon/back.png"
                @click="renderBack"
              >
            </div>
          </div>
        </div>
        <p style="margin-top: 0px;">
          注:折线图最小单位为小时,可支持下钻
        </p>
        <div>
          <p style="font-size:16px">
            日志
          </p>
          <el-table
            :data="tableData"
            border
            max-height="200"
            style="width: 100%"
          >
            <el-table-column
              type="index"
              label="序号"
              width="60"
              align="center"
              label-class-name="itemSpan"
            />
            <el-table-column
              prop="endTime"
              label="离线日期"
              align="center"
              label-class-name="itemSpan"
            />
            <el-table-column
              prop="startTime"
              label="上线日期"
              align="center"
              label-class-name="itemSpan"
            />
            <el-table-column
              prop="mun"
              label="离线时长"
              align="center"
              label-class-name="itemSpan"
            />
          </el-table>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import * as echarts from 'echarts'
import dayjs from 'dayjs'
export default {
  props: {
    visible: { type: Boolean, required: true },
    macDate: { type: Object, required: true }
  },
  data () {
    return {
      title: '详情',
      formInline: {},
      macOnlineDetailData: {},
      time: '小时',
      selectTime: [],
      startTime: '',
      endTime: '',
      tableData: [],
      choiceDate: null,
      chart: null,
      pieChart: null,
      type: 'hour',
      lineType: 'hour',
      // 重点
      pickerOptions: {
        onPick: ({ maxDate, minDate }) => {
          // 把选择的第一个日期赋值给一个变量。
          this.choiceDate = minDate.getTime()
          // 如何你选择了两个日期了,就把那个变量置空
          if (maxDate) this.choiceDate = ''
        },
        disabledDate: time => {
          // 如何选择了一个日期
          if (this.choiceDate) {
            // 7天的时间戳
            const one = 6 * 24 * 3600 * 1000
            // 当前日期 - one = 6天之前
            const minTime = this.choiceDate - one
            // 当前日期 + one = 6天之后
            const maxTime = this.choiceDate + one
            return (
              time.getTime() < minTime ||
              time.getTime() > maxTime ||
              // 限制不能选择今天及以后
              time.getTime() > Date.now()
            )
          } else {
            // 如果没有选择日期,就要限制不能选择今天及以后
            return time.getTime() > Date.now()
          }
        }
      }
    }
  },
  watch: {
    time (newValue, oldValue) {
      if (newValue === '天') {
        this.type = 'day'
      } else if (newValue === '小时') {
        this.type = 'hour'
      } else if (newValue === '分钟') {
        this.type = 'minute'
      }
    }
  },
  mounted () {
    this.title = `${this.macDate.name}详情`
    this.startTime = this.macDate.startTime
    this.endTime = this.macDate.endTime
    this.$set(this.selectTime, 0, new Date(this.macDate.startTime))
    this.$set(this.selectTime, 1, new Date(this.macDate.endTime))
    this.getLineData()
    this.getMacDetail()
  },
  beforeDestroy () {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.myPieChart.dispose()
    this.chart = null
    this.myPieChart = null
  },
  methods: {
    changeDay () {
      this.startTime = !this.selectTime ? '' : dayjs(this.selectTime[0]).format('YYYY-MM-DD  HH:mm')
      this.endTime = !this.selectTime ? '' : dayjs(this.selectTime[1]).format('YYYY-MM-DD  HH:mm')
      this.getMacDetail()
      if (this.type !== 'minute') {
        this.getLineData()
      }
    },
    initPieChart (pieChartData) {
      let labelData = {
        show: false,
      }
      if (pieChartData[0] > 0) {
        labelData = {
          show: true,
          position: 'left',
          normal: {
            formatter: function (params) {
              console.log('params22', params)
              let onlineType = params.dataIndex === 0 ? '离线' : '在线'
              return `${onlineType}: ${params.value}`
            },
            fontSize: 14, // 标签字体大小
            fontStyle: 'italic', // 标签字体斜体
          },
        }
      }
      let dom = document.getElementById('myPieChart')
      let myChart = echarts.init(dom)
      this.myPieChart = myChart
      this.myPieChart.setOption({
        grid: {
          left: '40px', // 左侧内边距
          right: '5px', // 右侧内边距
        },
        tooltip: {
          trigger: 'item',
          formatter: function (params) {
            var value = params.value
            let tip = params.dataIndex === 1 ? '在线: ' + value : '离线: ' + value
            return tip
          },
        },
        series: [
          {
            radius: 30,
            center: ['30%', '50%'],
            type: 'pie',
            data: pieChartData,
            label: labelData,
          },
        ],
      }, true)
    },
    initChart (myChart, option, dom) {
      myChart.setOption(option)
      if (this.lineType === 'hour') {
        myChart.on('click', (params) => {
          console.log(params)
          this.lineType = 'minute'
          echarts.dispose(dom)
          var myChart = echarts.init(dom)
          let starTiem = params.data[0]
          console.log('starTiem', dayjs(starTiem).format('YYYY.MM.DD  HH:mm:ss'))
          let endTiem = dayjs(starTiem).add(1, 'hour')
          this.getLineData(dayjs(starTiem).format('YYYY-MM-DD  HH:mm:ss'), dayjs(endTiem).format('YYYY-MM-DD  HH:mm:ss'), 'minute')
          myChart.setOption(option, true)
        })
      }
    },
    renderBack () {
      this.lineType = 'hour'
      let dom = document.getElementById('myLineChart')
      echarts.dispose(dom)
      this.getLineData(this.startTime, this.endTime, this.lineType)
    },
    renderLine () {
      let dom = document.getElementById('myLineChart')
      let myChart = echarts.init(dom)
      let option = this.getOption(
        this.xData,
        this.sData
      )
      this.initChart(myChart, option, dom)
    },
    getOption (xData, sData) {
      let option = null
      let minTime = xData[0]
      let maxTime = xData[xData.length]
      let interval = 3600 * 1000
      if (this.type === 'minute') {
        interval = 60 * 1000
      }
      console.log(minTime, maxTime)
      option = {
        grid: {
          left: '40px', // 左侧内边距
          right: '5px', // 右侧内边距
        },
        xAxis: {
          type: 'time',
          interval: interval,
          axisTick: { show: false },
          splitLine: { show: false },
          axisLine: {
            lineStyle: { width: 0 }
          },
          axisLabel: {
            interval: interval,
            interale: 0,
          }
        },
        tooltip: {
          trigger: 'item',
          formatter: function (params) {
            console.log(params)
            var value = params.data[0]
            let tip = params.value === 1 ? '在线: ' + value : '离线: ' + value
            return tip
          },
        },
        yAxis: {
          axisLine: {show: true},
          axisTick: {show: true},
          splitLine: {show: true},
          axisLabel: {
            formatter: function (value) {
              var texts = []
              if (value === 0) {
                texts.push('离线')
              } else if (value === 1) {
                texts.push('在线')
              }
              return texts
            },
          },
          splitArea: {show: true},
          show: true,
          type: 'value',
          splitNumber: 1,
          min: 0,
          max: 1,
        },
        dataZoom: [
          {
            height: 20, // 时间滚动条的高度
            type: 'slider', // type的作用是指定数据缩放的类型,slider表示使用滑动条进行缩放,inside表示使用鼠标滚轮进行缩放。
            xAxisIndex: 0, // 作用在x轴的下标(因为x轴可以有多个)
            filterMode: 'filter', // 间滚动条的过滤模式,'filter'表示滑动时间条时会直接过滤掉不在时间范围内的数据,'weakFilter'表示滑动时间条时会逐渐过滤掉不在时间范围内的数据。
            start: 0, // 默认开始位置(百分比)
            end: 100, // 默认结束位置(百分比)
          },
          {
            type: 'inside',
            xAxisIndex: 0,
            filterMode: 'filter',
            start: 0,
            end: 100,
          },
        ],
        series: [
          {
            data: sData,
            type: 'line'
          }
        ]
      }
      return option
    },
    getLineData (startTime = this.startTime, endTime = this.endTime, type = this.type) {
      this.$request({
        url: '/onlineRate/detail',
        method: 'get',
        params: {
          mac: this.macDate.mac,
          startTime: startTime,
          endTime: endTime,
          type: type
        }
      })
        .then(res => {
          this.xData = res.data.lineChart1.map(item => {
            return dayjs(item).format('YYYY-MM-DD HH:mm:ss')
          })
          let data = res.data.lineChart2
          this.sData = data.map((item, index) => {
            return [ this.xData[index], item ]
          })
          console.log(this.sData)
          this.$nextTick(() => {
            this.renderLine()
          })
        })
        .catch(err => {
          console.log(err)
        })
    },
    getMacDetail () {
      this.$request({
        url: '/onlineRate/detail',
        method: 'get',
        params: {
          mac: this.macDate.mac,
          startTime: this.startTime,
          endTime: this.endTime,
          type: this.type
        }
      })
        .then(res => {
          this.macOnlineDetailData = res.data
          this.tableData = res.data.tabulation
          let pieChartData = [this.macOnlineDetailData.pieChart1, this.macOnlineDetailData.pieChart2]
          this.initPieChart(pieChartData)
        })
        .catch(err => {
          console.log(err)
        })
    },
    close () {
      this.$emit('update:visible', false)
    }
  }
}
</script>
<style scoped lang="scss">
.echartsBox{
  // display: flex;
   height: 360px;
    .myLineChartBox {
    width: 100%;
    position: relative;
    #myLineChart{
      width: 100%!important;
      height:360px;
        left: -10px;
        canvas {
          width: 100%!important;
        }
    }
  }
}
  #myPieChart {
    height: 120px;
    width: 400px!important;
    canvas {
      width: 100%!important;
    }
  }
.backIcon{
   position: absolute;
    top: -10px;
    right: 80px;
    cursor: pointer;
   img{
    height: 40px;
   }
  }
.tit{
  position: relative;
  #myPieChart{
    float: right;
    position: absolute;
    left: 322px;
    top: -40px;
  }
}
</style>
src/views/onlineRate/index.vue
New file
@@ -0,0 +1,354 @@
<template>
  <div class="main">
    <div>
      <el-form
        :inline="true"
        :model="formInline"
        class="demo-form-inline"
      >
        <el-form-item label="选择组织:">
          <el-select
            v-model="formInline.organizationId"
            placeholder="选择组织"
          >
            <el-option
              v-for="(item,index) in orgData"
              :key="index"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="状态:">
          <el-select
            v-model="formInline.state"
            clearable
            placeholder="选择状态"
          >
            <el-option
              label="在线"
              value="1"
            />
            <el-option
              label="离线"
              value="0"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-radio-group
            v-model="time"
          >
            <el-radio-button label="今天" />
            <el-radio-button label="近1天" />
            <el-radio-button label="近3天" />
            <el-radio-button label="近5天" />
            <el-radio-button label="近7天" />
          </el-radio-group>
        </el-form-item>
        <el-form-item label="其他时间:">
          <el-date-picker
            v-model="selectTime"
            type="datetimerange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="yyyy-MM-dd HH:mm:ss"
            :picker-options="pickerOptions"
            @change="changeDay"
          />
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            @click="handleSearch"
          >
            查询
          </el-button>
        </el-form-item>
      </el-form>
    </div>
    <div>
      <p>当前设备共{{ tableData.length }}台,在线 {{ onlineData }}台,在线率 <span :class=" onlineRate<90 ?'redClor':'greenClor'">{{ onlineRate }}%</span></p>
      <div>
        <el-table
          v-loading="loading"
          :data="tableData"
          max-height="700"
          border
          style="width: 100%"
        >
          <el-table-column
            type="index"
            label="序号"
            width="60"
            align="center"
            label-class-name="itemSpan"
          />
          <el-table-column
            prop="mac"
            label="mac号"
            align="center"
            label-class-name="itemSpan"
          />
          <el-table-column
            prop="name"
            label="设备名称"
            align="center"
            label-class-name="itemSpan"
          >
            <template #default="scope">
              <el-button
                type="text"
                @click="handleDetail(scope.row)"
              >
                {{ scope.row.name }}
              </el-button>
            </template>
          </el-table-column>
          <el-table-column
            prop="endTime"
            label="最近一次掉线时间"
            align="center"
            label-class-name="itemSpan"
          />
          <el-table-column
            prop="startTime"
            label="最近一次上线时间"
            align="center"
            label-class-name="itemSpan"
          />
          <el-table-column
            prop="num"
            label="掉线次数"
            width="90px"
            label-class-name="itemSpan"
            align="center"
          />
          <el-table-column
            prop="onlineRate"
            label-class-name="itemSpan"
            label="在线率"
            width="100px"
            align="center"
          />
          <el-table-column
            prop="onlineTime"
            label-class-name="itemSpan"
            label="当前在线时长"
            width="120px"
            align="center"
          />
          <el-table-column
            prop="state"
            label-class-name="itemSpan"
            label="状态"
            width="80px"
            align="center"
          >
            <template slot-scope="scope">
              <el-button
                v-if="scope.row.state === '0'"
                style="color:red;font-size:15px"
                type="text"
              >
                离线
              </el-button>
              <el-button
                v-else
                style="color:#67c23a;font-size:15px"
                type="text"
              >
                在线
              </el-button>
            </template>
          </el-table-column>
          <!-- <el-table-column
            prop="address"
            align="center"
            width="80px"
            label-class-name="itemSpan"
            label="操作"
          >
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="text"
                style="font-size:15px"
                @click="handleDetail(scope.row)"
              >
                详情
              </el-button>
            </template>
          </el-table-column> -->
        </el-table>
      </div>
    </div>
    <detailBox
      v-if="handleShow"
      :visible.sync="handleShow"
      :mac-date="macDate"
    />
  </div>
</template>
<script>
import dayjs from 'dayjs'
import detailBox from '@/views/onlineRate/detailBox'
export default {
  components: {
    detailBox
  },
  data () {
    return {
      formInline: {
        organizationId: '',
        startTime: dayjs().startOf('day').format('YYYY-MM-DD  HH:mm'),
        endTime: dayjs().subtract(1, 'hour').format('YYYY-MM-DD  HH:mm')
      },
      time: '今天',
      selectTime: '',
      macDate: {},
      orgData: [],
      tableData: [],
      handleShow: false,
      loading: false,
      choiceDate: null,
      // 重点
      pickerOptions: {
        onPick: ({ maxDate, minDate }) => {
          // 把选择的第一个日期赋值给一个变量。
          this.choiceDate = minDate.getTime()
          // 如何你选择了两个日期了,就把那个变量置空
          if (maxDate) this.choiceDate = ''
        },
        disabledDate: time => {
          // 如何选择了一个日期
          if (this.choiceDate) {
            // 7天的时间戳
            const one = 6 * 24 * 3600 * 1000
            // 当前日期 - one = 6天之前
            const minTime = this.choiceDate - one
            // 当前日期 + one = 6天之后
            const maxTime = this.choiceDate + one
            return (
              time.getTime() < minTime ||
              time.getTime() > maxTime ||
              // 限制不能选择今天及以后
              time.getTime() > Date.now()
            )
          } else {
            // 如果没有选择日期,就要限制不能选择今天及以后
            return time.getTime() > Date.now()
          }
        }
      }
    }
  },
  computed: {
    onlineData () {
      return this.tableData.filter(item => item.state !== '0').length || 0
    },
    onlineRate () {
      return Math.floor((this.onlineData / this.tableData.length) * 100) || 0
    }
  },
  watch: {
    time (newValue, oldValue) {
      let now = dayjs() // 获取当前时间
      if (newValue === '近1天') {
        this.selectTime = []
        this.formInline.startTime = now.subtract(1, 'day').format('YYYY-MM-DD  HH:mm') // 获取昨天的零点
      } else if (newValue === '近3天') {
        this.selectTime = []
        this.formInline.startTime = now.subtract(3, 'day').format('YYYY-MM-DD  HH:mm') // 获取前天的零点
      } else if (newValue === '近5天') {
        this.selectTime = []
        this.formInline.startTime = now.subtract(5, 'day').format('YYYY-MM-DD  HH:mm') // 获取前天的零点
      } else if (newValue === '近7天') {
        this.selectTime = []
        this.formInline.startTime = now.subtract(7, 'day').format('YYYY-MM-DD  HH:mm') // 获取前天的零点
      } else if (newValue === '今天') {
        this.selectTime = []
        this.formInline.startTime = now.format('YYYY-MM-DD  HH:mm')
      }
    }
  },
  created () {
    this.getOrganizationId()
  },
  methods: {
    changeDay () {
      console.log(this.selectTime)
      this.formInline.startTime = this.selectTime[0]
      this.formInline.endTime = this.selectTime[1]
      this.time = ''
    },
    handleDetail (row) {
      console.log(row)
      this.handleShow = true
      this.macDate = row
      this.macDate.startTime = this.formInline.startTime
      this.macDate.endTime = this.formInline.endTime
    },
    handleSearch () {
      if (this.formInline.organizationId !== '') {
        this.loading = true
        this.$request({
          url: '/onlineRate/page',
          method: 'post',
          data: {
            ...this.formInline
          }
        })
          .then(res => {
            this.tableData = res.data
            this.loading = false
          })
          .catch(err => {
            console.log(err)
          })
      } else {
        this.$message.warning('请选择组织或者时间')
      }
    },
    getOrganizationId () {
      this.$request({
        url: '/organization/getOrganizationId',
        method: 'get'
      })
        .then(res => {
          this.orgData = res.data
        })
        .catch(err => {
          console.log(err)
        })
    },
  },
}
</script>
<style lang="scss" scoped>
.main{
  padding: 10px;
  font-size: 18px;
}
/deep/.el-form-item__label{
  font-size: 16px;
}
/deep/.itemSpan {
  font-size: 15px;
  color: rgba(16, 16, 16, 1);
}
 /deep/.cell{
  font-size: 15px;
}
.redClor{
  color: red;
}
.greenClor{
  color:#67c23a;
}
</style>>