Newer
Older
laserPTZFrontV2.0 / src / views / statistics / statistics.vue
wangxitong on 26 Sep 10 KB 流媒体
<script lang="ts" setup name="Statistics">
import { getCurrentInstance, ref } from 'vue'
import type { Ref } from 'vue'
import type { DateModelType } from 'element-plus'
import dayjs from 'dayjs'
import type { MonitorListInfo, StationListInfo } from '../alarm/alarm-interface'
import type { DateReturn, ITableData, TypeReturn } from './statistics-interface'
import LineChart from '@/components/Echart/LineChart.vue'
import BarChartHorizontal from '@/components/Echart/BarChartHorizontal.vue'
import BarChartVertical from '@/components/Echart/BarChartVertical.vue'
import type { lineDataI } from '@/components/Echart/echart-interface'
import { getAlarmDateStatistics, getAlarmTypeStatistics, getStationStatistics } from '@/api/ptz/statistics'
import { getStationList } from '@/api/ptz/station'
import { getDevList } from '@/api/ptz/dev'
import PieChart from '@/components/Echart/PieChart.vue'

// 每个展示块高度
const blockHeight = ref(300)
const blockWidth = ref(400)
const devTableLoading = ref(false)
const devBarLoading = ref(false)
const alarmDateLoading = ref(false)
const alarmTypeLoading = ref(false)
const showType = ref('柱状图')

const timeRange = ref<[DateModelType, DateModelType]>(['', ''])

// 默认查询条件
const defaultQuery = {
  stationId: '',
  monitorId: '',
  startTime: '',
  endTime: '',
}
const listQuery = reactive({ ...defaultQuery })
const stationList: Ref<StationListInfo[]> = ref([])
const monitorList: Ref<MonitorListInfo[]> = ref([])

const devTableData = ref<ITableData[]>([])
// 设备台账检定提醒表头
const devTableHead = [
  { text: '场站名称', value: 'stationName', width: '180' },
  { text: '云台数量', value: 'total' },
  { text: '在线', value: 'online' },
  { text: '离线', value: 'offline' },
]

const total = ref(20)

const devBarXData: Ref<string[]> = ref([])
const devBarData: Ref<lineDataI[]> = ref([])
const devBarYDataMax = ref()

const alarmDateXData: Ref<string[]> = ref([])
const alarmDateData: Ref<lineDataI[]> = ref([])
const alarmDateYDataMax = ref()

const alarmTypeXData: Ref<string[]> = ref([])
const alarmTypeData: Ref<lineDataI[]> = ref([])
const alarmTypeYDataMax = ref()
const pieTypeData: Ref<any[]> = ref([])

function fetchStationList() {
  getStationList().then((res) => {
    stationList.value = res.data
  })
}

function changeStation() {
  listQuery.monitorId = ''
  getDevList(listQuery.stationId).then((res) => {
    monitorList.value = res.data
  })
}

function getDevData() {
  devTableLoading.value = true
  devBarLoading.value = true
  getStationStatistics().then((res) => {
    devTableData.value = res.data
    const tValue = res.data.map((item: ITableData) => Number(item.total))
    const onValue = res.data.map((item: ITableData) => Number(item.online))
    const offValue = res.data.map((item: ITableData) => Number(item.offline))
    // devBarYDataMax.value = Math.max(tValue) //> 10 ? Math.max(tValue) : 10
    console.log(Math.max(tValue))
    devBarData.value = [{ name: '在线', data: onValue }, { name: '离线', data: offValue }]
    devBarXData.value = res.data.map((item: ITableData) => item.stationName)
    devTableLoading.value = false
    devBarLoading.value = false
  })
}

function getAlarmDate() {
  alarmDateLoading.value = true
  getAlarmDateStatistics(listQuery).then((res) => {
    const yValue = res.data.map((item: DateReturn) => Number(item.num))
    alarmDateYDataMax.value = Math.max(yValue) > 10 ? Math.max(yValue) : 10
    alarmDateXData.value = res.data.map((item: TypeReturn) => item.date)
    alarmDateData.value = [{ name: '报警数', data: yValue }]
    alarmDateLoading.value = false
  })
}

function getAlarmType() {
  alarmTypeLoading.value = true
  getAlarmTypeStatistics(listQuery).then((res) => {
    const yValue = res.data.map((item: TypeReturn) => Number(item.num))
    alarmTypeYDataMax.value = Math.max(yValue) > 10 ? Math.max(yValue) : 10
    alarmTypeXData.value = res.data.map((item: TypeReturn) => item.type)
    alarmTypeData.value = [{ name: '报警数', data: yValue }]
    pieTypeData.value = res.data.map((item: any) => {
      return {
        name: item.type,
        value: Number(item.num),
      }
    })
    alarmTypeLoading.value = false
  })
}

// 搜索按钮
function search() {
  if (timeRange.value) {
    listQuery.startTime = timeRange.value[0] as string || ''
    listQuery.endTime = timeRange.value[1] as string || ''
  }
  getAlarmDate()
  getAlarmType()
}

// 搜索重置
function clear() {
  Object.assign(listQuery, defaultQuery)
  listQuery.startTime = dayjs(Date.now() - 7 * 24 * 60 * 60 * 1000).format('YYYY-MM-DD HH:mm:ss')
  listQuery.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  timeRange.value = [listQuery.startTime, listQuery.endTime]
  search()
}

