ci:接口联调

main
lizhichao 2 years ago
parent 801e2f85b9
commit 96099bda98
  1. 19
      src/api/opsVisualization/alarmProcess.js
  2. 25
      src/api/opsVisualization/serviceDataOAM.js
  3. 270
      src/page/index/index.vue
  4. 103
      src/page/index/sidebar/opsSidebar.vue
  5. 888
      src/page/opsVisualization/alarmProcess.vue
  6. 756
      src/page/opsVisualization/serviceDataOAM.vue
  7. 6
      src/permission.js
  8. 25
      src/router/page/index.js
  9. 32
      src/router/views/index.js

@ -0,0 +1,19 @@
import request from '@/router/axios';
//设备类型通讯链路及排除方案
export const getWarnPoint = (params) => {
return request({
url: '/kgApi/monitor-business/getWarnPoint',
method: 'get',
params
})
}
//排查方案信息列表
export const getResolveTips = (params) => {
return request({
url: '/kgApi/monitor-business/getResolveTips',
method: 'get',
params
})
}

@ -0,0 +1,25 @@
import request from '@/router/axios';
//报警设备列表
export const getEquipList = (params) => {
return request({
url: '/kgApi/monitor-business/getEquipList',
method: 'get',
params
})
}
//当前报警信息
export const getWarnMsg = (params) => {
return request({
url: '/kgApi/monitor-business/getWarnMsg',
method: 'get',
params
})
}
//报警记录
export const getWarnHisList = (params) => {
return request({
url: '/kgApi/monitor-business/getWarnHisList',
method: 'get',
params
})
}

@ -1,112 +1,106 @@
<template> <template>
<div class="avue-contail" :class="{'avue--collapse':isCollapse}"> <div class="avue-contail" :class="{ 'avue--collapse': isCollapse }">
<div class="avue-header"> <div class="avue-header">
<div class="avue-left"> <div class="avue-left">
<!-- 左侧导航栏 --> <!-- 左侧导航栏 -->
<sidebar /> <sidebar />
</div> </div>
<!-- 顶部导航栏 --> <!-- 顶部导航栏 -->
<top ref="top" /> <top ref="top" />
</div> </div>
<!-- 运维可视化化左侧导航栏 -->
<opsSidebar v-if="$route.path.indexOf('opsVisualization') != -1"/> <opsSidebar v-if="$route.path.indexOf('opsVisualization') != -1" />
<div class="avue-layout"> <div class="avue-layout">
<div class="avue-main"> <div class="avue-main">
<!-- 顶部标签卡 --> <!-- 顶部标签卡 -->
<!-- <tags /> --> <!-- <tags /> -->
<transition name="fade-scale"> <transition name="fade-scale">
<search class="avue-view" v-show="isSearch"></search> <search class="avue-view" v-show="isSearch"></search>
</transition> </transition>
<!-- 主体视图层 --> <!-- 主体视图层 -->
<div style="height:100%;width: 100%;overflow: auto;" id="avue-view" v-show="!isSearch"> <div
<keep-alive> style="height: 100%; width: 100%; overflow: auto"
<router-view class="avue-view" v-if="$route.meta.keepAlive" /> id="avue-view"
</keep-alive> v-show="!isSearch"
<router-view class="avue-view" v-if="!$route.meta.keepAlive" /> >
</div> <keep-alive>
</div> <router-view class="avue-view" v-if="$route.meta.keepAlive" />
</keep-alive>
</div> <router-view class="avue-view" v-if="!$route.meta.keepAlive" />
<div class="avue-shade" @click="showCollapse"></div> </div>
</div>
</div> </div>
<div class="avue-shade" @click="showCollapse"></div>
</div>
</template> </template>
<script> <script>
import { import { mapGetters } from "vuex";
mapGetters import tags from "./tags";
} from "vuex"; import search from "./search";
import tags from "./tags"; import top from "./top/";
import search from "./search"; import sidebar from "./sidebar/";
import top from "./top/"; import opsSidebar from "./sidebar/opsSidebar";
import sidebar from "./sidebar/"; import admin from "@/util/admin";
import opsSidebar from "./sidebar/opsSidebar"; import { validatenull } from "@/util/validate";
import admin from "@/util/admin"; import { calcDate } from "@/util/date.js";
import { import { getStore } from "@/util/store.js";
validatenull
} from "@/util/validate";
import {
calcDate
} from "@/util/date.js";
import {
getStore
} from "@/util/store.js";
export default { export default {
components: { components: {
top, top,
tags, tags,
search, search,
sidebar, sidebar,
opsSidebar opsSidebar,
}, },
name: "index", name: "index",
provide() { provide() {
return { return {
index: this index: this,
}; };
}, },
data() { data() {
return { return {
// //
isSearch: false, isSearch: false,
//token //token
refreshLock: false, refreshLock: false,
//token //token
refreshTime: "" refreshTime: "",
}; };
}, },
created() { created() {
//token //token
this.refreshToken(); this.refreshToken();
}, },
mounted() { mounted() {
this.init(); this.init();
}, },
computed: mapGetters(["isMenu", "isLock", "isCollapse", "website", "menu"]), computed: mapGetters(["isMenu", "isLock", "isCollapse", "website", "menu"]),
props: [], props: [],
methods: { methods: {
showCollapse() { showCollapse() {
this.$store.commit("SET_COLLAPSE"); this.$store.commit("SET_COLLAPSE");
}, },
// //
init() { init() {
this.$store.commit("SET_SCREEN", admin.getScreen()); this.$store.commit("SET_SCREEN", admin.getScreen());
window.onresize = () => { window.onresize = () => {
setTimeout(() => { setTimeout(() => {
this.$store.commit("SET_SCREEN", admin.getScreen()); this.$store.commit("SET_SCREEN", admin.getScreen());
}, 0); }, 0);
}; };
this.$store.dispatch("FlowRoutes").then(() => {}); this.$store.dispatch("FlowRoutes").then(() => {});
}, },
// //
openMenu(item = {}) { openMenu(item = {}) {
this.$store.dispatch("GetMenu", item.id).then(data => { this.$store.dispatch("GetMenu", item.id).then((data) => {
if (data.length !== 0) { if (data.length !== 0) {
this.$router.$avueRouter.formatRoutes(data, true); this.$router.$avueRouter.formatRoutes(data, true);
} }
// //
/*if (!this.validatenull(item)) { /*if (!this.validatenull(item)) {
let itemActive = {}, let itemActive = {},
childItemActive = 0; childItemActive = 0;
if (item.path) { if (item.path) {
@ -126,40 +120,40 @@
}, itemActive.meta) }, itemActive.meta)
}); });
}*/ }*/
});
}); },
}, // token
// token refreshToken() {
refreshToken() { this.refreshTime = setInterval(() => {
this.refreshTime = setInterval(() => { const token =
const token = getStore({ getStore({
name: "token", name: "token",
debug: true debug: true,
}) || {}; }) || {};
const date = calcDate(token.datetime, new Date().getTime()); const date = calcDate(token.datetime, new Date().getTime());
if (validatenull(date)) return; if (validatenull(date)) return;
if (date.seconds >= this.website.tokenTime && !this.refreshLock) { if (date.seconds >= this.website.tokenTime && !this.refreshLock) {
this.refreshLock = true; this.refreshLock = true;
this.$store this.$store
.dispatch("refreshToken") .dispatch("refreshToken")
.then(() => { .then(() => {
this.refreshLock = false; this.refreshLock = false;
}) })
.catch(() => { .catch(() => {
this.refreshLock = false; this.refreshLock = false;
}); });
} }
}, 10000); }, 10000);
} },
} },
}; };
</script> </script>
<style scoped type="text/css"> <style scoped type="text/css">
.avue-left { .avue-left {
position: relative; position: relative;
width: 80%; width: 80%;
} }
.avue-layout { .avue-layout {
height: calc(100% - 64px); height: calc(100% - 64px);
} }
</style> </style>

