zhangzengfei
2022-08-05 012c84b59018018cd75f0b8c70f7492fcb3e3e6f
src/views/manageCenter/index.vue
@@ -1,10 +1,1049 @@
<template>
  <div class="manageCenter">管理中心</div>
  <div class="manageCenter">
    <!-- 页头 -->
    <IndexHeader :opacity="false"></IndexHeader>
    <div class="centerTitle">
      <div class="heart">
        <div class="welcome">{{ userName }}, 欢迎您回到管理中心。</div>
        <div class="time">{{ timeMsg }}</div>
      </div>
    </div>
    <!-- 版心 -->
    <div class="heart">
      <div class="products">
        <div class="title">全部产品</div>
        <div class="productList">
          <div class="productItem" v-for="(item, index) in productList" :key="index" @click="jump(item)">
            <img :src="item.icon" alt="" />
            <div class="name">{{ item.name }}</div>
          </div>
        </div>
      </div>
      <div class="heart">
        <div class="products">
          <div class="title">统计分析</div>
          <div class="productList">
            <p class="p-statis" style=" vertical-align: top">
              <span>时间:</span>
              <el-date-picker
                size="mini"
                v-model="searchTime"
                @change="searchHandler"
                type="datetimerange"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                :default-time="['00:00:00', '23:59:59']"
              ></el-date-picker>
            </p>
            <!-- <p class="p-statis" style="margin-left: 10px">
              <b style="width: 60px">场景:</b>
              <el-select
                v-model="taskValues"
                multiple
                @change="searchingBtn"
                :disabled="typeDisable"
                collapse-tags
                size="mini"
                placeholder="请选择"
              >
                <el-option
                  v-for="item in VideoPhotoData.tasks"
                  style="font-size: 12px"
                  :key="item.id + 'x'"
                  :value="item.id"
                  :label="item.isDelete ? item.name + '(已删除)' : item.name"
                  :title="item.isDelete ? item.name + '(已删除)' : item.name"
                ></el-option>
              </el-select>
            </p> -->
            <p class="p-statis" style="margin-left: 20px">
              <span>部门:</span>
              <el-cascader
                size="mini"
                style="width:400px"
                v-model="searchTree"
                :options="menuTree"
                :props="{ value: 'id', label: 'name', checkStrictly: true }"
                collapse-tags
                clearable
                @change="handleTreeChange"
              ></el-cascader>
            </p>
            <p class="p-statis" style="margin-left: 20px">
              <span>等级:</span>
              <el-select
                v-model="alarmValues"
                clearable
                collapse-tags
                size="mini"
                style="width:140px"
                placeholder="请选择"
              >
                <el-option
                  v-for="item in levelOptions"
                  :key="item.id"
                  :label="item.label"
                  :value="item.value"
                ></el-option>
              </el-select>
            </p>
            <p class="p-statis" style="">
              <el-button type="primary" size="mini" @click="searchHandler">搜索</el-button>
            </p>
          </div>
        </div>
      </div>
      <div class="equipmentInfo">
        <div class="equipmentCard">
          <div class="label">预警总量</div>
          <div class="number">
            {{ warningTotal }}
            <div class="upIcon iconfont">&#xe62e;</div>
          </div>
          <img src="/images/manageCenter/total2.png" alt="" />
        </div>
        <div class="equipmentCard">
          <div class="label">排查数量</div>
          <div class="number">
            {{ warningChecked }}
            <div class="upIcon iconfont">&#xe62e;</div>
          </div>
          <img src="/images/manageCenter/total3.png" alt="" />
        </div>
        <div class="equipmentCard">
          <div class="label">整改数量</div>
          <div class="number">
            {{ warningSolved }}
            <div class="downIcon iconfont">&#xe651;</div>
          </div>
          <img src="/images/manageCenter/total4.png" alt="" />
        </div>
        <div class="equipmentCard">
          <div class="label">处理率</div>
          <div class="number">
            {{ warningManage }}
            <div class="downIcon iconfont">&#xe651;</div>
          </div>
          <img src="/images/manageCenter/total1.png" alt="" />
        </div>
      </div>
      <div class="equipmentStatus">
        <div class="bar-chart">
          <div class="title">预警数量趋势</div>
          <!-- <div class="control">
            <div class="label" @click="select('day', 'selectBar')" :class="{ active: selectBar === 'day' }">
              今日
            </div>
            <div class="label" @click="select('week', 'selectBar')" :class="{ active: selectBar === 'week' }">
              本周
            </div>
            <div class="label" @click="select('month', 'selectBar')" :class="{ active: selectBar === 'month' }">
              本月
            </div>
          </div> -->
          <div id="bar"></div>
        </div>
      </div>
      <div class="hashRate">
        <div class="left">
          <div class="title">预警数据占比:</div>
          <div class="info">
            <div class="equipmentInfo" style="margin-top:25px">
              <div class="equipmentCard">
                <div class="label">整改总量</div>
                <div class="number">
                  {{ solvedTotal }}
                  <!-- <div class="upIcon iconfont">&#xe62e; 2</div> -->
                </div>
                <!-- <img src="/images/manageCenter/total2.png" alt="" /> -->
              </div>
              <div class="equipmentCard">
                <div class="label">日均次数</div>
                <div class="number">
                  {{ solvedPre }}
                  <!-- <div class="upIcon iconfont">&#xe62e; 2</div> -->
                </div>
                <!-- <img src="/images/manageCenter/total2.png" alt="" /> -->
              </div>
            </div>
            <div class="table-area">
              <el-table
                id="table"
                ref="table"
                tooltip-effect="dark"
                :data="tableDataList"
                :fit="true"
                :stripe="true"
                :max-height="350"
                class="gutter"
              >
                <el-table-column prop="date" label="日期" show-overflow-tooltip></el-table-column>
                <el-table-column prop="count" align="center" label="整改数量" show-overflow-tooltip></el-table-column>
              </el-table>
              <el-pagination
                @current-change="refrash"
                @size-change="handleSizeChange"
                :current-page="page"
                :page-size="size"
                layout="total, sizes, prev, pager, next, jumper"
                :page-sizes="[5, 10, 15, 20, 25]"
                :total="solvedTotal"
                background
              ></el-pagination>
            </div>
          </div>
        </div>
        <div class="right">
          <div class="title">算法预警数据占比</div>
          <div id="pieChart"></div>
        </div>
      </div>
    </div>
    <!-- 页尾 -->
    <Footer :isBlack="true"></Footer>
  </div>
