zhangzengfei
2020-07-29 577edb4400290865acb07f8342f7ee0c1055aa70
appp:添加算力管理
4个文件已添加
2个文件已修改
905 ■■■■■ 已修改文件
package.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/subComponents/SystemInfo.vue 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/analysisPower/index/App.vue 608 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/analysisPower/index/main.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/analysisPower/index/mixins.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/desktop/index/mock/userData.json 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -11,7 +11,8 @@
    "@hscmap/vue-window": "^2.4.2",
    "axios": "^0.19.2",
    "d3-force": "^2.0.1",
    "element-ui": "^2.4.6",
    "echarts": "^4.8.0",
    "element-ui": "^2.13.2",
    "less-loader": "^6.2.0",
    "pug": "^3.0.0",
    "pug-plain-loader": "^1.0.0",
@@ -22,6 +23,7 @@
    "stylus-loader": "^3.0.2",
    "vue": "^2.6.11",
    "vue-awesome-swiper": "^3.1.3",
    "vue-js-toggle-button": "^1.3.3",
    "vue-qrcode-component": "^2.1.1",
    "vuex": "^3.5.1"
  },
@@ -75,4 +77,4 @@
  "keywords": [],
  "author": "",
  "license": "ISC"
}
}
src/components/subComponents/SystemInfo.vue
New file
@@ -0,0 +1,204 @@
<template>
  <div :class="showClass">
    <div class="card-box" :style="`width:${borderWidth}`">
      <ul>
        <li style="max-width:30px;" v-if="ShowLocalVedio">
          <div class="total-box">
            <div style="width:100%;margin-top:28px;">
              <div class="top-text">
                <em>{{"总算力"}}</em>
              </div>
              <div class="mid-text">
                <em>{{` ${PollData.channelTotal}`}}</em>
              </div>
            </div>
          </div>
        </li>
        <li style="max-width:120px" v-if="showRealPoll">
          <DataStackCard
            style="width:95%"
            title="实时算力"
            fourTip="故障导致未处理"
            fourIcon="iconicon-test21"
            :total="`${PollData.RealTimeValidCount}路`"
            :ValidCount="`${PollData.RealTimeSum}路`"
            :InValidCount="`${PollData.RealTimeInvalid}路`"
            :RunningCount="`${PollData.RealTimeRun}路`"
            :NoDeal="`${PollData.RealTimeNoDeal}路`"
          />
        </li>
        <li style="max-width:120px" v-if="showRealPoll">
          <DataStackCard
            title="轮询算力"
            fourTip="等待轮询处理"
            fourIcon="iconicon-test2"
            style="width:95%"
            :total="`${PollData.PollValidCount}路`"
            :ValidCount="`${PollData.PollSum}路`"
            :InValidCount="`${PollData.PollInvalid}路`"
            :RunningCount="`${PollData.PollRun}路`"
            :NoDeal="`${PollData.PollNoDeal}路`"
          />
        </li>
        <li style="max-width:120px" v-if="ShowLocalVedio">
          <!-- <local-vedio-card
            title="本地算力"
            style="width:95%"
            :total="`${PollData.localVideo}通道`"
            :success="`${PollData.PollRun}路`"
            :warning="`${PollData.PollInvalid}路`"
          />-->
          <DataStackCard
            title="数据栈算力"
            style="width:95%"
            fourTip="未知原因导致未处理"
            fourIcon="iconicon-test5"
            :total="`${PollData.stackChannelCount}路`"
            :ValidCount="`${PollData.stackTotal}路`"
            :InValidCount="`${PollData.stackInvalidCount}路`"
            :RunningCount="`${PollData.stackRunningCount}路`"
            :NoDeal="`${PollData.stackNoDeal}路`"
          ></DataStackCard>
        </li>
      </ul>
    </div>
    <!-- <div :class="marginTop" :style="`width:${liquidWidth};`">
      <ul>
        <li>
          <liquid-fill-chart title="内存" :value="PollData.MemUsedPercent" :size="75" />
        </li>
        <li>
          <liquid-fill-chart title="算力" :value="PollData.GpuUsedPercent" :size="75" />
        </li>
        <li>
          <liquid-fill-chart title="CPU" :value="PollData.CpuUsedPercent" :size="75" />
        </li>
      </ul>
    </div>-->
    <div class="eCharts-box" :style="`width:${liquidWidth}`">
      <eChartsBar ref="cpuMeneryCharts" :xAxisData="PollData.barCharts"></eChartsBar>
    </div>
  </div>