@ -6,37 +6,37 @@
@open="handleOpen" @open="handleOpen"
@close="handleClose" @close="handleClose"
background-color="#1E283D" background-color="#1E283D"
active-background-color="red"
text-color="#fff" text-color="#fff"
active-text-color="#ffd04b" active-text-color="#04D4FF"
:default-active="$route.path" :default-active="$route.path"
:unique-opened="true"
router router
> >
<el-submenu index="1"> <el-submenu index="1" popper-class="red">
<template slot="title"> <template slot="title">
<span class="point"></span> <span class="point"></span>
<span>系统监控</span> <span>系统监控</span>
</template> </template>
<el-menu-item-group> <el-menu-item-group>
<el-menu-item index="/opsVisualization/tuobu" <el-menu-item index="/opsVisualization/tuobu">
>系统监控</el-menu-item 系统监控
> </el-menu-item>
<el-menu-item index="/opsVisualization/systemMonitoring" <el-menu-item index="/opsVisualization/systemMonitoring">
>服务监控</el-menu-item 服务监控
> </el-menu-item>
</el-menu-item-group> </el-menu-item-group>
</el-submenu> </el-submenu>
<el-submenu index="2"> <el-submenu index="2" popper-class="red">
<template slot="title"> <template slot="title">
<i class="point"></i> <i class="point"></i>
<span>业务数据运维</span> <span> 业务数据运维</span>
</template> </template>
<el-menu-item-group> <el-menu-item-group>
<el-menu-item index="/opsVisualization/alarmProcess" <el-menu-item index="/opsVisualization/alarmProcess">
>业务数据监控</el-menu-item 业务数据监控</el-menu-item
> >
<el-menu-item index="/opsVisualization/serviceDataOAM" <el-menu-item index="/opsVisualization/serviceDataOAM">
>报警信息记录</el-menu-item 报警信息记录</el-menu-item
> >
</el-menu-item-group> </el-menu-item-group>
</el-submenu> </el-submenu>
@ -50,14 +50,46 @@ export default {
data() { data() {
return {}; return {};
}, },
watch: {}, watch: {
$route(to, from) {
if (
this.$route.path == "/opsVisualization/tuobu" ||
this.$route.path == "/opsVisualization/systemMonitoring"
) {
document.getElementsByClassName(
"el-submenu__title"
)[0].style.background =
"linear-gradient(90deg, #07a7ff 0%, #142a43 100%)";
document.getElementsByClassName(
"el-submenu__title"
)[1].style.background = "#1E283D";
} else if (
this.$route.path == "/opsVisualization/alarmProcess" ||
this.$route.path == "/opsVisualization/serviceDataOAM"
) {
document.getElementsByClassName(
"el-submenu__title"
)[1].style.background =
"linear-gradient(90deg, #07a7ff 0%, #142a43 100%)";
document.getElementsByClassName(
"el-submenu__title"
)[0].style.background = "#1E283D";
}
},
},
computed: {}, computed: {},
mounted() {}, mounted() {
document.getElementsByClassName("el-submenu__title")[0].style.background =
"linear-gradient(90deg, #07a7ff 0%, #142a43 100%)";
},
methods: {}, methods: {},
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.red {
background: green !important;
}
.page { .page {
position: absolute; position: absolute;
top: 64px; top: 64px;
@ -76,5 +108,40 @@ export default {
margin: 0 20px 0 30px; margin: 0 20px 0 30px;
border-radius: 50%; border-radius: 50%;
} }
// /deep/.el-submenu__title:hover {
// background: linear-gradient(90deg, #07a7ff 0%, #142a43 100%);
// }
.el-menu-item {
display: flex;
align-items: center;
&:before {
content: "";
width: 2px;
height: 2px;
display: inline-block;
margin: 0 20px 0 10px;
border-radius: 50%;
}
}
.el-menu-item.is-active {
color: #04d4ff !important;
&:before {
content: "";
width: 2px;
height: 2px;
background: #04d4ff;
display: inline-block;
margin: 0 20px 0 10px;
border-radius: 50%;
}
}
/deep/.el-menu-item-group {
.el-menu-item {
background: rgba(7, 167, 255, 0.15) !important;
}
}
// /deep/.el-submenu__title {
// background: linear-gradient(90deg, #07a7ff 0%, #142a43 100%) !important;
// }
</style> </style>

@ -1,422 +1,486 @@
<template> <template>
<div class="content"> <div class="content">
<div class="process"> <div class="process">
<div class="title">报警节点示意图</div> <div class="title">报警节点示意图</div>
<div class="main"> <div class="main">
<div class="process-example"> <div class="process-example">
<div class="example-title">示例</div> <div class="example-title">示例</div>
<div class="example-box"> <div class="example-box">
<div class="point blue"></div> <div class="point blue"></div>
<div class="value">正常</div> <div class="value">正常</div>
</div> </div>
<div class="example-box margin-right-left-20"> <div class="example-box margin-right-left-20">
<div class="point red"></div> <div class="point red"></div>
<div class="value">报警</div> <div class="value">报警</div>
</div> </div>
<div class="example-box"> <div class="example-box">
<div class="point grey"></div> <div class="point grey"></div>
<div class="value">静默</div> <div class="value">静默</div>
</div> </div>
</div> </div>
<div class="process-center"> <div class="process-center">
<div class="process-node-box"> <div class="process-node-box">
<div class="node-img"> <div class="node-img">
<img class="nav_img" src="../../../public/img/process/node1.png"> <img
<div class="node-text">脚本</div> class="nav_img"
</div> src="../../../public/img/process/node1.png"
<div class="yes-no"> />
<div class="yes"></div> <div class="node-text">脚本</div>
<img class="nav_img" src="../../../public/img/process/yes.png"> </div>
</div> <div class="yes-no">
<div class="node-img"> <div class="yes"></div>
<img class="nav_img" src="../../../public/img/process/node2.png"> <img class="nav_img" src="../../../public/img/process/yes.png" />
<div class="node-text">电子围栏服务</div> </div>
</div> <div class="node-img">
<div class="yes-no"> <img
<div class="yes"></div> class="nav_img"
<img class="nav_img" src="../../../public/img/process/yes.png"> src="../../../public/img/process/node2.png"
</div> />
<div class="node-img"> <div class="node-text">电子围栏服务</div>
<img class="nav_img" src="../../../public/img/process/node3.png"> </div>
<div class="node-text">网关</div> <div class="yes-no">
</div> <div class="yes"></div>
<div class="yes-no"> <img class="nav_img" src="../../../public/img/process/yes.png" />
<div class="yes"></div> </div>
<img class="nav_img" src="../../../public/img/process/yes.png"> <div class="node-img">
</div> <img
<div class="node-img"> class="nav_img"
<div class="baojing">dtu断联报警</div> src="../../../public/img/process/node3.png"
<img class="nav_img" src="../../../public/img/process/node4.png"> />
<div class="node-text">dtu</div> <div class="node-text">网关</div>
</div> </div>
<div class="yes-no"> <div class="yes-no">
<div class="no"></div> <div class="yes"></div>
<img class="nav_img" src="../../../public/img/process/no.png"> <img class="nav_img" src="../../../public/img/process/yes.png" />
</div> </div>
<div class="node-img"> <div class="node-img">
<img class="nav_img" src="../../../public/img/process/node5.png"> <div class="baojing">dtu断联报警</div>
<div class="node-text">电子围栏</div> <img
</div> class="nav_img"
</div> src="../../../public/img/process/node4.png"
<div class="process-more"> />
<div class="button">查看更多报警信息</div> <div class="node-text">dtu</div>
</div> </div>
</div> <div class="yes-no">
<div class="process-bottom"> <div class="no"></div>
<div class="line"> <img class="nav_img" src="../../../public/img/process/no.png" />
<div class="item"> </div>
<div class="item-box"> <div class="node-img">
<div class="time">2024-5-17 08:51:12</div> <img
<div class="point red"></div> class="nav_img"
<div class="name">dtu断联报警</div> src="../../../public/img/process/node5.png"
<div class="code">dtu编号SJK001</div> />
<div class="btn red-btn"> <div class="node-text">电子围栏</div>
<img class="img" src="../../../public/img/process/serch.png" alt=""> </div>
<div class="text">请检查dtu设备</div> </div>
</div> <div class="process-more">
</div> <div class="button">查看更多报警信息</div>
<div class="item-box"> </div>
<div class="time">2024-5-17 08:51:13</div> </div>
<div class="point grey"></div> <div class="process-bottom">
<div class="name">静默</div> <div class="line">
<div class="code">设备编号SHUIBIAO1</div> <div class="item">
<div class="btn grey-btn"> <div class="item-box">
<img class="img" src="../../../public/img/process/loading.png" alt=""> <div class="time">2024-5-17 08:51:12</div>
<div class="text">等待重新链接</div> <div class="point red"></div>
</div> <div class="name">dtu断联报警</div>
</div> <div class="code">dtu编号SJK001</div>
</div> <div class="btn red-btn">
<div class="restart"> <img
<div class="restart-title">操作</div> class="img"
<div class="restart-btn">一键重启</div> src="../../../public/img/process/serch.png"
</div> alt=""
</div> />
</div> <div class="text">请检查dtu设备</div>
</div> </div>
</div> </div>
<div class="method"> <div class="item-box">
<div class="title">报警解决方法</div> <div class="time">2024-5-17 08:51:13</div>
<div class="main"> <div class="point grey"></div>
<div class="text-box"> <div class="name">静默</div>
<div class="label">设备位置</div> <div class="code">设备编号SHUIBIAO1</div>
<div class="value"> <div class="btn grey-btn">
<div class="item">园区2号围栏</div> <img
</div> class="img"
</div> src="../../../public/img/process/loading.png"
<div class="text-box"> alt=""
<div class="label">排查方法</div> />
<div class="value"> <div class="text">等待重新链接</div>
<div class="item">1.检查电源是否正常重新接入或更换电源</div> </div>
<div class="item">2.检查是否过载重新调整系统负载或更换更高性能的设备</div> </div>
<div class="item">3.检查温度是否过高采取措施降低温度如改变工作环境或更换散热设备</div> </div>
<div class="item">4.检查是否受到电磁干扰采取措施降低干扰如改变工作环境或更换屏蔽设备</div> <div class="restart">
</div> <div class="restart-title">操作</div>
</div> <div class="restart-btn">一键重启</div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<div class="method">
<div class="title">报警解决方法</div>
<div class="main" v-for="item in data">
<div class="text-box">
<div class="label">设备类型编码</div>
<div class="value">
<div class="item">{{ item.classCode }}</div>
</div>
</div>
<div class="text-box">
<div class="label">排查方法</div>
<div class="value">
<div class="item">1.检查电源是否正常重新接入或更换电源</div>
<div class="item">
2.检查是否过载重新调整系统负载或更换更高性能的设备
</div>
<div class="item">
3.检查温度是否过高采取措施降低温度如改变工作环境或更换散热设备
</div>
<div class="item">
4.检查是否受到电磁干扰采取措施降低干扰如改变工作环境或更换屏蔽设备
</div>
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
import {
getWarnPoint,
getResolveTips,
} from "@/api/opsVisualization/serviceDataOAM";
export default { export default {
data() { data() {
return { return {
data: [
} {
}, classCode: "设备类型编码,0100",
created() { pointCode: "报警节点code,1",
tips: "排查方案说明,简单进线电流",
}, shortNum: 1, //
mounted() { },
}, ],
methods: { };
} },
} created() {},
mounted() {
// [
// {
// nodeid: 1,
// list: [
// {
// name: "",
// state: "",
// },
// {
// name: "",
// state: "",
// },
// {
// name: "",
// state: "",
// },
// {
// name: "dtu",
// state: "dtu",
// },
// {
// name: "",
// state: "",
// },
// ],
// },
// ];
getResolveTips();
},
methods: {},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.content{ .content {
padding: 20px !important; padding: 20px !important;
.process{ .process {
width: calc(100% - 218px); width: calc(100% - 218px);
margin-left: 218px; margin-left: 218px;
height: 584px; height: 584px;
background: #FFFFFF; background: #ffffff;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #D1D1D1; border: 1px solid #d1d1d1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.title{ .title {
width: 100%; width: 100%;
height: 40px; height: 40px;
background: #E5E5E5; background: #e5e5e5;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #D1D1D1; border: 1px solid #d1d1d1;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 18px; font-size: 18px;
color: #333333; color: #333333;
} }
.main{ .main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 30px; padding: 30px;
height: 50%; height: 50%;
.process-example{ .process-example {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
.example-title{ .example-title {
color: #999999; color: #999999;
margin-right: 6px; margin-right: 6px;
font-size: 14px; font-size: 14px;
} }
.example-box{ .example-box {
display: flex; display: flex;
align-items: center; align-items: center;
.point{ .point {
width: 11px; width: 11px;
height: 11px; height: 11px;
border-radius: 10px; border-radius: 10px;
margin-right: 11px; margin-right: 11px;
} }
.value{ .value {
color: #999999; color: #999999;
font-size: 14px; font-size: 14px;
} }
} }
.margin-right-left-20{ .margin-right-left-20 {
margin: 0 20px; margin: 0 20px;
} }
} }
.process-center{ .process-center {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-around;
margin-top: 75px; margin-top: 75px;
.process-node-box{ .process-node-box {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
.node-img{ .node-img {
width: 69px; width: 69px;
height: 69px; height: 69px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative; position: relative;
.baojing{ .baojing {
width: 133px; width: 133px;
height: 31px; height: 31px;
background: #FFF3F3; background: #fff3f3;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #EE6464; border: 1px solid #ee6464;
font-size: 16px; font-size: 16px;
color: #E14B33; color: #e14b33;
position: absolute; position: absolute;
top: -55px; top: -55px;
transform: translateY(-50%); transform: translateY(-50%);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.nav_img{ .nav_img {
width: 100%; width: 100%;
height: 100%; height: 100%;
// margin-bottom: 20px; // margin-bottom: 20px;
} }
.node-text{ .node-text {
position: absolute; position: absolute;
transform: translateY(-50%); transform: translateY(-50%);
width: 100px; width: 100px;
text-align: center; text-align: center;
top: 100px; top: 100px;
} }
} }
.yes-no{ .yes-no {
width: 163px; width: 163px;
height: 17px; height: 17px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative; position: relative;
.yes{ .yes {
width: 167px; width: 167px;
height: 17px; height: 17px;
background: #21A2E5; background: #21a2e5;
opacity: 0.18; opacity: 0.18;
position: absolute; position: absolute;
} }
.no{ .no {
width: 167px; width: 167px;
height: 17px; height: 17px;
background: #A5A5A5; background: #a5a5a5;
opacity: 0.18; opacity: 0.18;
position: absolute; position: absolute;
} }
.nav_img{ .nav_img {
width: 24px; width: 24px;
height: 24px; height: 24px;
opacity: 1; opacity: 1;
z-index: 10; z-index: 10;
} }
} }
} }
.process-more{ .process-more {
.button{ .button {
width: 190px; width: 190px;
height: 40px; height: 40px;
background: #FFFFFF; background: #ffffff;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #2B8EE5; border: 1px solid #2b8ee5;
color: #2B8EE5; color: #2b8ee5;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
} }
} }
} }
.process-bottom{ .process-bottom {
border-top: 1px solid #D1D1D1; border-top: 1px solid #d1d1d1;
margin-top: 200px; margin-top: 200px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.line{ .line {
margin-top: 20px; margin-top: 20px;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
} }
.item{ .item {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.item-box{ .item-box {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 20px;
.point{ .point {
width: 10px; width: 10px;
height: 10px; height: 10px;
margin: 0 20px; margin: 0 20px;
border-radius: 10px; border-radius: 10px;
} }
.name{ .name {
width: 200px; width: 200px;
} }
.code{ .code {
width: 250px; width: 250px;
margin-left: 40px; margin-left: 40px;
} }
.btn{ .btn {
margin-left: 20px; margin-left: 20px;
width: 185px; width: 185px;
height: 31px; height: 31px;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
font-size: 16px; font-size: 16px;
.img{ .img {
width: 15px; width: 15px;
height: 15px; height: 15px;
} }
} }
.red-btn{ .red-btn {
background: #FFF3F3; background: #fff3f3;
border: 1px solid #EE6464; border: 1px solid #ee6464;
.text{ .text {
color: #E14B33; color: #e14b33;
} }
} }
.grey-btn{ .grey-btn {
background: #F5F5F5; background: #f5f5f5;
border: 1px solid #999999; border: 1px solid #999999;
.text{ .text {
color: #999999; color: #999999;
} }
} }
} }
} }
.restart{ .restart {
margin-left: 72px; margin-left: 72px;
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
.restart-text{ .restart-text {
font-size: 16px; font-size: 16px;
color: #333333; color: #333333;
} }
.restart-btn{ .restart-btn {
width: 93px; width: 93px;
height: 31px; height: 31px;
background: #2B8EE5; background: #2b8ee5;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
font-size: 16px; font-size: 16px;
color: #FFFFFF; color: #ffffff;
margin-left: 7px; margin-left: 7px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
} }
} }
} }
} }
.method{ .method {
flex: 1; flex: 1;
margin-top: 30px; margin-top: 30px;
width: calc(100% - 218px); width: calc(100% - 218px);
// height: 326px; // height: 326px;
margin-left: 218px; margin-left: 218px;
background: #FFFFFF; background: #ffffff;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #D1D1D1; border: 1px solid #d1d1d1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.title{ .title {
width: 100%; width: 100%;
height: 40px; height: 40px;
background: #E5E5E5; background: #e5e5e5;
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
border: 1px solid #D1D1D1; border: 1px solid #d1d1d1;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 18px; font-size: 18px;
color: #333333; color: #333333;
} }
.main{ .main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 22px; padding: 22px;
// height: 50%; // height: 50%;
overflow: auto; overflow: auto;
.text-box{ .text-box {
margin-bottom: 22px; margin-bottom: 22px;
display: flex; display: flex;
.label{ .label {
} }
.value{ .value {
.item{ .item {
margin-bottom: 12px; margin-bottom: 12px;
} }
} }
} }
} }
} }
.blue{ .blue {
background: #21A2E5; background: #21a2e5;
} }
.red{ .red {
background: #E96955; background: #e96955;
} }
.grey{ .grey {
background: #E1E1E1; background: #e1e1e1;
} }
} }
</style> </style>

@ -3,75 +3,136 @@
<el-col :span="3"> </el-col> <el-col :span="3"> </el-col>
<el-col :span="21" style="height: 100%"> <el-col :span="21" style="height: 100%">
<basic-container style="height: 100%"> <basic-container style="height: 100%">
<avue-crud <div class="search_box">
:option="option" <el-input
:table-loading="loading" class="search_input"
:data="data" v-model="classCode"
ref="crud" placeholder="请输入设备类型编码"
v-model="form" clearable
:permission="permissionList" />
:before-open="beforeOpen" <el-select
:before-close="beforeClose" class="search_select"
@row-del="rowDel" placeholder="请选择报警状态"
@row-update="rowUpdate" style="margin: 0 20px 0 10px"
@row-save="rowSave" v-model="warnStatus"
@search-change="searchChange" >
@search-reset="searchReset" <el-option label="全部" value=""></el-option>
@selection-change="selectionChange" <el-option label="正常" value="0"></el-option>
@current-change="currentChange" <el-option label="报警" value="1"></el-option>
@size-change="sizeChange" </el-select>
@refresh-change="refreshChange" <el-input
@on-load="onLoad" class="search_input"
@tree-load="treeLoad" v-model="equipCode"
:page.sync="page" placeholder="请输入设备编码"
> clearable
<template slot-scope="scope" slot="areaSearch"> />
<el-select v-model="area"> <el-button class="search_button" @click="handleSearch">
<el-option label="业务区" value="1"></el-option> <i class="el-icon-search"></i>
<el-option label="塔台" value="2"></el-option> </el-button>
</el-select> </div>
</template> <div style="position: relative">
<!-- <template slot-scope="scope" slot="startDateSearch"> <el-table
<el-date-picker class="el_table"
v-model="startDate" :data="tableData"
type="date" border
placeholder="选择日期" stripe
value-format = 'yyyy-MM-dd' lo
format="yyyy-MM-dd" height="340"
> v-loading="loading"
</el-date-picker> >
</template> <el-table-column
<template slot-scope="scope" slot="endDateSearch"> type="index"
<el-date-picker :index="indexMethod"
v-model="endDate" label="序号"
type="date" width="80"
placeholder="选择日期" align="center"
value-format = 'yyyy-MM-dd' >
format="yyyy-MM-dd" </el-table-column>
> <el-table-column prop="classCode" label="设备编码" width="180">
</el-date-picker> </el-table-column>
</template> --> <el-table-column prop="equipName" label="设备名称">
</avue-crud> </el-table-column>
<el-table-column
prop="equipStatus"
label="设备状态"
width="100"
align="center"
>
</el-table-column>
<el-table-column prop="equipContent" label="报警信息">
</el-table-column>
<el-table-column prop="warnDate" label="报警时间">
</el-table-column>
<el-table-column prop="equipLocation" label="设备位置">
</el-table-column>
<el-table-column
prop="address"
label="操作"
width="100"
align="center"
>
<el-button type="text" size="small">查看</el-button>
</el-table-column>
</el-table>
<div class="el_pagination">
<div
style="
width: 100%;
height: 100%;
position: absolute;
background: rgba(255,255,255,.9);
z-index: 9;
position: absolute;
top: 0;
left: 0;
"
v-show="loading"
></div>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[6, 10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</div>
<div class="box"> <div class="box">
<div class="box_nav"> <div class="box_nav">
<span class="box_tab" style="margin-right: 50px">报警详情信息</span> <span
<span class="box_tab" style="color: #2b8ee5">报警信息记录</span> class="box_tab"
:style="{
marginRight: '50px',
color: tabKey == 1 ? '#2b8ee5' : '',
}"
@click="() => tabChange(1)"
>报警详情信息</span
>
<span
class="box_tab"
:style="{ color: tabKey == 2 ? '#2b8ee5' : '' }"
@click="() => tabChange(2)"
>报警信息记录</span
>
</div> </div>
<el-select placeholder="按报警时间查询" class="box_select"> <el-select placeholder="按报警时间查询" class="box_select">
</el-select> </el-select>
<div class="timelineBox"> <div class="timelineBox">
<div style="width: 100%"> <div style="width: 100%">
<div class="timelineBoxTitle"> <div class="timelineBoxTitle">
<span>设备报警信息详情</span> <span>{{ tabKey == 1 ? "报警详情信息" : "报警信息记录" }}</span>
<span>更多</span> <span>更多</span>
</div> </div>
<div class="timelineBoxContent"> <div class="timelineBoxContent" v-if="warnMsgList.length">
<div <div
v-for="(item, index) in myList" v-for="(item, index) in warnMsgList"
:key="item.time" :key="item.warnDate"
style="display: flex; align-items: center; line-height: 50px" style="display: flex; align-items: center; line-height: 50px"
> >
{{ item.time }} {{ item.warnDate }}
<div <div
style=" style="
width: 40px; width: 40px;
@ -90,7 +151,7 @@
" "
></div> ></div>
<div <div
v-if="index < myList.length - 1" v-if="index < warnMsgList.length - 1"
style=" style="
border-right: 1px dashed #d1d1d1; border-right: 1px dashed #d1d1d1;
height: 45px; height: 45px;
@ -100,9 +161,16 @@
" "
></div> ></div>
</div> </div>
{{ item.content }}dtu编号:{{ item.id }} {{ item.warnContent }}设备编号:{{ item.equipCode }}
</div> </div>
</div> </div>
<div
v-else
class="timelineBoxContent"
style="text-align: center; line-height: 100px"
>
暂无数据
</div>
</div> </div>
</div> </div>
</div> </div>
@ -114,6 +182,7 @@
.box { .box {
width: 100%; width: 100%;
height: 26vh; height: 26vh;
margin-top: 30px;
} }
.tab_btn { .tab_btn {
cursor: pointer; cursor: pointer;
@ -123,8 +192,8 @@
height: 30px; height: 30px;
margin-top: 20px; margin-top: 20px;
} }
.box_nav{ .box_nav {
>span{ > span {
cursor: pointer; cursor: pointer;
} }
} }
@ -155,464 +224,161 @@
/deep/ .basic-container__card { /deep/ .basic-container__card {
height: 100%; height: 100%;
} }
.search_box {
display: flex;
margin-bottom: 30px;
.search_select {
// width: 138px;
height: 40px;
}
.search_input {
width: 238px;
height: 40px;
}
/deep/.el-input__inner {
border-radius: 0;
}
.search_button {
width: 50px;
height: 40px;
border-radius: 0;
display: flex;
justify-content: center;
align-items: center;
margin-left: 6px;
.el-icon-search {
font-size: 19px;
color: #c9c9c9;
}
}
}
.el-table {
::v-deep td {
padding: 0 !important;
}
}
/deep/.el-table__row {
height: 40px;
}
.el_pagination {
display: flex;
justify-content: end;
border: 1px solid #d1d1d1;
border-top: none;
padding: 10px 7px 7px 7px;
position: absolute;
bottom: 0;
width: 99%;
}
.el_table {
width: 100%;
overflow: auto;
border: 1px solid #d1d1d1;
border-bottom: 50px solid #fff;
}
</style> </style>
<script> <script>
import { import {
getLazyList, getEquipList,
remove, getWarnMsg,
update, getWarnHisList,
add, } from "@/api/opsVisualization/serviceDataOAM";
getDept,
getDeptTree,
} from "@/api/system/dept";
import { mapGetters } from "vuex";
import website from "@/config/website";
import { getAlarmList, getDeptLazyTree } from "@/api/equipment";
var DIC = {
alarmType: [
{
label: "未知",
value: -1,
},
{
label: "事件报警",
value: 1,
},
{
label: "设备报警",
value: 2,
},
],
statusType: [
{
label: "报警中",
value: 1,
},
{
label: "已恢复",
value: 2,
},
],
aereaType: [
{
label: "业务区",
value: "1",
},
{
label: "塔台",
value: "2",
},
],
recoveryType: [
{
label: " ",
value: -1,
},
{
label: "手动",
value: 1,
},
{
label: "自动",
value: 0,
},
],
};
export default { export default {
data() { data() {
return { return {
myList: [ tabKey: 1,
{
time: "2019-08-07 15:36:48", classCode: "",
content: "dtu1002报警", warnStatus: "",
id: 1, equipCode: "",
}, currentPage: 1,
{ pageSize: 6,
time: "2019-08-07 15:36:48", total: 0,
content: "dtu1002报警",
id: 2,
},
{
time: "2019-08-07 15:36:48",
content: "dtu1002报警",
id: 2,
},
{
time: "2019-08-07 15:36:48",
content: "dtu1002报警",
id: 2,
},
{
time: "2019-08-07 15:36:48",
content: "dtu1002报警",
id: 2,
},
{
time: "2019-08-07 15:36:48",
content: "dtu1002报警",
id: 2,
},
],
area: this.$route.query.area ? this.$route.query.area : "1",
classCode: this.$route.query.classCode ? this.$route.query.classCode : "",
startDate: "",
endDate: "",
form: {},
selectionList: [],
query: {},
loading: false, loading: false,
parentId: 0,
page: { tableData: [],
pageSize: 5, warnMsgList: [],
currentPage: 1,
total: 0,
},
option: {
lazy: true,
tip: false,
// simplePage: true,
searchShow: true,
searchMenuSpan: 6,
tree: true,
border: true,
index: true,
selection: true,
viewBtn: true,
menuWidth: 80,
dialogClickModal: false,
addBtn: false,
delBtn: false,
editBtn: false,
emptyBtn: false,
column: [
{
label: "通讯状态",
prop: "equipName",
align: "center",
search: true,
type: "select",
dicData: DIC.alarmType,
},
{
label: "业务类别",
prop: "location",
search: true,
type: "select",
dicData: DIC.alarmType,
align: "center",
},
{
label: "报警信息",
prop: "warnContent",
align: "center",
},
{
label: "dtu编号",
prop: "warnContent",
align: "center",
},
{
label: "设备编号",
prop: "warnContent",
align: "center",
search: true,
type: "input",
dicData: DIC.alarmType,
},
// {
// label: "",
// prop: "warnType",
// search: true,
// type: "select",
// dicData: DIC.alarmType,
// align: "center",
// },
// {
// label: "",
// prop: "warnType",
// search: true,
// type: "select",
// dicData: DIC.alarmType,
// align: "center",
// },
// {
// label: "",
// prop: "status",
// type: "select",
// dicData: DIC.statusType,
// align: "center",
// },
{
label: "设备位置",
prop: "warnDate",
type: "datetime",
width: "140",
// format:'yyyy-MM-dd',
// valueFormat:'yyyy-MM-dd',
align: "center",
},
// {
// label: "",
// prop: "endDate",
// align:'center',
// searchslot:true,
// hide:true,
// search:true,
// row: false,
// display: false,
// viewDisplay:false
// },
{
label: "dtu报警信息",
prop: "recoveryType",
dicData: DIC.recoveryType,
type: "select",
align: "center",
},
{
label: "报警时间",
prop: "recoveryPerson",
align: "center",
},
{
label: "设备报警信息",
prop: "recoveryDate",
type: "datetime",
align: "center",
},
{
label: "报警时间",
prop: "recoveryDate",
type: "datetime",
align: "center",
},
],
},
data: [],
treeData: [],
treeOption: {
nodeKey: "id",
lazy: true,
treeLoad: function (node, resolve) {
const parentId = node.level === 0 ? 0 : node.data.id;
getDeptLazyTree(parentId).then((res) => {
resolve(
res.data.data.map((item) => {
return {
...item,
leaf: !item.hasChildren,
};
})
);
});
},
addBtn: false,
menu: false,
size: "small",
props: {
labelText: "标题",
label: "title",
value: "value",
children: "children",
},
},
}; };
}, },
computed: { computed: {},
...mapGetters(["userInfo", "permission"]), mounted() {
permissionList() { this.handleSearch();
return {
addBtn: this.vaildData(this.permission.dept_add, false),
viewBtn: this.vaildData(this.permission.dept_view, false),
delBtn: this.vaildData(this.permission.dept_delete, false),
editBtn: this.vaildData(this.permission.dept_edit, false),
};
},
ids() {
let ids = [];
this.selectionList.forEach((ele) => {
ids.push(ele.id);
});
return ids.join(",");
},
}, },
methods: { methods: {
nodeClick(data) { indexMethod(index) {
this.classCode = data.key; const { currentPage, pageSize } = this;
this.page.currentPage = 1; return (currentPage - 1) * pageSize + index + 1;
this.onLoad(this.page);
}, },
handleSearch() {
initData() { const { classCode, warnStatus, equipCode, currentPage, pageSize } = this;
getDeptTree().then((res) => { this.loading = true;
const column = this.findObject(this.option.column, "parentId"); getEquipList({
column.dicData = res.data.data; classCode,
warnStatus,
equipCode,
currentPage,
pageSize,
}).then((res) => {
this.tableData = res.data.data.records;
this.currentPage = res.data.data.current;
this.total = res.data.data.total;
this.loading = false;
});
getWarnMsg({ equipCode }).then((res) => {
this.warnMsgList = res.data.data;
}); });
}, },
handleAdd(row) { tabChange(tabKey) {
this.parentId = row.id; this.tabKey = tabKey;
const column = this.findObject(this.option.column, "parentId"); const { equipCode } = this;
column.value = row.id; if (tabKey == 1) {
column.addDisabled = true; getWarnMsg({ equipCode }).then((res) => {
this.$refs.crud.rowAdd(); this.warnMsgList = res.data.data;
},
rowSave(row, done, loading) {
add(row).then(
(res) => {
//
const data = res.data.data;
row.id = data.id;
row.deptCategoryName = data.deptCategoryName;
row.tenantId = data.tenantId;
this.$message({
type: "success",
message: "操作成功!",
});
//
done(row);
},
(error) => {
window.console.log(error);
loading();
}
);
},
rowUpdate(row, index, done, loading) {
update(row).then(
() => {
this.$message({
type: "success",
message: "操作成功!",
});
//
done(row);
},
(error) => {
window.console.log(error);
loading();
}
);
},
rowDel(row, index, done) {
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
return remove(row.id);
})
.then(() => {
this.$message({
type: "success",
message: "操作成功!",
});
//
done(row);
});
},
handleDelete() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据");
return;
}
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
return remove(this.ids);
})
.then(() => {
//
this.data = [];
this.parentId = 0;
this.$refs.crud.refreshTable();
this.$refs.crud.toggleSelection();
//
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!",
});
}); });
}, } else if (tabKey == 2) {
searchReset() { getWarnHisList({ equipCode, currentPage: 1, pageSize: 10 }).then(
this.query.warnType = ""; (res) => {
this.query.area = "1"; this.warnMsgList = res.data.data.records;
this.startDate = ""; }
this.page.currentPage = 1; );
this.onLoad(this.page);
},
searchChange(params, done) {
this.query.warnType = params.warnType;
this.query.startDate = params.startDate;
this.page.currentPage = 1;
this.onLoad();
done();
},
selectionChange(list) {
this.selectionList = list;
},
selectionClear() {
this.selectionList = [];
this.$refs.crud.toggleSelection();
},
beforeOpen(done, type) {
if (["add", "edit"].includes(type)) {
this.initData();
}
if (["edit", "view"].includes(type)) {
// getDept(this.form.id).then(res => {
// this.form = res.data.data;
// });
} }
done();
}, },
beforeClose(done) { //
// this.parentId = ""; handleSizeChange(pageSize) {
// const column = this.findObject(this.option.column, "parentId"); this.pageSize = pageSize;
// column.value = ""; this.loading = true;
// column.addDisabled = false; const { classCode, warnStatus, equipCode, currentPage } = this;
done(); getEquipList({
}, classCode,
currentChange(currentPage) { warnStatus,
this.page.currentPage = currentPage; equipCode,
}, currentPage,
sizeChange(pageSize) { pageSize,
this.page.pageSize = pageSize; }).then((res) => {
}, this.tableData = res.data.data.records;
refreshChange() { this.currentPage = res.data.data.current;
this.onLoad(this.page, this.query); this.total = res.data.data.total;
this.loading = false;
});
}, },
onLoad() { //
handleCurrentChange(currentPage) {
this.currentPage = currentPage;
this.loading = true; this.loading = true;
getAlarmList( const { classCode, warnStatus, equipCode, pageSize } = this;
this.query.warnType, getEquipList({
this.startDate, classCode,
this.endDate, warnStatus,
this.page.currentPage, equipCode,
this.page.pageSize, currentPage,
this.area, pageSize,
this.classCode }).then((res) => {
).then((res) => { this.tableData = res.data.data.records;
this.data = res.data.data.records; this.total = res.data.data.total;
// this.page.total = res.data.data.total
this.page.total = res.data.data.total;
console.log(this.page);
this.loading = false; this.loading = false;
}); });
// this.selectionClear();
}, },
// treeLoad(tree, treeNode, resolve) {
// const parentId = tree.id;
// getLazyList(parentId).then(res => {
// resolve(res.data.data);
// });
// }
}, },
}; };
</script> </script>