</template>
<script>
export default {};
import IndexHeader from "@/components/IndexHeader"
import Footer from "@/components/Footer"
import * as echarts from "echarts"
import "echarts/map/js/china.js"
import * as Base64 from "js-base64"
import { analysisReport } from "@/api/es"
import { getLocalCameraTree } from "@/api/area"
import { getClusterDevList } from "@/api/clusterManage"
export default {
  components: {
    IndexHeader,
    Footer
  },
  computed: {
    solvedPre() {
      if (this.solvedTotal == 0 || this.tableDataList.length == 0) {
        return 0
      }
      return parseInt(this.solvedTotal / this.tableDataList.length)
    },
    warningManage() {
      if (this.warningChecked == 0 || this.warningTotal == 0) {
        return 0
      }
      return parseInt(this.warningChecked / this.warningTotal) * 100 + "%"
    }
  },
  data() {
    return {
      lineChart: {},
      pieChart: {},
      searchTree: "",
      selectedOrg: "",
      selectNodes: [],
      searchTime: [
        this.$moment()
          .subtract(6, "days")
          .format("YYYY-MM-DD 00:00:00"),
        this.$moment().format("YYYY-MM-DD HH:mm:ss")
      ],
      alarmValues: "",
      userName: "",
      timeMsg: "",
      selectBar: "day",
      selectForm: "day",
      productList: [
        {
          name: "设备管理",
          icon: "/images/manageCenter/manage.png",
          openPath: "/equipmentManagement",
          path: "/equipmentList",
          permission: "deviceMng"
        },
        {
          name: "算力管理",
          icon: "/images/manageCenter/manage2.png",
          openPath: "/hashrate",
          path: "/hashrateDetail",
          permission: "analysisMng"
        },
        {
          name: "统计查询",
          icon: "/images/manageCenter/search.png",
          openPath: "/searchOpen",
          path: "/search",
          permission: "statisticMng"
        },
        {
          name: "推送管理",
          icon: "/images/manageCenter/manage2.png",
          openPath: "/report",
          path: "/report",
          permission: "statisticMng"
        }
      ],
      cameraTree: [],
      menuTree: [],
      levelOptions: [
        { id: 0, value: "", label: "全部" },
        { id: 1, value: "一级", label: "一级" },
        { id: 2, value: "二级", label: "二级" },
        { id: 3, value: "三级", label: "三级" },
        { id: 4, value: "四级", label: "四级" },
        { id: 5, value: "五级", label: "五级" }
      ],
      barOption: {
        grid: {
          left: "3%",
          right: "3%",
          bottom: "10%",
          containLabel: true
        },
        legend: {
          x: "right",
          y: "top",
          itemHeight: 2,
          itemWidth: 2,
          icon: "circle"
        },
        tooltip: {},
        xAxis: {
          type: "category",
          boundaryGap: false,
          axisTick: {
            show: false
          },
          axisLabel: {
            color: "#666"
          },
          data: []
        },
        yAxis: {
          axisTick: {
            show: false
          },
          axisLine: {
            //y轴
            show: false
          },
          axisLabel: {
            color: "#666"
          },
          splitLine: {
            //网格线
            lineStyle: {
              color: "rgb(230, 230, 230)",
              type: "dashed" //设置网格线类型 dotted:虚线   solid:实线
            },
            show: true //隐藏或显示
          }
        },
        // Declare several bar series, each will be mapped
        // to a column of dataset.source by default.
        series: [
          {
            type: "line",
            data: [],
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                {
                  offset: 0,
                  color: "#0066FF"
                },
                {
                  offset: 1,
                  color: "rgba(0, 102, 255, 0.25)"
                }
              ])
            },
            color: {
              type: "linear",
              x: 0.02,
              y: 0.02,
              x2: 1,
              y2: 1,
              colorStops: [
                {
                  offset: 0,
                  color: "#0066FF" // 0% 处的颜色
                  // radius: ["50%", "80%"]
                },
                {
                  offset: 1,
                  color: "rgba(0, 102, 255, 0.25)" // 100% 处的颜色
                }
              ],
              global: false // 缺省为 false
            },
            itemStyle: {
              //柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
              normal: {
                //柱形图圆角,初始化效果
                barBorderRadius: [15, 15, 0, 0]
              }
            }
          }
        ]
      },
      pieOption: {
        legend: {
          top: "bottom"
        },
        color: [
          "rgb(54, 60, 231)",
          "rgb(54, 178, 74)",
          "rgb(255, 178, 36)",
          "rgb(240, 190, 231)",
          "rgb(255, 124, 31)",
          "rgb(165, 96, 255)"
        ],
        series: [
          {
            name: "Nightingale Chart",
            type: "pie",
            radius: [20, 160],
            center: ["50%", "50%"],
            roseType: "area",
            itemStyle: {
              borderRadius: 8
            },
            label: {
              show: false
            },
            data: []
          }
        ]
      },
      tableDataList: [],
      page: 1,
      size: 5,
      solvedTotal: 0,
      warningTotal: 0,
      warningChecked: 0,
      warningSolved: 0
    }
  },
  created() {
    this.getInfo()
  },
  mounted() {
    this.searchHandler()
    this.initBar()
    this.initPie()
    this.getCameras()
  },
  methods: {
    async getCameras() {
      let clusterId = ""
      let clusterReq = await getClusterDevList()
      if (clusterReq && clusterReq.success) {
        if (clusterReq.data.clusterList.length > 0) {
          clusterId = clusterReq.data.clusterList[0].cluster_id
        }
      }
      let camereReq = await getLocalCameraTree({ clusterId: clusterId })
      if (camereReq && camereReq.success) {
        this.cameraTree = camereReq.data.treeMenu
        let tmpTree = JSON.parse(JSON.stringify(camereReq.data.treeMenu))
        for (let i = 0; i < tmpTree.length; i++) this.clearNode(tmpTree[i])
        this.menuTree = tmpTree
      }
    },
    clearNode(tree) {
      if (tree.children) {
        tree.children = tree.children.filter((item) => {
          return item.type == "MENU"
        })
      }
      if (tree.children && tree.children.length > 0) {
        for (let i = 0; i < tree.children.length; i++) this.clearNode(tree.children[i])
      } else {
        delete tree.children
      }
    },
    collSelectedNodes() {
      let selectedNodeId = this.selectedOrg
      let selectedNode = {}
      let orgNodeIds = []
      if (this.selectedOrg == "") {
        return orgNodeIds
      }
      function findNode(node) {
        if (node.id == selectedNodeId) {
          selectedNode = node
          return
        }
        if (node.children) {
          node.children.forEach((n) => {
            findNode(n)
          })
        }
      }
      function collNode(node) {
        if (node.type != "MENU") {
          orgNodeIds.push(node.id)
          return
        }
        if (node.children) {
          node.children.forEach((n) => {
            collNode(n)
          })
        }
      }
      this.cameraTree.forEach((n) => {
        findNode(n)
      })
      collNode(selectedNode)
      return orgNodeIds
    },
    searchHandler() {
      let query = {
        treeNodes: this.collSelectedNodes(),
        searchTime: this.format(this.searchTime),
        alarmLevel: this.alarmValues
      }
      analysisReport(query).then((rsp) => {
        if (rsp && rsp.success) {
          this.decodeWarningRate(rsp.data.warningRate)
          this.decodeWarningChartRate(rsp.data.warningChartRate)
          this.decodeWarningStatics(rsp.data.warningTable)
          this.decodeWarningTable(rsp.data.warningStatics)
        }
      })
    },
    decodeWarningTable(b64data) {
      this.solvedTotal = 0
      this.tableDataList = []
      if (b64data) {
        let decodeString = Base64.decode(b64data)
        if (decodeString != "") {
          let decodeResult = JSON.parse(decodeString)
          decodeResult = []
          if (decodeResult) {
            decodeResult.forEach((element) => {
              this.solvedTotal = this.solvedTotal + element.doc_count
              this.tableDataList.push({ date: element.key_as_string, count: element.doc_count })
            })
          }
        }
      }
    },
    // 折线图
    decodeWarningStatics(b64data) {
      this.lineChart.clear()
      this.barOption.xAxis.data = []
      this.barOption.series[0].data = []
      if (b64data) {
        let decodeString = Base64.decode(b64data)
        if (decodeString != "") {
          let decodeResult = JSON.parse(decodeString)
          if (decodeResult) {
            decodeResult.forEach((element) => {
              this.barOption.xAxis.data.push(element.key_as_string)
              this.barOption.series[0].data.push(element.doc_count)
            })
          }
        }
      }
      this.lineChart.setOption(this.barOption)
    },
    // 饼图
    decodeWarningChartRate(b64data) {
      this.pieChart.clear()
      this.pieOption.series[0].data = []
      if (b64data) {
        let decodeString = Base64.decode(b64data)
        if (decodeString != "") {
          let decodeResult = JSON.parse(decodeString)
          if (decodeResult) {
            decodeResult.forEach((element) => {
              this.pieOption.series[0].data.push({ value: element.doc_count, name: element.key })
            })
          }
        }
      }
      this.pieChart.setOption(this.pieOption)
    },
    // "warningRate": {"buckets":[{"doc_count":4,"key":3},{"doc_count":3,"key":2},{"doc_count":1,"key":1}],"total":3257}
    //key 1=误报数据,2=已整改,3=未整改,4=已排查 doc_count=数量 total=总量
    decodeWarningRate(b64data) {
      if (b64data) {
        this.warningTotal = 0
        this.warningSolved = 0
        this.warningChecked = 0
        let decodeString = Base64.decode(b64data)
        if (decodeString != "") {
          let decodeResult = JSON.parse(decodeString)
          if (decodeResult && decodeResult.total > 0) {
            this.warningTotal = decodeResult.total
            decodeResult.buckets.forEach((element) => {
              switch (element.key) {
                case 2:
                  this.warningSolved += element.doc_count
                  break
                case 4:
                  this.warningChecked += element.doc_count
                  break
                default:
                  break
              }
            })
          }
          // console.log("WarningRate:", decodeResult)
        }
      }
    },
    handleTreeChange(value) {
      this.selectedOrg = value[value.length - 1]
    },
    getInfo() {
      if (sessionStorage.getItem("userInfo")) {
        this.userName = JSON.parse(sessionStorage.getItem("userInfo")).username
      }
      let date = new Date()
      let year = date.getFullYear() //获取完整的年份(4位)
      let month = date.getMonth() + 1 //获取当前月份(0-11,0代表1月)
      let day = date.getDate() //获取当前月份(0-11,0代表1月)
      let weekDay = ""
      switch (date.getDay()) {
        case 0:
          weekDay = "星期日"
          break
        case 1:
          weekDay = "星期一"
          break
        case 2:
          weekDay = "星期二"
          break
        case 3:
          weekDay = "星期三"
          break
        case 4:
          weekDay = "星期四"
          break
        case 5:
          weekDay = "星期五"
          break
        case 6:
          weekDay = "星期六"
          break
      }
      this.timeMsg = "今日, " + year + "年" + month + "月" + day + "日" + weekDay
    },
    select(value, type) {
      this[type] = value
    },
    initBar() {
      let bartDom = document.getElementById("bar")
      this.lineChart = echarts.init(bartDom)
      this.lineChart.setOption(this.barOption)
    },
    initPie() {
      let pieDom = document.getElementById("pieChart")
      this.pieChart = echarts.init(pieDom)
      this.pieChart.setOption(this.pieOption)
    },
    jump(route) {
      const userInfo = JSON.parse(sessionStorage.getItem("userInfo"))
      const val = userInfo.permissions.find((item) => {
        return item == route.permission
      })
      if (val) {
        if (route.path === "/search") {
          const { href } = this.$router.resolve({
            path: "/search"
          })
          window.open(href, "_blank")
          return
        }
        this.$router.push(route.path)
      } else if (!userInfo.parentId) {
        this.$router.push(route.openPath)
      }
    },
    refrash() {},
    handleSizeChange() {},
    format(array) {
      if (!array || array.length === 0) {
        return []
      }
      return [
        this.$moment(array[0]).format("YYYY-MM-DD HH:mm:ss"),
        this.$moment(array[1]).format("YYYY-MM-DD HH:mm:ss")
      ]
    }
  }
}
</script>
<style>
</style>
<style lang="scss" scoped>
.manageCenter {
  box-sizing: border-box;
  min-width: 1346px;
  background-color: rgb(243, 245, 248);
  .p-statis {
    display: flex;
    padding-right: 10px;
    box-sizing: border-box;
    margin-top: 20px;
    b:hover {
      color: #2249b4;
    }
  }
  .title {
    margin-bottom: 20px;
    box-sizing: border-box;
    padding-left: 10px;
    border-left: 4px solid #0064ff;
    font-size: 16px;
    font-weight: 700;
  }
  .control {
    position: absolute;
    display: flex;
    top: 20px;
    right: 20px;
    .label {
      margin-left: 10px;
      width: 44px;
      height: 24px;
      line-height: 24px;
      font-size: 14px;
      text-align: center;
      color: #666;
      cursor: pointer;
      &.active {
        background: #0064ff;
        border-radius: 12px;
        color: #fff;
      }
    }
  }
  .centerTitle {
    box-sizing: border-box;
    padding-top: 47px;
    height: 150px;
    background-image: url("/images/manageCenter/Rectangle 2180.png");
    .welcome {
      font-size: 14px;
      font-weight: 700;
    }
    .time {
      margin-top: 5px;
      font-size: 12px;
      color: #999;
    }
  }
  .products {
    box-sizing: border-box;
    margin: 24px 0;
    padding: 20px;
    max-height: 282px;
    background-color: #fff;
    .productList {
      display: flex;
      .productItem {
        margin-right: 20px;
        width: 190px;
        height: 90px;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 5px;
        border: 1px solid #e9ebee;
        cursor: pointer;
        img {
          width: 60px;
          height: 60px;
        }
        .name {
          font-size: 14px;
          color: #666;
        }
        &:hover {
          box-shadow: 0px 2px 16px 0px rgba(0, 43, 106, 0.25);
        }
        &:nth-child(6n) {
          margin-right: 0px;
        }
      }
    }
  }
  .equipmentInfo {
    display: flex;
    justify-content: space-between;
    .equipmentCard {
      position: relative;
      overflow: hidden;
      box-sizing: border-box;
      padding: 20px 0 20px 40px;
      width: 302px;
      height: 100px;
      border-radius: 5px;
      font-size: 14px;
      color: #fff;
      .number {
        display: flex;
        font-size: 32px;
        font-weight: 700;
        align-items: end;
      }
      .iconfont {
        padding: 0 5px 0 2px;
        margin-left: 10px;
        font-size: 12px;
        font-weight: normal;
        margin-bottom: 6px;
        background-color: #fff;
        border-radius: 7px;
        &.upIcon {
          color: #ff6a00;
        }
        &.downIcon {
          color: #3fb54a;
        }
      }
      img {
        position: absolute;
        width: 96px;
        height: 96px;
        top: 10px;
        right: -10px;
        opacity: 0.2;
      }
      &:nth-child(1) {
        background: linear-gradient(108deg, #0065ff -8%, #0065ff -8%, #99cfff 100%, #99cfff 100%);
      }
      &:nth-child(2) {
        background: linear-gradient(108deg, #ff6a00 0%, #ff6a00 0%, #ffb599 100%, #ffb599 100%);
      }
      &:nth-child(3) {
        background: linear-gradient(108deg, #6d44e5 1%, #6d44e5 1%, #b299ff 100%, #b299ff 100%);
      }
      &:nth-child(4) {
        background: linear-gradient(108deg, #40b63a 0%, #40b63a 0%, #89e5bc 100%, #89e5bc 100%);
      }
    }
  }
  .equipmentStatus {
    display: flex;
    justify-content: space-between;
    margin: 24px 0;
    height: 466px;
    .bar-chart {
      box-sizing: border-box;
      position: relative;
      padding: 20px;
      background-color: #fff;
      width: 100%;
      height: 466px;
      #bar {
        height: 440px;
      }
    }
    .right {
      box-sizing: border-box;
      padding: 20px;
      width: 411px;
      height: 466px;
      background: #ffffff;
    }
  }
  .performence {
    box-sizing: border-box;
    position: relative;
    padding: 20px;
    background-color: #fff;
    width: 1280px;
    height: 570px;
    .el-pagination ::v-deep {
      margin-left: 650px;
      margin-top: 30px;
      text-align: center;
      height: 24px;
      .el-pagination__sizes {
        margin-right: 0;
      }
      button {
        margin: 0;
        background-color: #fff;
        border: 1px solid #c0c5cc;
        border-radius: 2px;
      }
      .number {
        background-color: #fff;
        &:not(.disabled):hover {
          color: #0065ff;
        }
        &:not(.disabled).active {
          background-color: #0065ff;
          color: #fff;
        }
      }
      .el-input .el-input__inner {
        padding-left: 0;
        &:hover,
        &:focus {
          border-color: #0065ff;
        }
      }
    }
  }
  .map {
    overflow: hidden;
    box-sizing: border-box;
    padding: 20px;
    margin: 24px 0;
    background-color: #fff;
    height: 598px;
    #mapChart {
      margin-top: -100px;
      width: 1100px;
      height: 600px;
    }
  }
  .hashRate {
    margin-bottom: 20px;
    display: flex;
    height: 540px;
    .left {
      position: relative;
      box-sizing: border-box;
      padding: 20px;
      margin-right: 24px;
      width: 737px;
      background-color: #fff;
      #scatterChart {
        height: 500px;
      }
      .table-area {
        margin-top: 10px;
        margin-bottom: 5px;
        width: 700px;
      }
    }
    .right {
      box-sizing: border-box;
      padding: 20px;
      width: 519px;
      height: 540px;
      background: #ffffff;
      #pieChart {
        margin-top: -40px;
        height: 500px;
      }
    }
    .info {
      position: absolute;
      top: 20px;
      right: 20px;
      .item {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        .label {
          margin-right: 8px;
          font-size: 14px;
          color: #666;
        }
        .data {
          font-size: 18px;
          font-weight: 700;
        }
      }
    }
  }
}
</style>