function calcBlockSize() {
  // 计算工作台区域高度 - 顶部-面包屑-边距
  const bodyHeight = document.body.clientHeight - 60 - 50 - 20
  blockHeight.value = bodyHeight > 610 ? (bodyHeight - 10) / 2 : 300
  blockWidth.value = (document.body.clientWidth - 180 - 20 - 20)
}

window.addEventListener('resize', () => {
  calcBlockSize()
})

onBeforeMount(() => {
  calcBlockSize()
})
onMounted(() => {
  getDevData()
  listQuery.startTime = dayjs(Date.now() - 7 * 24 * 60 * 60 * 1000).format('YYYY-MM-DD HH:mm:ss')
  listQuery.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  timeRange.value = [listQuery.startTime, listQuery.endTime]
  fetchStationList()
  search()
})
</script>

<template>
  <app-container>
    <div class="device-bench">
      <el-row :gutter="10">
        <el-col :span="10">
          <bench-col v-loading="devBarLoading" icon="icon-bar1" title="设备统计" :height="blockHeight">
            <bar-chart-horizontal
              :x-axis-data="devBarXData" :width="`${blockWidth * 10 / 24 - 10}px`" :data="devBarData"
              :max="devBarYDataMax"
            />
          </bench-col>
        </el-col>
        <el-col :span="14">
          <search-area @search="search">
            <search-item>
              <el-select
                v-model="listQuery.stationId" placeholder="所在场站" clearable style="width: 130px;"
                @change="changeStation"
              >
                <el-option v-for="item in stationList" :key="item.id" :label="item.stationName" :value="item.id" />
              </el-select>
            </search-item>
            <search-item>
              <el-select
                v-model="listQuery.monitorId" clearable style="width: 160px;"
                :disabled="listQuery.stationId === ''" :placeholder="listQuery.stationId === '' ? '请先选择所在场站' : '选择设备'"
              >
                <el-option v-for="item in monitorList" :key="item.id" :label="item.monitorName" :value="item.id" />
              </el-select>
            </search-item>
            <search-item>
              <el-date-picker
                v-model="timeRange" type="datetimerange" range-separator="到" format="YYYY-MM-DD HH:mm:ss"
                value-format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间" end-placeholder="结束时间" style="width: 350px;"
                :clearable="false"
              />
            </search-item>
          </search-area>
          <bench-col
            v-loading="alarmDateLoading" icon="icon-line" title="报警趋势分析" :height="`${blockHeight - 45}px`"
            style="margin-top: -10px;"
          >
            <line-chart
              :x-axis-data="alarmDateXData" :width="`${blockWidth * 14 / 24 - 10}px`" :data="alarmDateData"
              unit="次"
            />
          </bench-col>
        </el-col>
      </el-row>
    </div>
    <div class="device-bench" style="margin-top: 10px;">
      <el-row :gutter="10">
        <el-col :span="8">
          <bench-col
            v-loading="devTableLoading" icon="icon-book" title="设备统计" path-url=""
            :style="{ height: blockHeight }" :height="blockHeight"
          >
            <el-table
              :data="devTableData" :height="blockHeight - 60" style="width: 100%; height: 100%;" stripe
              header-row-class-name="bench-table-header" row-class-name="bench-table-row" class="bench-table"
            >
              <el-table-column
                v-for="item in devTableHead" :key="item.value" :prop="item.value" align="center"
                :label="item.text" :width="item.width"
              />
            </el-table>
          </bench-col>
        </el-col>
        <el-col :span="16">
          <bench-col v-loading="alarmTypeLoading" icon="icon-bar" title="各类报警统计" :height="blockHeight">
            <el-radio-group v-model="showType" size="small" style="position: absolute;right: 20px;top: 10px;">
              <el-radio-button label="柱状图" />
              <el-radio-button label="饼状图" />
            </el-radio-group>
            <bar-chart-vertical
              v-show="showType === '柱状图'"
              :x-axis-data="alarmTypeXData"
              :width="`${blockWidth * 16 / 24 - 10}px`"
              :height="`${blockHeight - 50}px`"
              :data="alarmTypeData" unit="次"
            />
            <pie-chart
              v-show="showType === '饼状图'"
              :data="pieTypeData"
              :radius="['0%', '70%']"
              :width="`${blockWidth * 16 / 24 - 10}px`"
              :height="`${blockHeight - 50}px`"
            />
          </bench-col>
        </el-col>
      </el-row>
    </div>
  </app-container>
</template>

<style lang="scss" scoped>
.device-bench {
  width: 100%;
  height: 100%;
  box-sizing: border-box;

  .the-month-total-Data {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    padding: 0 20px;

    .title {
      display: flex;
      justify-content: space-between;
      font-weight: 500;
      margin-bottom: 3px;
    }

    .content {
      width: 100%;

      .item {
        display: flex;
        flex-direction: column;
        flex: 1;
        margin-right: 10px;
        padding: 3px 0;
        justify-content: center;
        align-items: center;
        background-image: linear-gradient(to bottom, #e9f5ff, #3d7eff);
        border-radius: 8px;

        &:last-child {
          margin-right: 0;
        }
      }
    }
  }

  .my-equipment {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    padding: 20px;

    .item {
      height: 40%;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-image: linear-gradient(to right, #caddff, #3d7eff);
      border-radius: 16px;
    }
  }
}
</style>

<style lang="scss">
.bench-table {
  .el-table__header-wrapper {
    border-radius: 8px;
  }
}

.bench-table-header {
  th {
    font-weight: normal;
    font-size: 14px;
  }
}

.bench-table-row {
  border-radius: 8px;
}
</style>