@ -70,9 +70,11 @@ router.beforeEach((to, from, next) => {
if (meta.isAuth === false) { if (meta.isAuth === false) {
next() next()
} else { } else {
if (to.path.indexOf('/opsVisualization/alarmProcess') == '-1') { if (to.path.indexOf('/opsVisualization') == '-1') {
next('/login') next('/login')
} else { }
//运维可视化免登录
else {
next() next()
} }
} }

@ -87,6 +87,7 @@ export default [{
path: '/opsVisualization', path: '/opsVisualization',
name: '系统监控', name: '系统监控',
component: Layout, component: Layout,
redirect: '/opsVisualization/tuobu',
meta: { meta: {
keepAlive: true, keepAlive: true,
isTab: false, isTab: false,
@ -94,10 +95,13 @@ export default [{
}, },
children: [ children: [
{ {
path: "alarmProcess", path: 'tuobu',
name: '系统监控1', name: '系统监控',
meta: {
i18n: 'dashboard'
},
component: () => component: () =>
import( /* webpackChunkName: "page" */ '@/page/opsVisualization/alarmProcess'), import( /* webpackChunkName: "views" */ '@/page/opsVisualization/tuobu')
}, },
{ {
path: "systemMonitoring", path: "systemMonitoring",
@ -106,20 +110,17 @@ export default [{
import( /* webpackChunkName: "page" */ '@/page/opsVisualization/systemMonitoring'), import( /* webpackChunkName: "page" */ '@/page/opsVisualization/systemMonitoring'),
}, },
{ {
path: "serviceDataOAM", path: "alarmProcess",
name: '业务数据监控', name: '业务数据监控',
component: () => component: () =>
import( /* webpackChunkName: "page" */ '@/page/opsVisualization/serviceDataOAM'), import( /* webpackChunkName: "page" */ '@/page/opsVisualization/alarmProcess'),
}, },
{ {
path: 'tuobu', path: "serviceDataOAM",
name: 'tuobu', name: '报警信息记录',
meta: {
i18n: 'dashboard'
},
component: () => component: () =>
import( /* webpackChunkName: "views" */ '@/page/opsVisualization/tuobu') import( /* webpackChunkName: "page" */ '@/page/opsVisualization/serviceDataOAM'),
} },
] ]
}, },
] ]

@ -243,35 +243,5 @@ export default [{
component: () => component: () =>
import( /* webpackChunkName: "views" */ '@/views/system/systemSetting') import( /* webpackChunkName: "views" */ '@/views/system/systemSetting')
}] }]
}, }
{
path: '/opsVisualization',
component: Layout,
redirect: '/opsVisualization/index',
children: [{
path: 'index',
name: 'index',
meta: {
i18n: 'dashboard'
},
component: () =>
import( /* webpackChunkName: "views" */ '@/views/opsVisualization/index')
}, {
path: 'alarmProcess',
name: 'alarmProcess',
meta: {
i18n: 'dashboard'
},
component: () =>
import( /* webpackChunkName: "views" */ '@/views/opsVisualization/alarmProcess')
}, {
path: 'tuobu',
name: 'tuobu',
meta: {
i18n: 'dashboard'
},
component: () =>
import( /* webpackChunkName: "views" */ '@/views/opsVisualization/tuobu')
}]
},
] ]

Loading…
Cancel
Save