</template>
<script>
import DataStackCard from "@/components/subComponents/DataStackCard"
import eChartsBar from '@/components/subComponents/eChartsBar'
export default {
  name: "SystemInfo",
  components: {
    DataStackCard,
    eChartsBar,
  },
  props: {
    showTask: {
      type: Boolean,
      default: false
    },
    showClass: {
      type: String,
      default: 'sysinfo-box flex-box'
    },
    ShowLocalVedio: {
      type: Boolean,
      default: false
    },
    showRealPoll: {
      type: Boolean,
      default: true
    },
    marginTop: {
      type: String,
      default: 'ma'
    },
    borderWidth: {
      type: String,
      default: '70%'
    },
    liquidWidth: {
      type: String,
      default: '30%'
    }
  },
  methods: {
    initCpuCharts() {
      this.$forceUpdate();
    }
  },
}
</script>
<style lang="scss">
.sysinfo-box {
  height: 100%;
  .card-box {
    width: 50%;
    @media screen and (min-width: 1280px) and (max-width: 1440px) {
      width: 65%;
    }
    @media screen and (max-width: 1279px) {
      width: 70%;
    }
    .total-box {
      height: 120px;
      width: 100%;
      display: inline-block;
      margin: 10px 5px;
      background: #ffffff;
      border: 1px solid #e2e2e2;
      box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07);
      border-radius: 4px;
      cursor: pointer;
      .top-text {
        line-height: 30px;
        font-family: PingFangSC-Medium;
        font-size: 14px;
        color: #222222;
      }
      .mid-text {
        margin-bottom: 18px;
        font-family: PingFangSC-Medium;
        font-size: 18px;
        color: #ff7733;
      }
      .bottom-text {
        position: relative;
        top: 3px;
        left: 1px;
        color: #666666;
        font-size: 13px;
      }
      em {
        font-weight: 700;
      }
    }
  }
  .eCharts-box {
    width: 50%;
    height: 100%;
    margin-left: 5px;
    @media screen and (min-width: 1280px) and (max-width: 1440px) {
      width: 35%;
    }
    @media screen and (max-width: 1279px) {
      width: 30%;
    }
  }
  .chart-box {
    float: left;
    width: 50%;
    margin-top: 20px;
    margin-left: 20px;
  }
  ul {
    list-style: none;
    display: table;
    width: 100%;
    li {
      display: table-cell;
      text-align: center;
      vertical-align: top;
    }
  }
}
</style>
src/pages/analysisPower/index/App.vue
New file
@@ -0,0 +1,608 @@
<template>
  <div class="s-poll-setting">
    <div class="top" v-show="!strethTable">
      <div class="percentBall">
        <sysinfo
          ref="sysInfo"
          v-if="showSysInfo"
          :ShowLocalVedio="true"
          showTask
          showClass="sysinfo-box flex-row-left"
        />
      </div>
      <div class="barGraph">
        <div id="barSimple"></div>
      </div>
    </div>
    <div class="bottom">
      <div style="width: 100%;height: 10px;background-color: #E9EBF2;"></div>
      <div class="content">
        <div class="toolBar">
          <el-input
            size="small"
            style="width: 180px;"
            placeholder="请输入搜索内容"
            prefix-icon="el-icon-search"
            clearable
            v-model="PollData.SearchName"
          ></el-input>
          <el-button
            size="small"
            type="primary"
            style="margin-left: 20px; margin-right: 50px;"
            @click="pollSeach"
          >搜索</el-button>
          <div class="tip">
            <span>
              轮询时间 :
              <b>{{PollData.Config.poll_period}}</b>分钟
            </span>
            <span>
              轮询周期 :
              <b>{{pollCycle}}</b>分钟
            </span>
            <span>
              轮询开关 :
              <b>{{PollData.Enabled | switchText}}</b>
            </span>
          </div>
          <span :class="stretchStyle" @click="strethTable = !strethTable"></span>
          <el-button size="small" type="primary" style="float:right" @click="openDrawer">设置</el-button>
        </div>
        <el-table
          :header-cell-style="{background:'#F8F8F8', color: '#222222'}"
          :data="PollData.CameraList"
          height="93%"
          border
        >
          <el-table-column label="序号" type="index" align="center" width="100px"></el-table-column>
          <el-table-column label="摄像机名称" align="center" show-overflow-tooltip sortable>
            <template slot-scope="scope">
              <span
                :style="scope.row.is_running ? `color:#3d68e1` : '' "
              >{{scope.row.alias !== '' ? scope.row.alias: scope.row.name}}</span>
            </template>
          </el-table-column>
          <el-table-column label="摄像机地址" prop="addr" align="center" show-overflow-tooltip sortable></el-table-column>
          <el-table-column label="摄像机IP" prop="ip" align="center" width="130px" sortable></el-table-column>
          <el-table-column label="摄像机类型" align="center" width="110px" sortable>
            <template slot-scope="scope">
              <span>{{scope.row.run_type | cameraType}}</span>
            </template>
          </el-table-column>
          <el-table-column label="执行算法" align="center" show-overflow-tooltip sortable>
            <template slot-scope="scope">
              <span v-if="scope.row.run_type === -1 ">-</span>
              <span v-else>{{scope.row.tasks | taskList}}</span>
            </template>
          </el-table-column>
          <el-table-column label="运行设备" align="center" width="160px">
            <template slot-scope="scope">
              <span v-if="scope.row.run_type === -1 ">-</span>
              <span v-else>{{scope.row.runServerName}}</span>
            </template>
          </el-table-column>
          <el-table-column label="状态" align="center" show-overflow-tooltip sortable width="100px">
            <template slot-scope="scope">
              <span v-if="scope.row.status === -1 ">-</span>
              <span v-else-if="scope.row.status === 2">{{"处理中"}}</span>
              <span v-else-if="scope.row.status === 1">{{"等待处理"}}</span>
              <span v-else-if="scope.row.status === 0">{{"规则不全"}}</span>
            </template>
          </el-table-column>
          <el-table-column label="实时/轮询" align="center" width="100px">
            <template slot-scope="scope">
              <span v-if="scope.row.run_type === -1 ">-</span>
              <toggle-button
                v-else
                :value="scope.row.run_type === 1"
                :width="60"
                :labels="{checked: '实时', unchecked: '轮询'}"
                :color="{checked: '#4D88FF', unchecked: '#FF7733', disabled: '#CCCCCC'}"
                :sync="true"
                @change="pollSwitch(scope.row)"
              />
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <!-- 设置弹窗 -->
    <el-drawer
      title="算力设置"
      :visible.sync="drawer"
      direction="rtl"
      size="350px"
      custom-class="e-drawer"
      :before-close="closeDrawer"
    >
      <div class="dawer_details">
        <span>总算力 {{formData.totalChanle}} 通道</span>
        <span style="margin-left:20px">实时算力 {{formData.realTime}} 通道</span>
      </div>
      <div class="e-drawer_rate">
        <div class="rate">
          <label>轮询时间</label>
          <el-input-number
            size="small"
            style="width: 60px;margin-left:25px"
            v-model.number="formData.pollPeriod"
            :controls="false"
            :min="0"
            :max="60 * 24 * 1"
          ></el-input-number>
          <span>分钟</span>
          <label>轮询开关</label>
          <el-switch style="margin-left: 10px;" v-model="formData.pollEnable"></el-switch>
        </div>
        <div class="rate">
          <label>轮询算力</label>
          <el-input-number
            style="margin-left:25px;width:90px"
            size="small"
            v-model="formData.polling"
            @change="changePoll"
            controls-position="right"
            :min="0"
            :max="maxPoll"
          ></el-input-number>
        </div>
        <div class="rate">
          <label>数据栈算力</label>
          <el-input-number
            style="margin-left:11px;width:90px"
            size="small"
            v-model="formData.dataStack"
            @change="changeStack"
            controls-position="right"
            :min="0"
            :max="maxDataStack"
          ></el-input-number>
        </div>
        <el-button
          size="small"
          type="primary"
          style="margin:10px 10px 0px 200px"
          @click="saveSetting"
        >保存</el-button>
        <el-button size="small" type="info" style="color:black" @click="closeDrawer">取消</el-button>
      </div>
    </el-drawer>
  </div>
