This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nezha-nezha-fronted/nezha-fronted/src/components/common/leftMenu.vue

804 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="content">
<div class="content-left left-slot" :class="{'left-slot-shrink': isShrink}">
<div class="sidebar-title too-long-split">{{$t(parentMenu.i18n)}}</div>
<div class="sidebar-info" style="height: 90%; overflow: auto;">
<template v-if="parentMenu == '/project'">
<el-collapse v-model="projectChoose" accordion class="left-menu-bg" ref="projectLeft" style="padding-top: 0;">
<el-collapse-item :key="item.id" :name="item.id + ''" v-for="(item, index) in projectList">
<template slot="title">
<div :class="{'sidebar-info-item-active': item.id == currentProject.id}" :id="'project-module-'+item.id" @click="detailProject(item)" class="sidebar-info-item-project sidebar-info-item">
<div class="sidebar-info-item-txt">
<el-popover :content="item.name" placement="top-start" popper-class="transparent-pop" trigger="hover" v-if="item.name.length > 14">
<span class="" slot="reference">
{{item.name}}
</span>
</el-popover>
<span v-else>{{item.name}}</span>
</div>
</div>
</template>
<div class="sidebar-info sub-sidebar-info" >
<div :title="$t('overall.createModule')" @click="addModule(item)" class="sidebar-info-item sidebar-info-item-project-add" v-if="getProjectModule(item.id).length == 0">
<span><i class="nz-icon nz-icon-create-square"></i>&nbsp;{{$t("overall.addProject")}}</span>
</div>
<template v-else>
<div :class="{'sidebar-info-item-active': module.id == currentModule.id}" :id="'project-module-'+module.id" @click="changeModule(item, module)" class="sidebar-info-sub-item" v-for="module in getProjectModule(item.id)">
<div :id="`module-${module.id}`" class="item-tip">
<div :class="itemTip(module.id, module.name, ready)" class="item-tip-hide item-tip-key el-popover">{{module.name}}</div>
<span class="too-long-split" style="width: 120px;">{{module.name}}</span>
<div :id="'project-module-edit-'+module.id" @click.stop="editModule(module)" class="hid-div side-bar-menu-edit sub-side-bar-menu-edit" v-has="'project_module_toEdit'" v-show="module.buildIn != 1" ><i class="nz-icon nz-icon-edit"></i></div>
</div>
</div>
</template>
</div>
</el-collapse-item>
</el-collapse>
</template>
<template v-else-if="parentMenu == '/asset'">
<el-collapse class="left-menu-bg" v-model="activeType">
<el-collapse-item :title="$t('asset.left.dataCenter')" name="dataCenter">
<el-checkbox-group size="small" v-model="dcCheckList">
<el-checkbox :class="{'sidebar-info-item-active': indOf(dcCheckList, item.id)}" :key="key"
:label=item.id class="sidebar-info-item sidebar-info-item-asset" v-for="(item,key) in dcData">
<div class="sidebar-info-item-txt">
<el-popover :content="item.name" placement="top-start" trigger="hover" v-if="item.name.length > 14" >
<span slot="reference">{{item.name}}</span>
</el-popover>
<span v-else>{{item.name}}</span>
</div>
<el-badge :value="item.total" class="mark" type="primary"/>
</el-checkbox>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('asset.assetType')" name="assetType">
<el-checkbox-group @change="changeAssetTypeCheckBox" size="small" v-model="assetTypeCheckList">
<el-checkbox :class="{'sidebar-info-item-active': indOf(assetTypeCheckList, item.id)}" :key="key" :label=item.id class="sidebar-info-item" v-for="(item, key) in assetTypeData">
<div class="sidebar-info-item-txt">
<el-popover :content="item.name" placement="top-start" trigger="hover" v-if="item.name.length > 14" >
<span slot="reference">{{item.name}}</span>
</el-popover>
<span v-else>{{item.name}}</span>
</div>
<el-badge :value="item.total" class="mark" type="primary"/>
</el-checkbox>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('asset.left.vendor')" name="vendor">
<el-checkbox-group @change="changeVendorCheckBox" size="small" v-model="vendorCheckList">
<el-checkbox :class="{'sidebar-info-item-active': indOf(vendorCheckList, item.id)}" :key="key" :label=item.id class="sidebar-info-item" v-for="(item, key) in vendorData">
<div class="sidebar-info-item-txt">
<el-popover :content="item.name" placement="top-start" trigger="hover" v-if="item.name.length > 14" >
<span slot="reference">{{item.name}}</span>
</el-popover>
<span v-else>{{item.name}}</span>
</div>
<el-badge :value="item.total" class="mark" type="primary"/>
</el-checkbox>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('asset.left.ping')" name="ping" v-if="assetPingSwitch">
<el-checkbox-group @change="changePingCheckBox" size="small" v-model="pingCheckList">
<el-checkbox :class="{'sidebar-info-item-active': indOf(pingCheckList, item.key)}" :key="index" :label="item.value" class="sidebar-info-item" v-for="(item, index) in pingData">
<div class="sidebar-info-item-txt">
<span>{{item.label}}</span>
</div>
<el-badge :value="item.total" class="mark" type="primary"/>
</el-checkbox>
</el-checkbox-group>
</el-collapse-item>
</el-collapse>
<!--tag 过滤-->
<div class="sidebar-title too-long-split orange-font">
Tag
</div>
<el-collapse class="left-menu-bg" v-model="activeTag">
<el-collapse-item :key="item.key" :name="item.key" :title="item.key" v-for="item in tagData">
<el-checkbox-group size="small" v-model="tagCheckList" >
<el-checkbox :key="item.key+'-'+tag.value" :label="item.key+'-'+tag.value" @change="changeTagCheckBox(item,tag.value)" class="sidebar-info-item" v-for="tag in item.values">
<div class="sidebar-info-item-txt">
<el-popover :content="tag.value" placement="top-start" trigger="hover" v-if="tag.value.length > 14" >
<span slot="reference">{{tag.value}}</span>
</el-popover>
<span v-else>{{tag.value}}</span>
</div>
<el-badge :max="99" :value="tag.total" class="mark" type="primary"/>
</el-checkbox>
</el-checkbox-group>
</el-collapse-item>
</el-collapse>
</template>
<template v-else>
<div :class="{'sidebar-info-item-active': menu.route == route}" @click="jumpTo(menu.route)" class="sidebar-info-item" v-for="menu in parentMenu.children">
{{$t(menu.i18n)}}
</div>
</template>
</div>
<div @click="toggleStat" class="bottom-icon">
<div class="bottom-divider"></div>
<div style="display: inline-block;float: right;margin-right:15px;"><i style="font-size: 24px;" :class="{'nz-icon nz-icon-push-pin-line': isShrink, 'nz-icon nz-icon-push-pin-fill': !isShrink}" :style="{color : !isShrink ? '#EE9D3F' : ''}"></i></div>
</div>
</div><div class="content-right right-slot" :class="{'right-slot-open': isShrink}">
<router-view v-if="isRouterAlive"/>
</div>
<transition name="right-box">
<module-box v-if="rightBox.module.show" :current-project="currentProject" :module="module" @close="closeModuleRightBox" ref="moduleBox"></module-box>
</transition>
</div>
</template>
<script>
import bus from "../../libs/bus";
export default {
name: "leftMenu",
props: {
resizeFunc: Function,
},
data() {
return{
isShrink: localStorage.getItem('nz-left-menu-shrink') == 'true',
parentMenu: {},
//active: "/overview",
//project相关
projectList: [],
moduleList: [],
showProjectPanel: true,
currentProjectTitle: '',
currentProject: {id: '', name: '', remark: ''}, //endpoint弹框、module列表用来回显project
module: {}, //编辑的module
blankModule: {name: '', project: {}, port: 9100, path: '', param: '',labels:'', type: 'http', paramObj: [],labelModule:[], snmpParam: '', walk: [], version: 2, max_repetitions: 25, retries: 3, timeout: 10, community: 'public', username: '', security_level: 'noAuthNoPriv', password: '', auth_protocol: 'MD5', priv_protocol: 'DES', priv_password: '', context_name: ''}, //空白module
currentModule: {id: '', type: '', name: '', project: {}, port: '', path: '', param: '', paramObj: [], snmpParam: '',labels:'',labelModule:[]}, //用来回显的module
ready: false,
rightBox: {module: {show: false}},
//asset相关
activeType: 'dataCenter',
activeTag:'',
dcData: [],
dcCheckList: [],
assetTypeData: [],
assetTypeCheckList: [],
vendorData: [],
vendorCheckList: [],
pingData: [],
pingCheckList: [],
tagData:[],
tagCheckList:[],
tagCheckMap:{},
lastCheckSize:0,
assetPingSwitch:true,
isRouterAlive: true,
projectChoose:[],
}
},
computed: {
route() {
return this.$route.path;
},
itemTip() {
return function(id, content, ready) {
let className = "item-tip-show";
this.$nextTick(() => {
if (ready) {
let cellDom = document.querySelector(`#module-${id}`);
let spanDom = document.querySelector(`#module-${id}>span`);
if (cellDom.offsetWidth - 16 <= spanDom.offsetWidth) {
document.querySelector(`#module-${id}>.el-popover`).classList.add(className);
} else {
document.querySelector(`#module-${id}>.el-popover`).classList.remove(className);
}
}
});
return "";
}
},
checkedTagCount(){
return this.tagCheckList.length;
},
currentProjectChange() {
return this.$store.state.currentProject;
}
},
watch: {
route: {
deep: true,
immediate: true,
handler(n) {
this.parentMenu = this.getParentMenu(n);
}
},
currentProjectChange: {
immediate: true,
handler(n, o) {
if (n && n.id != this.currentProject.id) {
this.currentProject = n;
if (this.currentProject && this.currentProject.id && this.showProjectPanel) {
this.detailProject(this.currentProject);
// this.projectChoose=[];
}
this.changeCurrentModule('');
}
},
},
currentProject: {
immediate: true,
deep: true,
handler(n, o) {
bus.$emit("current-project-change", n); //告知project.vue
},
},
dcCheckList: {
deep: true,
immediate:true,
handler(n) {
bus.$emit("asset-filter-change", "idcIds", n.join(","));
}
}
},
created() {
this.initEvent(); //注册监听事件
},
mounted() {
Promise.all([this.getProjectList(), this.getModuleList(), this.getLeftMenuList()]).then(response => {
setTimeout(() => {
this.ready = true;
}, 300);
});
},
methods: {
toggleStat() {
this.isShrink = !this.isShrink;
localStorage.setItem('nz-left-menu-shrink', this.isShrink);
if (this.resizeFunc) {
this.resizeFunc();
}
},
//根据route获取父菜单
getParentMenu(route) {
let parentMenu = "";
let end = false;
if (route != '/project'){
this.changeCurrentModule('');
}
if (route != '/project' && route != '/asset') {
this.$store.getters.menuList.forEach(menu => {
if (!end) {
if (menu.children) {
menu.children.forEach(subMenu => {
if (subMenu.route == route) {
parentMenu = menu;
end = true;
}
});
}
}
});
} else {
parentMenu = route;
}
return parentMenu;
},
getProjectList() {
return new Promise(resolve => {
this.$get('project', {pageSize: -1}).then(response=>{
if(response.code == 200){
this.projectList = response.data.list;
}
resolve(this.projectList);
});
});
},
getProjectModule(projectId) {
let moduleList = JSON.parse(JSON.stringify(this.moduleList));
return moduleList.filter((item,index) => {
return item.project.id == projectId;
})
},
getModuleList() {
return new Promise(resolve => {
this.$get('module', { pageSize: -1, pageNo: 1}).then(response => {
if (response.code === 200) {
this.moduleList = response.data.list;
for (let i = 0; i < this.moduleList.length; i++) {
try {
let param=this.moduleList[i].param|| '{}';
let tempObj = JSON.parse(param);
let labels=this.moduleList[i].labels|| '{}';
let tempObj1=JSON.parse(labels);
this.$set(this.moduleList[i], 'paramObj', []);
this.$set(this.moduleList[i], 'labelModule', []);
for (let k in tempObj) {
this.moduleList[i].paramObj.push({key: k, value: tempObj[k]});
}
for (let k in tempObj1) {
this.moduleList[i].labelModule.push({key: k, value: tempObj1[k]});
}
} catch (err) {}
}
}
resolve(this.moduleList);
});
});
},
//左侧module列表选中切换与project.vue同步
changeModule(project, module) {
this.showProjectPanel = false;
this.changeCurrentProject(project);
this.changeCurrentModule(module);
bus.$emit("project-page-type", "endpoint"); //告知project.vue
},
addModule(obj) {
this.module = this.newModule(obj);
this.rightBox.module.show = true;
this.$nextTick(() => {
this.$refs.moduleBox.initWalk();
});
},
newModule(obj) {
let module=JSON.parse(JSON.stringify(this.blankModule));
module.project = this.$store.state.currentProject;
if(obj){
module.project=obj;
}
return module
},
//弹出module编辑页
editModule(module) {
this.module = JSON.parse(JSON.stringify(module));
if (!this.module.paramObj) {
this.$set(this.module, 'paramObj', []);
}
if (!this.module.labelModule) {
this.$set(this.module, 'labelModule', []);
}
if (this.module.snmpParam) {
this.initSnmpParam(this.module);
}
this.rightBox.module.show = true;
this.$nextTick(() => {
this.$refs.moduleBox.initWalk();
});
},
closeModuleRightBox(refresh) {
this.rightBox.module.show = false;
if (refresh) {
this.getModuleList();
}
},
initSnmpParam(module) {
this.$set(module, 'walk', []);
this.$set(module, 'version', '');
this.$set(module, 'max_repetitions', '');
this.$set(module, 'retries', '');
this.$set(module, 'timeout', '');
this.$set(module, 'community', '');
this.$set(module, 'username', '');
this.$set(module, 'security_level', '');
this.$set(module, 'password', '');
this.$set(module, 'auth_protocol', '');
this.$set(module, 'priv_protocol', '');
this.$set(module, 'priv_password', '');
this.$set(module, 'context_name', '');
},
changeCurrentProject(project) {
// localStorage.setItem("nz-current-project", project.id);
this.$store.commit("currentProjectChange", project);
this.currentProject = project;
},
changeCurrentModule(module) {
bus.$emit("current-module-change", module); //告知project.vue
this.currentModule = module;
},
//与header.vue同步
detailProject(project) {
this.showProjectPanel = true;
this.changeCurrentProject(project);
bus.$emit("project-page-type", "project"); //告知project.vue
this.changeCurrentModule({id: ""});
},
initEvent() {
/*bus.$on("parent-menu-change", parentMenu => {
this.parentMenu = parentMenu;
});
bus.$on("menu-change", menu => {
this.active = menu;
});*/
bus.$on("header-dc-change", dcId => {
this.dcCheckList = [dcId];
// bus.$emit("asset-filter-change", "idcIds", dcId);
});
bus.$on("clear-asset-filter", dcId => {
this.dcCheckList = [];
this.assetTypeCheckList = [];
this.vendorCheckList = [];
this.pingCheckList = [];
});
bus.$on("project-list-change", () => {
this.getProjectList();
});
bus.$on("module-list-change", menu => {
this.getModuleList();
});
bus.$on('asset-list-change',()=>{
let dcData=JSON.parse(JSON.stringify(this.dcData))
let assetTypeData=JSON.parse(JSON.stringify(this.assetTypeData))
let vendorData=JSON.parse(JSON.stringify(this.vendorData))
let pingData=JSON.parse(JSON.stringify(this.pingData))
let tagData=JSON.parse(JSON.stringify(this.tagData))
this.getLeftMenuList().then(()=>{
let result=[];
let dcDiff=this.compareAssetLeftMenu(dcData,this.dcData,"idcIds")
if(dcDiff.length>0){
let temp =this.dcCheckList.filter(item=>{
return !dcDiff.find((t,i)=>{return item == t.id})
})
result.push({key:"idcIds",value:temp.join(',')})
this.dcCheckList=temp;
}
let typeDiff=this.compareAssetLeftMenu(assetTypeData,this.assetTypeData,'typeIds')
if(typeDiff.length>0){
this.assetTypeCheckList=this.assetTypeCheckList.filter(item=>{
return !typeDiff.find(t=>{return item == t.id})
})
result.push({key:'typeIds',value:this.assetTypeCheckList.join(',')})
}
let vendorDiff=this.compareAssetLeftMenu(vendorData,this.vendorData,'vendorIds')
if(vendorDiff.length>0){
this.vendorCheckList=this.vendorCheckList.filter(item=>{
return !vendorDiff.find(t=>{return item == t.id})
})
result.push({key:'vendorIds',value:this.vendorCheckList.join(',')})
}
let pingDiff=this.compareAssetLeftMenu(pingData,this.pingData,'pingStates')
if(pingDiff.length>0){
this.pingCheckList=this.pingCheckList.filter(item=>{
return !pingDiff.find(t=>{return item == t.value})
})
result.push({key:'pingStates',value:this.pingCheckList.join(',')})
}
let tagDiff=this.compareAssetLeftMenu(tagData,this.tagData,"tags")
if(tagDiff.length>0){
let $self=this;
tagDiff.forEach(item=>{
let key=item.key;
let values=item.values;
let checkedVals=$self.tagCheckMap[key];
if(checkedVals&&checkedVals.length>0){
$self.tagCheckList=$self.tagCheckList.filter(t=>{return !values.find(r=>{return key+"-"+r.value == t})})
$self.lastCheckSize = $self.lastCheckSize - values.length;
checkedVals=checkedVals.filter(t=>{return !values.find(r=>{return r.value == t;})})
if(checkedVals.length>0){
$self.tagCheckMap[key]=checkedVals;
}else{
delete $self.tagCheckMap[key]
}
}
})
if(Object.keys($self.tagCheckMap).length > 0){
result.push({key:'tags',value:JSON.stringify($self.tagCheckMap)})
} else{
result.push({key:'tags',value:''})
}
}
bus.$emit("asset-filter-change", "multiParam", result);
});
})
bus.$on('asset-property-change',()=>{
this.getLeftMenuList();
})
bus.$on('asset-ping-switch-change',(isOpen)=>{
this.assetPingSwitch = isOpen
})
},
// 获取asset左侧菜单数据
getLeftMenuList(){
return new Promise(resolve => {
this.$get('asset/filter').then(response => {
if (response.code === 200) {
//dc
this.dcData = response.data.dc;
// AssetType
this.assetTypeData = response.data.assetType;
// vendor
this.vendorData = response.data.vendor;
// ping
this.pingData=[{label:'up',value:1,total:0},{label:'down',value:0,total:0}]
this.pingData.map(item=>{
if(response.data.ping){
let data=response.data.ping.find(t=>t.name == item.label);
if(data){
item.total = data.total;
item.value = data.status
}
}
return item;
})
this.tagData = response.data.tag
}
resolve();
});
});
},
compareAssetLeftMenu:function(src,dist,key){
let result=src.filter(item=>{
if(key == 'pingStates'){
return !dist.find(t=>{return t.name == item.name})
}
if(key == 'tags'){
let tag=dist.find(t=>{
return t.key == item.key
})
if(tag){
let srcValues=item.values;
let distValues=tag.values
let vals=srcValues.filter(t=>{
return distValues.find(r=>{
return r.value == t.value;
})
})
return !vals || vals.length < 1;
}else{
return true;
}
}
return !dist.find(t=>{return item.id == t.id;})
})
return result
},
//asset左侧菜单4个事件
changeCheckBox() {
this.assetClick = true;
},
changeAssetTypeCheckBox() {
if(this.assetTypeCheckList && this.assetTypeCheckList.length > 0){
let assetTypeIds = this.assetTypeCheckList.join(',');
bus.$emit("asset-filter-change", "typeIds", assetTypeIds);
}else{
bus.$emit("asset-filter-change", "typeIds", "");
}
},
changeVendorCheckBox() {
if(this.vendorCheckList && this.vendorCheckList.length > 0){
let vendorIds = this.vendorCheckList.join(',');
bus.$emit("asset-filter-change", "vendorIds", vendorIds);
}else{
bus.$emit("asset-filter-change", "vendorIds", "");
}
},
changePingCheckBox() {
if(this.pingCheckList && this.pingCheckList.length > 0){
let pingStates = this.pingCheckList.join(',');
bus.$emit("asset-filter-change", "pingStates", pingStates);
}else{
bus.$emit("asset-filter-change", "pingStates", "");
}
},
changeTagCheckBox(tag,value){
let checked=this.tagCheckMap[tag.key];
if(!checked){
checked=[];
}
if(this.lastCheckSize < this.tagCheckList.length){
checked.push(value)
}else{
let index=checked.findIndex(item=>{
return item == value
})
checked.splice(index,1)
}
if(checked.length>0){
this.tagCheckMap[tag.key] = checked;
}else{
if(this.tagCheckMap[tag.key]){
delete this.tagCheckMap[tag.key]
}
}
this.lastCheckSize = this.tagCheckList.length;
if(Object.keys(this.tagCheckMap).length > 0){
bus.$emit("asset-filter-change", "tags", JSON.stringify(this.tagCheckMap));
}else{
bus.$emit("asset-filter-change", "tags", '');
}
},
indOf(a, b) {
let c = [];
for (let i = 0; i < a.length; i++) {
c.push(a[i]);
}
if (c.indexOf(b) > -1) {
return true;
} else {
return false;
}
},
jumpTo(route) {
if(route == this.route){
this.reload();
}
this.$router.push({
path: route,
query: {
t: +new Date()
}
});
},
reload () {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
}
},
beforeDestroy(){
/*bus.$off("parent-menu-change");
bus.$off("menu-change");*/
bus.$off("header-dc-change");
bus.$off("clear-asset-filter");
bus.$off("project-list-change");
bus.$off("module-list-change");
bus.$off('asset-list-change');
bus.$off('asset-property-change')
bus.$off('asset-ping-switch-change')
}
}
</script>
<style scoped lang="scss">
.content{
position: relative;
height: calc(100% - 54px);
}
.slot-content{
height: 100%;
}
.content .left-slot{
position: relative;
background-color: $left-menu-bgcolor;
transition: transform 200ms, opacity 200ms;
transform: scaleX(1);
transform-origin: left;
opacity: 1;
/*border-bottom: 1px solid #eeeeee;*/
/*transition: all 100ms;*/
}
.content .right-slot{
width: calc(100% - 200px);
}
.content .right-slot-open{
width: calc(100% - 23px);
margin-left: -177px;
}
.content .left-slot-shrink{
transform: scaleX(0.12);
opacity: 0;
.bottom-icon .bottom-divider{
width: 0px;
}
}
.slot-content {
transition: opacity 200ms;
}
.item-tip {
position: relative;
}
.item-tip-hide {
display: none;
position: absolute;
bottom: 30px;
min-width: 50px;
white-space: normal;
}
.sidebar-info-sub-item:first-of-type .item-tip-hide {
bottom: -50px;
}
.item-tip:hover>.item-tip-show {
display: block;
}
.hid-div{
visibility: hidden;
}
.sidebar-info-sub-item:hover .hid-div{
visibility: visible;
}
.sub-sidebar-info{
padding-top: 10px !important;
padding-left: 10px;
box-sizing: border-box;
}
.sub-side-bar-menu-edit{
margin-right: 13px;
}
.sidebar-info-item-project.sidebar-info-item{
margin:0 !important;
}
.sidebar-info-item-asset .sidebar-info-item-txt{
vertical-align: text-top;
}
/deep/ .el-badge__content{
min-width: 15px;
}
.left-slot .bottom-icon{
position:absolute;
width: 36px;
height: 36px;
right: 0;
bottom: 30px;
}
.left-slot .bottom-icon i{
visibility: hidden;
}
.left-slot:hover{
.bottom-icon i{
visibility: visible;
}
}
.left-slot .bottom-icon i:hover{
cursor: pointer;
}
.bottom-icon .bottom-divider{
display: inline-block;
height: 1px;
width: 175px;
border-top: 1px solid lightgrey;
vertical-align: middle;
visibility: hidden;
}
.content .left-slot-shrink:hover{
transform: scaleX(1);
z-index: 100;
opacity: 1;
.bottom-icon{
z-index: 101;
}
.bottom-icon .bottom-divider{
width: 175px;
}
}
.content-left .sidebar-info-item-project-add{
border: 1px solid rgba(0,0,0,0.15);
border-radius: 4px;
text-align: center;
font-family: Roboto-Regular;
font-size: 14px;
color: #535B64;
margin-right: 25px;
height: 30px;
line-height: 30px;
display: flex;
padding-left: 0;
justify-content: center;
}
/deep/ .el-badge__content--primary{
background-color: #74A7FA;
}
</style>
<style lang="scss">
</style>