</template>
<script>
import echarts from "echarts";
import { changeRunType, updatePollEnable, updatePollPeriod, updateChannelCount } from "@/api/pollConfig";
import Sysinfo from "@/components/subComponents/SystemInfo"
// import SliderVedio from '@/components/camera/slider-vedio'
// import eChartsBar from '@/components/subComponents/eChartsBar'
export default {
  name: "PollSeting",
  components: {
    Sysinfo,
    // SliderVedio,
    // eChartsBar
  },
  filters: {
    cameraType(type) {
      return type === -1 ? "监控摄像机" : "AI摄像机";
    },
    taskList(tasks) {
      return tasks.filter(task => {
        return task.hasRule;
      }).map(task => {
        return task.taskname
      }).join(',')
    },
    switchText(type) {
      return type ? "已开启" : "未开启";
    }
  },
  computed: {
    maxPoll() {
      return this.formData.totalChanle - this.formData.realTime;
    },
    maxDataStack() {
      return this.formData.totalChanle - this.formData.realTime;
    },
    stretchStyle() {
      let arry = ["iconfont", "stretch-btn"];
      arry.push(this.strethTable ? "iconzhankai" : "iconshouqi")
      return arry;
    },
    pollCycle() {
      let sumPollingCamera = 0;
      this.PollData.CameraList.forEach(cam => {
        if (cam.run_type === 0) {
          sumPollingCamera++
        }
      })
      return sumPollingCamera * this.PollData.Config.poll_period
    }
  },
  data() {
    return {
      switchValue: true,
      search: "",
      timeout: null,
      taskName: [],
      dataList: [],
      barChart: {},
      localDataChannel: 2,
      showSysInfo: false,
      drawer: false,
      formData: {},
      strethTable: false
    };
  },
  mounted() {
    this.PollData.init();
    this.statistic();
    this.barChart = echarts.init(document.getElementById("barSimple"));
    this.initLineChart();
  },
  beforeDestroy() {
    clearTimeout(this.timeout);
  },
  methods: {
    openDrawer() {
      this.initFormData();
      this.drawer = true;
    },
    closeDrawer() {
      this.drawer = false;
      this.initFormData();
    },
    initFormData() {
      this.formData = {
        totalChanle: this.PollData.channelTotal,
        realTime: this.PollData.RealTimeSum,
        pollEnable: this.PollData.Enabled,
        pollPeriod: this.PollData.Config.poll_period,
        polling: this.PollData.PollChannelTotal,
        dataStack: this.PollData.localVideo,
      }
    },
    pollSeach() {
      this.PollData.fetchPollList();
    },
    pollEnable() {
      updatePollEnable({ enable: this.PollData.Enabled }).then(rsp => {
        this.$notify({
          type: "success",
          message: "修改成功"
        });
        // this.PollData.fetchPollConfig()
      })
    },
    updateDelayTime() {
      updatePollPeriod({ period: this.PollData.Config.poll_period }).then(rsp => {
        if (rsp && rsp.success) {
          this.$notify({
            type: 'success',
            message: '轮询时间修改成功!'
          })
        } else {
          this.$notify({
            type: 'error',
            message: '轮询时间修改失败!'
          })
        }
      })
    },
    statistic() {
      this.PollData.statistics();
      let _this = this;
      _this.timeout = setTimeout(() => {
        _this.statistic();
      }, 10 * 1000);
    },
    pollSwitch(row) {
      changeRunType({ camera_ids: [row.id], run_type: row.run_type ^ 1 }).then(
        rsp => {
          if (rsp && rsp.success) {
            this.$notify({
              type: "success",
              message: "配置成功"
            });
            row.run_type = row.run_type ^ 1
          } else {
            this.$notify({
              type: "error",
              message: "配置失败"
            });
          }
          // this.PollData.fetchPollList();
        }
      );
    },
    initLineChart() {
      // console.log(this.barChart,'initLineChart')
      // this.$refs.sysInfo.initCpuCharts();
      let optionBar = {
        color: ["#3D68E1"],
        tooltip: {
          trigger: "axis",
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: "shadow" // 默认为直线,可选为:'line' | 'shadow'
          }
        },
        grid: {
          top: 40,
          // bottom: '45%',
          left: 0,
          containLabel: true
        },
        xAxis: [
          {
            type: "category",
            data: this.taskName,
            axisTick: {
              // alignWithLabel: true
            },
            axisLine: {
              show: false
            },
            nameLocation: 'start',
            axisTick: {
              show: false
            },
            axisLabel: {
              rotate: 45,
              formatter: function (value, index) {
                let name = ""
                if (value.length > 2) {
                  name = value.substring(0, 2) + '...'
                } else {
                  name = value
                }
                let text = [`{a|${name}}`]
                return text
              },
              rich: {
                a: {
                  fontSize: 10,
                  with: 30
                }
              }
            }
          }
        ],
        yAxis: [
          {
            type: "value",
            show: true,
            axisLine: {
              show: false
            },
            splitLine: {
              lineStyle: {
                type: "dotted",
                color: ['#f1f1f1']
              }
            },
            axisTick: {
              show: false
            }
          }
        ],
        series: [
          {
            name: "数量",
            type: "bar",
            barWidth: "30%",
            data: this.dataList
          }
        ]
      };
      this.showSysInfo = true
      this.barChart.setOption(optionBar);
      this.barChart.resize()
      this.$nextTick(() => {
        this.barChart.resize()
      })
    },
    //滑块数据更新回调
    changeSlider(val) {
      // console.log(val, '滑块值变动')
      let fileChannelCount = val[val.length - 1] - val[val.length - 2]
      let pollChannelCount = val[val.length - 2] - val[val.length - 3]
      this.PollData.updateChannelCount(fileChannelCount, pollChannelCount)
    },
    async saveSetting() {
      let rsp = await updatePollEnable({ enable: this.formData.pollEnable })
      if (!rsp || !rsp.success) {
        this.formData.pollEnable = !this.formData.pollEnable
        this.$notify({
          type: "error",
          message: "轮询开关切换失败!"
        });
        return
      }
      rsp = await updatePollPeriod({ period: this.formData.pollPeriod })
      if (!rsp || !rsp.success) {
        this.$notify({
          type: "error",
          message: "轮询时间修改失败!"
        });
        return
      }
      rsp = await updateChannelCount({ videoChannelCount: this.formData.dataStack, pollChannelCount: this.formData.polling })
      if (!rsp || !rsp.success) {
        this.$notify({
          type: "error",
          message: "算力配置失败!"
        });
        return
      } else {
        this.$notify({
          type: "success",
          message: "配置保存成功"
        });
      }
      this.PollData.statisticTaskInfo()
      this.PollData.fetchPollConfig()
    },
    //监听轮询算力
    changePoll(newVal, oldVal) {
      if (newVal > oldVal) {
        this.formData.dataStack--
      }
      if (newVal < oldVal) {
        this.formData.dataStack++
      }
      // console.log("this.formData.dataStack:"+this.formData.dataStack)
    },
    //监听数据栈算力
    changeStack(newVal, oldVal) {
      if (newVal > oldVal) {
        this.formData.polling--
      }
      if (newVal < oldVal) {
        this.formData.polling++
      }
      // console.log("this.formData.polling:"+this.formData.polling)
    }
  }
};
</script>
<style lang="scss">
.s-poll-setting {
  width: 100%;
  height: 100%;
  font-size: 14px;
  position: relative;
  .top {
    width: 100%;
    height: 190px;
    // border-bottom: 1px solid #ccc;
    .progressBar {
      width: 26%;
    }
    .percentBall {
      width: 80%;
      height: 82%;
      float: left;
      // @media screen and (min-width: 1280px) and (max-width: 1440px) {
      //   width: 75%;
      // }
      // @media screen and (max-width: 1280px) {
      //   width: 80%;
      // }
    }
    .barGraph {
      width: 20%;
      height: 100%;
      float: right;
      // @media screen and (min-width: 1280px) and (max-width: 1440px) {
      //   width: 25%;
      // }
      // @media screen and (max-width: 1280px) {
      //   width: 20%;
      // }
      #barSimple {
        width: 100%;
        height: 250px;
        margin-top: -30px;
      }
    }
    .point {
      text-align: right;
      margin-left: 64px;
      b {
        display: inline-block;
        width: 9px;
        height: 9px;
        border-radius: 50%;
        background-color: #f53d3d;
      }
    }
  }
  .bottom {
    width: calc(100% + 76px);
    height: 100%;
    // height: calc(100% - 220px);
    position: absolute;
    // top: 220px;
    left: -38px;
    .tip {
      display: inline-block;
      font-family: PingFangSC-Medium;
      font-size: 14px;
      span {
        margin: 0px 10px;
      }
    }
    .content {
      padding: 20px 38px 38px 38px;
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      .toolBar {
        width: 100%;
        height: 42px;
        text-align: left;
        margin-bottom: 15px;
      }
      .el-table {
        border: 1px solid #e0e0e0;
      }
    }
    .stretch-btn {
      float: right;
      margin-left: 10px;
      line-height: 35px;
      cursor: pointer;
    }
  }
}
.e-drawer {
  // margin-top: 150px;
  font-family: PingFangSC-Medium;
  font-size: 14px;
  .dawer_details {
    text-align: left;
    margin-left: 70px;
    margin-top: 30px;
  }
  .e-drawer_rate {
    width: 100%;
    margin-top: 15px;
    .rate {
      width: 100%;
      text-align: left;
      margin-top: 15px;
      margin-left: 50px;
    }
    label {
      margin-left: 20px;
    }
  }
  .el-drawer__header {
    margin-bottom: 0px;
  }
}
</style>
src/pages/analysisPower/index/main.ts
New file
@@ -0,0 +1,20 @@
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
import "@/assets/css/element-variables.scss";
import "../../../assets/icons/alibaba/iconfont.css";
import "../../../assets/icons/basic/iconfont.css";
import "../../../assets/icons/iconfont.css";
import "../../../assets/icons/symbol.js";
import App from './App.vue'
import ToggleButton from 'vue-js-toggle-button';
import Mixin from "./mixins";
Vue.use(ElementUI)
Vue.use(ToggleButton)
Vue.mixin(Mixin);
new Vue({
  el: '#app',
  render: h => h(App)
})
src/pages/analysisPower/index/mixins.ts
New file
@@ -0,0 +1,13 @@
import DataPool from "@/Pool/PollData"
/* eslint-disable */
const onlyDataPool = new DataPool
const mixin = {
  data() {
    return {
      PollData: onlyDataPool
    };
  },
};
export default mixin;
src/pages/desktop/index/mock/userData.json
@@ -4,12 +4,36 @@
  "data": {
    "docks": [
      {
        "id": "5",
        "src": "../../images/app-mid/GB-config.png",
        "alt": "GB28281配置",
        "type": "2",
        "url": "/view/gb28181",
        "name": "GB28281配置"
      },
      {
        "id": "12",
        "src": "../../images/app-mid/monitor.png",
        "alt": "实时监控-在线播放",
        "type": "2",
        "url": "/view/cameraVideo",
        "name": "实时监控-在线播放"
      },
      {
        "id": "9",
        "src": "../../images/app-mid/algorithm-manage.png",
        "alt": "算法管理",
        "type": "2",
        "url": "/view/algorithmManage",
        "name": "算法管理"
      },
      {
        "id": "1",
        "src": "../../images/app-mid/camera-access.png",
        "alt": "camera-access",
        "type": "2",
        "url": "/view/camera",
        "name":"摄像机接入"
        "name": "摄像机接入"
      },
      {
        "id": "2",
@@ -17,7 +41,7 @@
        "alt": "datastack-config",
        "type": "2",
        "url": "/view/datastack",
        "name":"数据栈配置"
        "name": "数据栈配置"
      },
      {
        "id": "3",
@@ -34,14 +58,6 @@
        "type": "2",
        "url": "/view/datapush",
        "name": "数据推送"
      },
      {
        "id": "5",
        "src": "../../images/app-mid/GB-config.png",
        "alt": "GB28281配置",
        "type": "2",
        "url": "/view/gb28181",
        "name": "GB28281配置"
      },
      {
        "id": "6",
@@ -68,14 +84,6 @@
        "name": "轮询管理"
      },
      {
        "id": "9",
        "src": "../../images/app-mid/algorithm-manage.png",
        "alt": "算法管理",
        "type": "2",
        "url": "/view/algorithmManage",
        "name": "算法管理"
      },
      {
        "id": "10",
        "src": "../../images/app-mid/algorithm-store.png",
        "alt": "算法商城",
@@ -88,16 +96,8 @@
        "src": "../../images/app-mid/hashrate-manage.png",
        "alt": "算力管理",
        "type": "2",
        "url": "/view/hashrateManage",
        "url": "/view/analysisPower",
        "name": "算力管理"
      },
      {
        "id": "12",
        "src": "../../images/app-mid/monitor.png",
        "alt": "实时监控-在线播放",
        "type": "2",
        "url": "/view/monitor",
        "name": "实时监控-在线播放"
      },
      {
        "id": "13",