feat:添加预览页面 以及调整 chat图 删除无用页面

This commit is contained in:
zhangyu
2021-02-05 11:41:20 +08:00
parent 6f51e9d5cc
commit 624eaa9760
10 changed files with 2219 additions and 4756 deletions

View File

@@ -1,8 +1,8 @@
<template>
<div class="tooltip-box" style="display: flex;" v-if="chartData.tooltipShow">
<div class="tooltip-box" style="display: flex;" v-if="isChart||chartData.tooltipShow">
<span class="temp-dom"></span>
<div class="tooltip-box-chart" style="" v-if="chartData.displayChart&&chartData.tooltipShow">
<line-chart-block v-if="chartData.type !== 'table'"
<div class="tooltip-box-chart" style="" v-if="isChart||(chartData.displayChart&&chartData.tooltipShow)">
<line-chart-block v-if="isChart || chartData.type !== 'table'"
:key="'inner' + chartData.id"
:from="'project'"
:ref="'editChart' + 0"
@@ -24,7 +24,7 @@
<!--:panel-id="-1"-->
<!--:chart-data="chartData"-->
<!--:chart-index="0"></chart-table>-->
<div class="tooltip-box-info">
<div class="tooltip-box-info" v-if="!isChart">
<expression-info :chart-data="chartData" :filterTime="filterTime"/>
</div>
</div>
@@ -47,6 +47,10 @@
type:Object,
},
filterTime:{},
isChart:{
type:Boolean,
default:false,
}
},
watch:{
chartDataParent:{

View File

@@ -1,819 +0,0 @@
<template>
<div class="mc" @click.self="clickOutside">
<div class="right-box right-box-edit-endpoint">
<!-- begin--顶部按钮-->
<div class="right-box-top-btns right-box-form-delete" v-if="lineData.id">
<button id="edit-ep-del" type="button" @click="del" class="nz-btn nz-btn-size-normal nz-btn-size-alien">
<span class="right-box-top-btn-icon"><i class="nz-icon nz-icon-delete"></i></span>
<span class="right-box-top-btn-txt">{{$t('overall.delete')}}</span>
</button>
</div>
<!-- end--顶部按钮-->
<!-- begin--标题-->
<div class="right-box-title" v-if="!lineData.id">
{{$t('project.topology.addLine')}}
</div>
<div class="right-box-title" v-if="lineData.id">
{{$t("project.topology.editLine")}}
</div>
<!-- end--标题-->
<!-- begin--表单-->
<div class="right-box-form-box">
<el-form class="right-box-form right-box-form-left" ref="form" :model="form" label-width="120px" :rules="rules">
<el-form-item :label="$t('project.topology.lineName')" prop="lineName" class="line-name">
<el-input v-model="form.lineName" size="small"></el-input>
</el-form-item>
<div class="right-box-sub-title" style="margin-bottom: 20px">{{$t('project.topology.option')}}</div>
<div class="line-option">
<!--<el-form-item :label="$t('project.topology.width')" prop="width" class="line-width">-->
<!--<el-input v-model="form.width" size="small"></el-input>-->
<!--</el-form-item>-->
<el-form-item :label="$t('project.topology.width')" prop="width" class="line-width">
<el-select v-model="form.width" placeholder="" :popper-append-to-body="false" size="small">
<div slot="prefix">
<div class="width-option">
<div :style="{height:0,width:'80%',borderTop:form.width+'px'+' solid' +' #899FB7'}"></div>
</div>
</div>
<el-option v-for="(item,index) in widthOption" :label="item+'px'" :value="item" :key="index">
<div class="width-option">
<span style="marginRight:5px">{{item}}px</span><div class="width-option-line" :style="{height:0,width:'80%',borderTop:item+'px solid #899FB7'}"></div>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('project.topology.dashes')" prop="dashes" class="line-width">
<el-select v-model="form.dashes" placeholder="" :popper-append-to-body="false" size="small">
<div slot="prefix">
<div class="width-option">
<div class="width-option-line" v-if="!form.dashes" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}"></div>
<div class="dashes-box" v-if="form.dashes">
<div class="width-option-line"
v-for="count in dashesCount(form.dashes)"
:key="count"
:style="{
height:0,
width:dashesWidth(form.dashes)+'px',
borderTop:'1px solid #899FB7',
display:'inline-block'
}">
</div>
</div>
</div>
</div>
<el-option v-for="(item,index) in dashesOption" :label="item+'px'" :value="item" :key="index">
<div class="width-option">
<div class="width-option-line" v-if="!item" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}"></div>
<div class="dashes-box" v-if="item">
<div class="width-option-line"
v-for="count in dashesCount(item)"
:key="count"
:style="{
height:0,
width:dashesWidth(item)+'px',
borderTop:'1px solid #899FB7',
display:'inline-block'
}">
</div>
</div>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('project.topology.arrows')" prop="arrows" class="arrows">
<el-select v-model="form.arrows" placeholder="" :popper-append-to-body="false" size="small">
<div slot="prefix">
<div class="width-option">
<div v-if='form.arrows==="from"' class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-right" style="top: -15px;"></i>
</div>
<div v-if='form.arrows==="to"' class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-left" style="top: -15px;"></i>
</div>
<div v-if='form.arrows==="from;to"' class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-left" style="top: -15px;"></i>
<i class="nz-icon nz-icon-sanjiaoxing position-right" style="top: -15px;"></i>
</div>
<div v-if='form.arrows==="0"' class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}"></div>
</div>
</div>
<el-option label="from" value="from">
<div class="width-option">
<div class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-right"></i>
</div>
</div>
</el-option>
<el-option label="to" value="to">
<div class="width-option">
<div class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-left"></i>
</div>
</div>
</el-option>
<el-option label="from;to" value="from;to">
<div class="width-option">
<div class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}">
<i class="nz-icon nz-icon-sanjiaoxing position-left"></i>
<i class="nz-icon nz-icon-sanjiaoxing position-right"></i>
</div>
</div>
</el-option>
<el-option label="" value="0">
<div class="width-option">
<div class="width-option-line" :style="{height:0,width:'80%',borderTop:'1px solid #899FB7'}"></div>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('project.topology.color')" class="color">
<div class="color-show" @click="colorPickerClick" v-clickoutside="colorOut">
<div class="color-show-left" :style="{background:form.color}"></div>
<span> {{form.color}}</span>
<span class="color-arrows">
<i class="nz-icon nz-icon-arrow-down" v-show="!showPicker"></i>
<i class="nz-icon nz-icon-arrow-up" v-show="showPicker"></i>
</span>
</div>
<div class="color-content" ref="color-content">
<el-color-picker
v-model="form.color"
:predefine="predefineColors"
ref="colorPicker"
@active-change="colorChange"
>
</el-color-picker>
</div>
</el-form-item>
<el-form-item :label="$t('project.topology.lineType')" prop="type" class="type">
<el-select v-model="form.type" placeholder="" :popper-append-to-body="false" size="small">
<el-option :label="$t('project.topology.straight')" :value="false">
{{$t('project.topology.straight')}}
</el-option>
<!--<el-option label="continuous" value="continuous">-->
<!--continuous-->
<!--</el-option>-->
<!--<el-option label="discrete" value="discrete">-->
<!--discrete-->
<!--</el-option>-->
<!--<el-option label="diagonalCross" value="diagonalCross">-->
<!--diagonalCross-->
<!--</el-option>-->
<!--<el-option label="straightCross" value="straightCross">-->
<!--straightCross-->
<!--</el-option>-->
<!--<el-option label="horizontal" value="horizontal">-->
<!--horizontal-->
<!--</el-option>-->
<!--<el-option label="vertical" value="vertical">-->
<!--vertical-->
<!--</el-option>-->
<el-option :label="$t('project.topology.curve')" value="curvedCW">
{{$t('project.topology.curve')}}
</el-option>
</el-select>
</el-form-item>
</div>
<div class="right-box-sub-title" style="margin-bottom: 20px">
<span>{{$t('alert.config.expr')}}</span>
<span class="float-right" @click="addExpression"><i style="font-size: 16px; cursor: pointer;" class="nz-icon nz-icon-create-square"></i></span>
</div>
<el-row class="element-item expr form-row-item" style="" v-for="index of promqlKeys.length" :key="'ele' + index">
<span class="nz-icon-minus-medium nz-icon-minus-position" style="padding: 0 8px"><i class="nz-icon nz-icon-minus" @click="removeExpression(index-1)"></i></span>
<el-form-item :rules="{required: true,message: '名称不能为空', trigger: 'blur'}" :prop="'name.' + (index-1)">
<el-row>
<template>
<el-col class="expr-title" style="">
{{$t('project.topology.chartName')}}
</el-col>
<el-col style="width: calc(100% - 122px);">
<el-input
v-model="form.name[index-1]"
type="text"
size="small"
></el-input>
</el-col>
</template>
</el-row>
</el-form-item>
<el-row>
<el-col class="expr-title">
{{$t('project.topology.unit')}}
</el-col>
<el-col style="width: calc(100% - 120px);">
<el-cascader filterable placeholder="" popper-class="no-style-class unit-popper-class" size="small" style="width: 100%"
:options="unitOptions"
:props="{ expandTrigger: 'click',emitPath:false }"
:show-all-levels="false"
v-model="unit[index-1]"
></el-cascader>
</el-col>
</el-row>
<div>
<promql-input
:ref="'promql-'+(index-1)"
:id="promqlKeys[index-1]"
:key="promqlKeys[index-1]"
:expression-list="expressions"
:index="index-1"
:styleType="2"
:plugins="['metric-selector', 'metric-input', 'remove']"
@change="expressionChange"
@removeExpression="removeExpression"
:showRemove="false"
:projectRightBox="true"
></promql-input>
</div>
<el-row>
<template>
<el-col class="expr-title">
{{$t('dashboard.panel.chartForm.legend')}}&nbsp;
<el-popover :content="$t('dashboard.panel.chartForm.legendTip')" placement="top" width="150" trigger="hover">
<i slot="reference" class="nz-icon nz-icon-info-normal" @mouseover="rz"></i>
</el-popover>
</el-col>
<el-col style="width: calc(100% - 120px);">
<el-input v-model="legends[index-1]" type="text" size="small"></el-input>
</el-col>
</template>
</el-row>
</el-row>
</el-form>
</div>
<!-- end--表单-->
<!--底部按钮-->
<div class="right-box-bottom-btns">
<button @click="esc" id="ep-edit-esc" class="nz-btn nz-btn-size-normal-new nz-btn-style-light-new">
<span>{{$t('overall.cancel')}}</span>
</button>
<button @click="onSubmit" id="ep-edit-save" class="nz-btn nz-btn-size-normal-new nz-btn-style-normal-new">
<span>{{$t('overall.save')}}</span>
</button>
</div>
</div>
</div>
</template>
<script>
import promqlInput from "@/components/page/dashboard/explore/promqlInput";
import chartDataFormat from "@/components/charts/chartDataFormat";
import {getUUID,resetZIndex} from "@/components/common/js/common";
var rz = {
methods: {
rz(e) {
resetZIndex(e);
}
}
};
export default {
name:"addLine",
props:{
lineData:{},
},
components:{
'promql-input': promqlInput,
},
mixins: [rz],
watch:{
lineData:{
handler(n){
console.log(n);
this.form={
arrows:n.arrows,
color:n.color,
lineId:n.id,
width:n.width,
lineName:n.name,
name:[],
dashes:!n.dashes?n.dashes:JSON.stringify(n.dashes),
type:n.smooth.type?n.smooth.type:false,
// dashes:!n.dashes?n.dashes:JSON.stringify([n.dashes[2],n.dashes[2]]),
};
if( n.expressions){
n.expressions.forEach((item,index)=>{
this.addExpression();
this.form.name[index]=item.name;
this.unit[index]=item.unit;
this.expressions[index]=item.metric;
this.legends[index]=item.legend;
})
}
},
immediate: true,
deep: true,
}
},
data(){
return{
metricList: [], // metric列表
metricCascaderList:[],//metric级联列表
metricAllData:new Map(),//存放所有的project-module-metric-labelValue避免重复加载
metricOptions: [],
form:{
arrows:'0',
label:'',
color:'#1e90ff',
lineName:'',
lineId:'',
width:'',
type:'',
roundness:'',
name:[],
dashes:''
},
predefineColors: [
'#ff4500',
'#ff8c00',
'#ffd700',
'#90ee90',
'#00ced1',
'#1e90ff',
'#c71585',
],
showPicker:false,
unitOptions: chartDataFormat.unitOptions(),
promqlKeys:[],
expressions: [],
promqlCount:0,
elementIds:[],
legends:[],
widthOption:['1','2','3','4'],
dashesOption:[false,'[3,3]','[9,9]','[15,15]','[21,21]'],
unit:[],
rules:{
// arrows: [
// { required: true, message: '', trigger: 'change' },
// ],
lineName: [
{ required: true, message: '', trigger: 'change' },
],
}
}
},
mounted(){
// this.addExpression();
this.queryMetrics();
if( this.lineData.expressions){
this.lineData.expressions.forEach((item,index)=>{
this.$refs['promql-'+(index)][0].metricChange(this.expressions[index]);
})
}
},
methods:{
getMetricOptions() {
return this.metricOptions;
},
queryMetrics() {
this.metricOptions = [];
this.$get('prom/api/v1/label/__name__/values').then(response=>{
if(response.status == 'success'){
let metrics=response.data.sort();
let metricMap=new Map();
metrics.forEach((item)=>{
let key='';
if(/^[a-zA-Z]+?_[a-zA-Z]*/.test(item)){
key=item.split('_')[0];
}else if(/^_\w*/.test(item)){
key=' ';
}else{
key=item;
}
if(metricMap.get(key)){
let values=metricMap.get(key);
values.push({label:item,value:item});
}else{
let values=[{label:item,value:item}];
metricMap.set(key,values);
}
//this.metricStore.push({label:item,value:item,insertText:item})
});
for(let key of metricMap.keys()){
let option={
label:key,
value:key,
};
if(metricMap.get(key) && metricMap.get(key).length>1){
option.children=metricMap.get(key);
}
this.metricOptions.push(option);
}
}
})
},
onSubmit(){
this.$refs['form'].validate((valid) => {
if (valid) {
let model=Object.assign({id:this.form.lineId?this.form.lineId:undefined},{...this.form},{color: {color:this.form.color,highlight:this.form.color,hover:this.form.color,opacity:1.0}});
// model.label=this.form.lineName;
model.name=this.form.lineName;
model.width = parseInt(model.width) || 4;
if(!this.form.type){
model.smooth={
enabled:false,
};
} else{
model.smooth={
roundness:0.5 ,// (Math.random()*8 +1)/10 获取0.1-0.9之间的随机数
type:this.form.type,
};
}
model.dashes=!model.dashes?model.dashes:JSON.parse(model.dashes);
model.expressions=[];
this.promqlKeys.forEach((item,index)=>{
model.expressions.push({
"name": this.form.name[index],
"unit": this.unit[index],
"metric": this.expressions[index],
"legend": this.legends[index],
})
});
this.$emit('addLine',model);
}
});
},
expressionChange: function () {
},
addExpression() {
this.expressions.push('');
this.legends.push('');
this.form.name.push('');
this.unit.push(1);
this.promqlKeys.push(getUUID());
this.elementIds.push("");
this.promqlCount++;
},
removeExpression(index) {
if (this.promqlCount >= 1) {
this.expressions.splice(index, 1);
this.legends.splice(index, 1);
this.form.name.splice(index, 1);
this.unit.splice(index, 1);
this.promqlKeys.splice(index, 1);
this.elementIds.splice(index, 1);
this.promqlCount--;
this.$nextTick(() => {
this.expressions.forEach((ex, index) => {
if (ex) {
this.$refs[`promql-${index}`][0].metricChange(ex);
}
});
});
}
},
/*关闭弹框*/
esc(refresh) {
this.$emit("close", refresh);
},
clickOutside() {
this.esc(false);
},
del(){
this.$emit('del');
this.esc();
},
colorPickerClick(){
this.showPicker=true;
this.$refs['colorPicker'].showPicker=true;
},
colorChange(val){
this.form.color=this.colorRGBtoHex(val)
},
colorRGBtoHex(color) {
let rgb = color.split(',');
let r = parseInt(rgb[0].split('(')[1]);
let g = parseInt(rgb[1]);
let b = parseInt(rgb[2].split(')')[0]);
let hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
return hex;
},
colorOut(){
this.showPicker=false;
},
//返回dashes的第一項
dashesWidth(item){
return JSON.parse(item)[0]
},
// 返回應該遍历的次数
dashesCount(item){
if(!item){
return 0;
}
return Math.floor(190/this.dashesWidth(item)/2);
}
},
}
</script>
<style scoped>
.mc{
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: 11;
}
.color-content{
height: 0;
width: 0;
overflow: hidden;
position: absolute;
top: 0;
left: 140px;
}
.color{
position: relative;
}
.color-show{
border: 1px solid #E7EAED;
border-radius: 5px;
display: flex;
align-items: center;
width: calc(100% - 32px);
height: 30px;
}
.color-show-left{
width: 18px;
height: 18px;
border: 1px solid #E7EAED;
border-radius: 5px;
margin: 0 5px;
}
.line-name{
width: calc(100% - 70px);
}
.form-title{
font-size: 14px;
color: #333333;
padding-left: 28px;
margin-bottom: 15px;
}
/deep/ .el-form-item__label{
font-size: 14px;
color: #666666;
}
.arrows /deep/ .el-input.el-input--prefix.el-input--suffix,.line-width /deep/ .el-input.el-input--prefix.el-input--suffix{
border: 1px solid #DCDFE6;
height: 28px;
width: calc(100% - 32px);
}
.arrows /deep/ .el-input__inner,.line-width /deep/ .el-input__inner{
display: none;
}
.arrows /deep/ .el-input__prefix,.line-width /deep/ .el-input__prefix{
height: 28px;
line-height: 28px;
color: #899FB7;
}
.arrows /deep/ .el-input__prefix > div{
width: 100%;
height: 100%;
}
.line-width /deep/ .el-input__prefix{
width: calc(100% - 32px);
display: flex;
align-items: center;
}
.line-width /deep/ .el-input__prefix > div{
width: 100%;
}
/deep/ .el-select{
width: 100%;
}
.line-option{
display: flex;
flex-wrap: wrap;
margin-left: 70px;
}
.line-option > div{
width: 50%;
}
.line-option .line-width .el-input{
width: clac(100% - 60px);
}
/deep/ .el-input--small .el-input__icon{
line-height: 28px;
}
.width-option-line{
position: relative;
color: #899FB7;
}
.position-left{
position: absolute;
left:-4px ;
top: -18px;
transform: rotate(180deg);
}
.position-right{
position: absolute;
right: -4px;
top: -18px;
}
/deep/ .el-select-dropdown__item.selected .width-option-line {
border-color: #ee9d3f !important;
color: #ee9d3f !important;
}
/deep/ .el-dropdown-menu__item:focus .width-option-line, .el-dropdown-menu__item:not(.is-disabled):hover .width-option-line, .el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover .width-option-line, .el-select-dropdown__item.hover .width-option-line, .el-select-dropdown__item:hover .width-option-line{
border-color: #ee9d3f !important;
color: #ee9d3f !important;
}
.color-arrows{
color: #C0C4CC;
position: absolute;
right: 42px;
}
.color-arrows .nz-icon{
font-size: 12px;
}
.element-item{
padding: 20px 0;
border-bottom: 1px dashed #dfe7f2;
width: 100%;
}
/deep/ .right-box-form .element-item.form-row-item {
padding: 20px 20px 20px 0;
border: 1px dashed #dfe7f2;
width: calc(100% - 120px);
margin-left: 70px;
position: relative;
}
.element-item.expr /deep/ .el-form-item__content{
position: relative;
margin-left: 0 !important;
}
.element-item.expr /deep/ .el-form-item__content .el-row{
margin-bottom: 0;
}
.element-item.expr /deep/ .el-form-item__content .el-form-item__error{
left: 120px;
}
.expr-title{
width: 120px;
padding-right: 20px;
text-align: right;
color: #666;
font-size: 14px;
letter-spacing: 0;
line-height: 22px;
}
/deep/.promqlInput .expr-title{
padding-right: 0;
}
.width-option{
width: 190px;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
overflow: hidden;
}
.dashes-box{
height:100%;
width:80%;
overflow: hidden;
display: flex;
justify-content: space-between;
align-items: center;
}
.type /deep/ .el-input--suffix{
width: calc(100% - 30px);
}
.type /deep/ .el-scrollbar__view.el-select-dropdown__list{
width: 256px;
}
.el-row {
margin-bottom: 20px;
line-height: 32px;
}
.el-row:last-child {
margin-bottom: 0;
}
.nz-btn-edit-ok{
position: absolute;
bottom: 0;
right:0;
}
.nz-btn-edit-esc{
position: absolute;
bottom: 0;
left:0;
}
/* begin--搜索框*/
.endpoint-asset-search {
display: inline-block;
position: relative;
margin-top: -16px;
}
.endpoint-asset-search button {
height: 22px !important;
}
.endpoint-asset-search-dropdown {
position: absolute;
top: 25px;
background-color: #444;
border-radius: 4px;
width: 44px;
left: 0;
}
.endpoint-asset-search-dropdown-item {
text-align: center;
line-height: 22px;
height: 22px;
cursor: default;
color: white;
font-size: 12px;
}
.endpoint-asset-label-txt {
display: inline-block;
width: 19px;
text-align: center;
}
.endpoint-asset-search-dropdown-item:first-of-type {
border-radius: 4px 4px 0 0;
}
.endpoint-asset-search-dropdown-item:last-of-type {
border-radius: 0 0 4px 4px;
}
.endpoint-asset-search-dropdown-item:hover {
background-color: #222;
color: #ff9900;
}
.endpoint-asset-search-input {
display: inline-block;
width: 150px;
vertical-align: top;
}
/* end--搜索框*/
/* begin--table*/
.endpoint-sub-table {
padding-top: 30px;
height: 440px;
}
.line-100 {
margin-bottom: 3px;
}
.endpoint-sub-table-head {
line-height: 28px;
height: 30px;
}
.endpoint-sub-table-row, .endpoint-sub-table-row-disabled {
line-height: 28px;
height: 30px;
color: #656565;
}
.endpoint-sub-table-row:hover {
background-color: #dadada;
cursor: default;
}
.endpoint-sub-table-row-active {
background-color: #dadada;
}
.endpoint-sub-table-row-selected {
background-color: #656565;
color: white;
}
.endpoint-sub-table-col {
display: inline-block;
width: calc(50% - 15px);
padding-left: 10px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.endpoint-sub-table-paginate-all {
position: absolute;
left: 10px;
bottom: 17px;
color: #5a5a5a;
}
.endpoint-sub-table-body {
font-size: 15px;
position: relative;
overflow: auto;
height: calc(100% - 34px);
}
.endpoint-sub-table-body-dialog {
width: 100%;
height: 100%;
background-color: #e9ebec;
position: absolute;
opacity: 0.2;
}
.endpoints-clear-btn {
margin: 6px 0 0 7px;
}
/* end--table*/
</style>

View File

@@ -1,745 +0,0 @@
<template>
<div class="mc" @click.self="clickOutside">
<div class="right-box right-box-edit-endpoint">
<!-- begin--顶部按钮-->
<div class="right-box-top-btns right-box-form-delete" v-if="nodeData.id">
<button id="edit-ep-del" type="button" @click="del" class="nz-btn nz-btn-size-normal nz-btn-size-alien">
<span class="right-box-top-btn-icon"><i class="nz-icon nz-icon-delete"></i></span>
<span class="right-box-top-btn-txt">{{$t('overall.delete')}}</span>
</button>
</div>
<!-- end--顶部按钮-->
<!-- begin--标题-->
<div class="right-box-title" v-if="!nodeData.id">
{{$t("project.topology.addModule")}}
</div>
<div class="right-box-title" v-if="nodeData.id">
{{$t("project.topology.editModule") + " ID" + nodeData.id}}
</div>
<!-- end--标题-->
<!-- begin--表单-->
<div class="right-box-form-box" ref="scrollbar">
<el-form class="right-box-form right-box-form-left" ref="form" :model="form" label-width="160px" :rules="rules">
<el-form-item label="Module Name" prop="moduleId">
<el-select v-model="form.moduleId" placeholder="" popper-class="asset-dropdown" size="small">
<el-option
v-for="item in moduleDataS.module"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="Icon" prop="iconId" class="icon">
<el-select :loading="imgageLoading" class="icon-select" placeholder="" popper-class="asset-dropdown" size="small" v-model="form.iconId">
<div slot="prefix" class="sel-image">
<img :src="selImage.image" style="height: 24px; width: auto; max-width: 48px; margin-top: 2px" v-if="form.iconId"/>
<span v-if="form.iconId" class="sel-image-name">{{selImage.imageName}}</span>
</div>
<el-option
v-for="item in iconArray"
:key="item.id"
:label="item.label"
:value="item.id">
<span style="float: left; width: 55px;">
<img :src="item.image" style="height: 28px; width: auto; max-width: 48px; margin-top: 2px"/>
</span>
<span style="color: #8492a6; font-size: 13px">{{ item.imageName }}</span>
</el-option>
</el-select>
<el-upload
class="avatar-uploader"
action=" "
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:auto-upload="true"
>
{{$t('project.topology.upload')}}
</el-upload>
</el-form-item>
<div class="right-box-sub-title" style="padding-bottom: 8px;margin-bottom: 20px">
<span>{{$t('alert.config.expr')}}</span>
<span class="float-right" @click="addExpression"><i style="font-size: 16px; cursor: pointer;" class="nz-icon nz-icon-create-square"></i></span>
</div>
<el-row :key="'ele' + index" class="element-item expr form-row-item" v-for="index of promqlKeys.length">
<span class="nz-icon-minus-medium nz-icon-minus-position" style="padding: 0 8px; margin-left: 8px;"><i @click="removeExpression(index-1)" class="nz-icon nz-icon-minus"></i></span>
<el-form-item :prop="'name.' + (index-1)" :rules="{required: true,message: '名称不能为空', trigger: 'blur'}">
<el-row>
<template>
<el-col class="expr-title" style="">
{{$t('project.topology.chartName')}}
</el-col>
<el-col style="width: calc(100% - 122px);">
<el-input
v-model="form.name[index-1]"
type="text"
size="small"
></el-input>
</el-col>
</template>
</el-row>
</el-form-item>
<el-row>
<el-col class="expr-title">
{{$t('project.topology.unit')}}
</el-col>
<el-col style="width: calc(100% - 120px);">
<el-cascader filterable placeholder="" popper-class="no-style-class unit-popper-class" size="small" style="width: 100%"
:options="unitOptions"
:props="{ expandTrigger: 'click',emitPath:false }"
:show-all-levels="false"
v-model="unit[index-1]"
></el-cascader>
</el-col>
</el-row>
<div>
<promql-input
:ref="'promql-'+(index-1)"
:id="promqlKeys[index-1]"
:key="promqlKeys[index-1]"
:expression-list="expressions"
:index="index-1"
:styleType="2"
:plugins="['metric-selector', 'metric-input', 'remove']"
@change="expressionChange"
@removeExpression="removeExpression"
:showRemove="false"
:projectRightBox="true"
></promql-input>
</div>
<el-row>
<template>
<el-col class="expr-title">
{{$t('dashboard.panel.chartForm.legend')}}&nbsp;
<el-popover :content="$t('dashboard.panel.chartForm.legendTip')" placement="top" width="150" trigger="hover">
<i slot="reference" class="nz-icon nz-icon-info-normal" @mouseover="rz"></i>
</el-popover>
</el-col>
<el-col style="width: calc(100% - 120px);">
<el-input v-model="legends[index-1]" type="text" size="small"></el-input>
</el-col>
</template>
</el-row>
</el-row>
</el-form>
</div>
<!-- end--表单-->
<!--底部按钮-->
<div class="right-box-bottom-btns">
<button @click="esc" id="ep-edit-esc" class="nz-btn nz-btn-size-normal-new nz-btn-style-light-new">
<span>{{$t('overall.cancel')}}</span>
</button>
<button @click="onSubmit" id="ep-edit-save" class="nz-btn nz-btn-size-normal-new nz-btn-style-normal-new">
<span>{{$t('overall.save')}}</span>
</button>
</div>
</div>
</div>
</template>
<script>
import promqlInput from "@/components/page/dashboard/explore/promqlInput";
import chartDataFormat from "@/components/charts/chartDataFormat";
import {getUUID,resetZIndex} from "@/components/common/js/common";
var rz = {
methods: {
rz(e) {
resetZIndex(e);
}
}
};
export default {
name:"addNode",
components:{
'promql-input': promqlInput,
},
props:{
nodeData:{},
moduleDataS:{},
},
mixins: [rz],
watch:{
nodeData:{
handler(n){
this.form.moduleId=n.id;
if( n.expressions){
n.expressions.forEach((item,index)=>{
this.addExpression();
this.form.name[index]=item.name;
this.unit[index]=item.unit;
this.expressions[index]=item.metric;
this.legends[index]=item.legend;
})
}
},
immediate: true,
deep: true,
},
moduleDataS:{
handler(n){
},
immediate: true,
deep: true,
},
'form.iconId':{
handler(n){
if(n){
this.selImage=this.iconArray.find(item=>item.id===n)
}
},
immediate: true,
deep: true,
}
},
data(){
return{
form:{
moduleId:'',
iconId:'',
name:[],
},
selImage:'',
file:'',
uploadFileList:[],
unitOptions: chartDataFormat.unitOptions(),
promqlKeys:[],
expressions: [],
promqlCount:0,
elementIds:[],
legends:[],
unit:[],
imgageLoading:false,
rules:{
moduleId:[
{ required: true, message: '请选择module', trigger: 'blur' },
],
iconId:[
{ required: true, message: '请选择icon', trigger: 'blur' },
],
},
iconArray:[],
metricList: [], // metric列表
metricCascaderList:[],//metric级联列表
metricAllData:new Map(),//存放所有的project-module-metric-labelValue避免重复加载
metricOptions: [],
}
},
mounted(){
this.getSuggestMetric();
this.queryMetrics();
// this.addExpression();
this.addNodeInit();
if( this.nodeData.expressions){
this.nodeData.expressions.forEach((item,index)=>{
this.$refs['promql-'+(index)][0].metricChange(this.expressions[index]);
})
}
},
methods:{
queryMetrics() {
this.metricOptions = [];
this.$get('prom/api/v1/label/__name__/values').then(response=>{
if(response.status == 'success'){
let metrics=response.data.sort();
let metricMap=new Map();
metrics.forEach((item)=>{
let key='';
if(/^[a-zA-Z]+?_[a-zA-Z]*/.test(item)){
key=item.split('_')[0];
}else if(/^_\w*/.test(item)){
key=' ';
}else{
key=item;
}
if(metricMap.get(key)){
let values=metricMap.get(key);
values.push({label:item,value:item});
}else{
let values=[{label:item,value:item}];
metricMap.set(key,values);
}
//this.metricStore.push({label:item,value:item,insertText:item})
});
for(let key of metricMap.keys()){
let option={
label:key,
value:key,
};
if(metricMap.get(key) && metricMap.get(key).length>1){
option.children=metricMap.get(key);
}
this.metricOptions.push(option);
}
}
})
},
addNodeInit(selImageId){
this.$get('/project/topo/icon').then(res=>{
this.imgageLoading=true;
this.iconArray=res.data.list;
this.iconArray.forEach((item,index)=>{
item.imageName=item.name;
delete item.name;
this.dealImg(`/project/topo/icon/${item.id}`).then((data)=>{
item.image=data;
if(index===this.iconArray.length-1){
setTimeout(()=>{
this.iconArray=[...this.iconArray];
this.imgageLoading=false;
if(selImageId || this.nodeData.iconId){
this.form.iconId=selImageId || this.nodeData.iconId;
}
},100)
}
})
});
})
},
dealImg(url) {
// 处理后端传过来的图片流乱码问题
if (url) {
return new Promise((resolve,reject)=>{
this.$axios
.get(url, {
responseType: "arraybuffer"
})
.then(res => {
return ("data:image/jpeg;base64," +btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), "")));
})
.then(data => {
resolve(data)
})
.catch(err => {
});
})
}
},
onSubmit(){
this.$refs['form'].validate((valid) => {
if (valid) {
let module=this.moduleDataS.module.find(item=>item.id===this.form.moduleId);
let img=this.iconArray.find(item=>item.id===this.form.iconId);
let model=Object.assign({...this.form},{...module},{...img},{id:this.form.moduleId,shape:'image',shapeProperties:{useImageSize:false}},);
model.label=model.name;
model.expressions=[];
this.promqlKeys.forEach((item,index)=>{
model.expressions.push({
"name": this.form.name[index],
"unit": this.unit[index],
"metric": this.expressions[index],
"legend": this.legends[index],
})
});
this.$emit('addModel',model);
}
});
},
expressionChange: function () {
},
// 获取metric列表
getSuggestMetric() {
//this.$get('/prom/api/v1/label/__name__/values').then(response => {
this.$get('/module?pageSize=-1').then(response => {
if (response.code === 200) {
this.metricList = response.data.list;
const cascaderMap = new Map();
this.metricList.forEach((item,index) => {
let projectName = item.project.name;
let moduleName = item.name;
const childOption = {
value: moduleName,
label: moduleName,
children:[],
};
if(cascaderMap.has(projectName)){
cascaderMap.get(projectName).push(childOption);
}else {
let childArr = [];
childArr.push(childOption);
cascaderMap.set(projectName,childArr);
}
//缓存全局数据
const moduleItem = {
name:moduleName,
metricMap:new Map()
};
if(this.metricAllData.has(projectName)){
let moduleGroup = this.metricAllData.get(projectName);
this.metricAllData.get(projectName).push(moduleItem);
}else {
let moduleList = [];
moduleList.push(moduleItem);
this.metricAllData.set(projectName,moduleList);
}
});
let metricCascaderArr = [];
cascaderMap.forEach(function(value,index){
const option = {
value: index+"_par",
label: index,
children:value,
};
metricCascaderArr.push(option);
});
this.metricCascaderList = metricCascaderArr;
}else {
this.metricList = [];
this.metricCascaderList = [];
}
})
},
getMetricOptions() {
return this.metricOptions;
},
addExpression() {
this.expressions.push('');
this.legends.push('');
this.form.name.push('');
this.unit.push(1);
this.promqlKeys.push(getUUID());
this.elementIds.push("");
this.promqlCount++;
},
removeExpression(index) {
if (this.promqlCount >= 1) {
this.expressions.splice(index, 1);
this.legends.splice(index, 1);
this.form.name.splice(index, 1);
this.unit.splice(index, 1);
this.promqlKeys.splice(index, 1);
this.elementIds.splice(index, 1);
this.promqlCount--;
this.$nextTick(() => {
this.expressions.forEach((ex, index) => {
if (ex) {
this.$refs[`promql-${index}`][0].metricChange(ex);
}
});
});
}
},
/*关闭弹框*/
esc(refresh) {
this.$emit("close", refresh);
},
clickOutside() {
this.esc(false);
},
del(){
this.$emit('del');
this.esc();
},
beforeAvatarUpload(file){
let this_=this
let isJPG = (file.type === 'image/jpeg' || file.type === 'image/png');
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error( this_.$t('project.topology.imgFormat'));
return false;
}
// if (!isLt2M) {
// this.$message.error( this_.$t('project.topology.imgSize'));
// return false;
// }
const isSize = new Promise(function(resolve, reject) {
let width = 100;
let height = 100;
let _URL = window.URL || window.webkitURL;
let img = new Image();
img.onload = function() {
let valid = img.width > width && img.height > height;
valid ? resolve() : reject();
}
img.src = _URL.createObjectURL(file);
}).then(() => {
if(isJPG){
this.file=file;
this.upload();
}
return file;
}, () => {
this.$message.error( this_.$t('project.topology.imgMeasure'));
return Promise.reject();
});
return false;
},
handleAvatarSuccess(file,res){
},
upload() {
let form = new FormData();
form.append("file",this.file);
let fileName=this.file.name;
form.append("name", fileName.substring(0, fileName.lastIndexOf(".")));
this.$post('/project/topo/icon',form,{'Content-Type': 'multipart/form-data'}).then(res => {
if(res.code == 200 ){
this.$message({duration: 2000, type: 'success', message: this.$t("tip.saveSuccess")});
this.addNodeInit(res.data.id);
}else{
this.$message.error(res.msg);
}
})
},
},
beforeDestroy(){
}
}
</script>
<style>
.icon-select>.el-input {
border-radius: 4px;
}
</style>
<style scoped>
.mc{
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: 11;
}
/deep/ .avatar-uploader{
display: inline-block;
color: #1989fa;
vertical-align: top;
}
/deep/.right-box-form .icon .el-select{
width: 60%;
}
.nz-icon-minus{
vertical-align: middle;
}
.sel-image{
height: 28px;
line-height: 28px;
width: 300px;
text-align: left;
}
.sel-image-name{
float: right;
display: inline-block;
height: 28px;
line-height: 28px;
color: #333333;
}
.nz-btn-edit-ok{
position: absolute;
bottom: 0;
right:0;
}
.nz-btn-edit-esc{
position: absolute;
bottom: 0;
left:0;
}
.icon /deep/ .el-input.el-input--prefix.el-input--suffix{
border: 1px solid #DCDFE6;
height: 28px;
width: calc(100% - 10px);
}
.icon /deep/ .el-input__inner{
display: none;
}
.icon /deep/ .el-input__prefix{
height: 28px;
line-height: 28px;
}
.element-item.expr /deep/ .el-form-item__content{
position: relative;
margin-left: 0 !important;
}
.element-item.expr /deep/ .el-form-item__content .el-row{
margin-bottom: 0;
}
.element-item.expr /deep/ .el-form-item__content .el-form-item__error{
left: 120px;
}
.expr-title{
width: 120px;
padding-right: 20px;
text-align: right;
color: #666;
font-size: 14px;
letter-spacing: 0;
line-height: 22px;
}
/deep/.promqlInput .expr-title{
padding-right: 0;
}
/* begin--搜索框*/
.endpoint-asset-search {
display: inline-block;
position: relative;
margin-top: -16px;
}
.endpoint-asset-search button {
height: 22px !important;
}
.endpoint-asset-search-dropdown {
position: absolute;
top: 25px;
background-color: #444;
border-radius: 4px;
width: 44px;
left: 0;
}
.endpoint-asset-search-dropdown-item {
text-align: center;
line-height: 22px;
height: 22px;
cursor: default;
color: white;
font-size: 12px;
}
.endpoint-asset-label-txt {
display: inline-block;
width: 19px;
text-align: center;
}
.endpoint-asset-search-dropdown-item:first-of-type {
border-radius: 4px 4px 0 0;
}
.endpoint-asset-search-dropdown-item:last-of-type {
border-radius: 0 0 4px 4px;
}
.endpoint-asset-search-dropdown-item:hover {
background-color: #222;
color: #ff9900;
}
.endpoint-asset-search-input {
display: inline-block;
width: 150px;
vertical-align: top;
}
/* end--搜索框*/
/* begin--table*/
.endpoint-sub-table {
padding-top: 30px;
height: 440px;
}
.line-100 {
margin-bottom: 3px;
}
.endpoint-sub-table-head {
line-height: 28px;
height: 30px;
}
.endpoint-sub-table-row, .endpoint-sub-table-row-disabled {
line-height: 28px;
height: 30px;
color: #656565;
}
.endpoint-sub-table-row:hover {
background-color: #dadada;
cursor: default;
}
.endpoint-sub-table-row-active {
background-color: #dadada;
}
.endpoint-sub-table-row-selected {
background-color: #656565;
color: white;
}
.endpoint-sub-table-col {
display: inline-block;
width: calc(50% - 15px);
padding-left: 10px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.endpoint-sub-table-paginate-all {
position: absolute;
left: 10px;
bottom: 17px;
color: #5a5a5a;
}
.endpoint-sub-table-body {
font-size: 15px;
position: relative;
overflow: auto;
height: calc(100% - 34px);
}
.endpoint-sub-table-body-dialog {
width: 100%;
height: 100%;
background-color: #e9ebec;
position: absolute;
opacity: 0.2;
}
.endpoints-clear-btn {
margin: 6px 0 0 7px;
}
/* end--table*/
.el-row {
margin-bottom: 20px;
line-height: 32px;
}
.el-row:last-child {
margin-bottom: 0;
}
.el-col {
border-radius: 4px;
}
.bg-purple {
background: white;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.common-float-left {
float: left;
display:inline-block;
}
.el-inner {
width: 200px;
border-top-width: 0px;
border-left-width: 0px;
border-right-width: 0px;
border-bottom-width: 10px;
border-color:red;
/*outline: medium;*/
}
.element-bottom-border {
padding-bottom: 5px;
border-bottom: 1px solid #dfe7f2;
margin-top: 15px;
}
/*metric样式--begin*/
.element-item {
padding: 20px;
border-bottom: 1px dashed #dfe7f2;
width: 700px;
}
/*metric样式--end*/
.label-center{
vertical-align: middle;
line-height: 34px;
}
.z-top {
z-index: 2900;
}
</style>

View File

@@ -1,186 +0,0 @@
<template>
<div style="background: #F9F9F9;height: 100%;padding-top: 15px">
<!--<div class="top-tools">-->
<!--&lt;!&ndash;时间选择&ndash;&gt;-->
<!--<template>-->
<!--<div class="top-tool-main-right">-->
<!--<div class="top-tool-search relative-position margin-r-20">-->
<!--<el-input ref="queryPanel" @clear="clearInput" id="queryPanel" @focus="focusInput" @blur="blurInput" v-model="filter.searchName" class="query-input-inactive" size="mini" clearable >-->
<!--<i slot="suffix" class="el-input__icon nz-icon nz-icon-search" @click="focusInput" style="float: right"></i>-->
<!--</el-input>-->
<!--</div>-->
<!--<pick-time :refresh-data-func="dateChange" v-model="searchTime" :use-chart-unit="false"></pick-time>-->
<!--</div>-->
<!--</template>-->
<!--</div>-->
<div class="project-facade">
<div class="facade-content">
<!--拓扑图盒子-->
<vis-network
:panel-id="item.id"
:chart-data="item"
:chart-index="0"
:allModuleInfo="allModuleInfo"
:projectInfo="projectInfo"
:alertData="alertData"
ref="visNetwork"
>
</vis-network>
</div>
</div>
</div>
</template>
<script>
import visNetwork from './visNetwork'
import draggable from 'vuedraggable'
import pickTime from "@/components/common/pickTime";
import bus from '@/libs/bus';
import timePicker from '@/components/common/timePicker'
export default {
name:"projectFacade",
components: {
visNetwork,
draggable,
'pick-time':pickTime,
'time-picker':timePicker,
},
props:{
obj:{}
},
watch:{
obj:{
// immediate: true,
deep: true,
handler(n){
this.getProjectData(n);
},
}
},
data(){
return {
item:{ // 拓扑图
id: -10,
panelId: 0,
title: this.$t("alert.config.chart.alertNumTrend"),
span: 8,
height: 800,
type: "topology",
prev: -11,
next: -1,
unit: 1,
buildIn: 1,
elements: [{
id: '',
expression: `nz_alert_nums{id="${3333}"}`,
type: ''
}]
},
panelData: [],
toAdd() {
this.$refs.panelBox.show(true);
this.panel = {
id: '',
name: ''
};
this.$refs.panelBox.setTitle(this.$t("dashboard.panel.createPanelTitle"));
},
showPanel: { //panel下拉列表
id: '',
name: ''
},
filter: { // 过滤条件
panelId: 0,
start_time: '',
end_time: '',
searchName: ''
},
searchTime: [
new Date(bus.computeTimezone(new Date().getTime())).setHours(new Date(bus.computeTimezone(new Date().getTime())).getHours() - 1),
new Date(bus.computeTimezone(new Date().getTime()))
],
projectInfo:{
title:'',
id:'',
remark:'',
alertStat:[1,2,3],
moduleMum:6,
loading:true,
},
alertData:{
loading:true,
title:'Alert : ',
sssObj:{
total:60,
stop:10,
pending:40,
other:10,
}
},
allModuleInfo:[]
}
},
mounted(){
if(this.obj.id){
this.getProjectData(this.obj);
};
this.$set(this.filter, "start_time", bus.timeFormate(new Date().getTime()-60*60*1000, "yyyy-MM-dd hh:mm:ss"));
this.$set(this.filter, "end_time", bus.timeFormate(new Date().getTime(), "yyyy-MM-dd hh:mm:ss"));
this.$set(this.filter, "panelId", this.projectId);
},
methods:{
getProjectData(n){
//获取projectInfo
this.projectInfo.loading=true;
this.$get('project/info', {id:n.id}).then(response => {
if (response.code === 200) {
this.projectInfo.loading=false;
this.projectInfo={...this.projectInfo,...response.data.basic,moduleMum:response.data.module.length};
}
});
},
focusInput() {
let classVal=document.getElementById('queryPanel').parentElement.getAttribute("class");
classVal=classVal.replace('query-input-inactive','query-input-active');
document.getElementById('queryPanel').parentElement.setAttribute("class",classVal );
// this.$refs.queryPanel.focus();
},
blurInput() {
if(!this.filter.searchName || this.filter.searchName == ''){
setTimeout(function(){
let classVal=document.getElementById('queryPanel').parentElement.getAttribute("class");
classVal=classVal.replace('query-input-active','query-input-inactive');
document.getElementById('queryPanel').parentElement.setAttribute("class",classVal );
},100)
}
},
clearInput() {
this.$refs.queryPanel.focus();
},
dateChange(val) {
this.filter.start_time = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss');
this.filter.end_time = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss');
this.filter.panelId = this.showPanel.id;
// this.getData(this.filter);
},
},
beforeDestroy(){
}
}
</script>
<style scoped>
.project-facade{
display: flex;
flex-direction: column;
height: 100%;
position: relative;
}
.facade-content{
flex: 1;
min-height: 800px;
width: calc(100% - 20px);
min-width: 1190px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -209,7 +209,7 @@
<i
:class="{'nz-icon':true, 'nz-icon-shuidi':true,'model-error':item.data.error&&!item.data.show,'model-error-active':item.data.error&&item.data.show}"
:ref="'modelTopId'+index"
@click="showNodeTools(index)"
@click="showNodeTools(index,item)"
>
<i class="nz-icon nz-icon-model"></i>
</i>
@@ -250,12 +250,13 @@
<div v-if="popDataShow.main">
<popDataMain :moduleId="moduleId" :projectId="projectInfo.id"></popDataMain>
</div>
<div v-if="popDataShow.total">
<total-chart :moduleId="moduleId" :projectId="projectInfo.id" :nodesArray="totalArray"></total-chart>
</div>
<div v-if="popDataShow.info">
<popDataInfo :moduleId="moduleId" :projectId="projectInfo.id"></popDataInfo>
</div>
<!--chart-->
<div v-if="popDataShow.total">
<topoTooltip :chartDataParent="chartData" :filterTime="filterTime" :isChart="true"/>
</div>
</div>
<!--endpoint-->
<transition name="right-box">
@@ -278,17 +279,18 @@
<!--preview-->
<el-dialog
:visible.sync="previewShow"
width=""
:width="'80%'"
:before-close="previewBeforeClose"
>
<div style="width: calc(50vw - 40px);height: 50vh">
<topologyL5
<div style="width: calc(80vw - 40px);height: 80vh">
<topologyPrev
v-if="previewShow"
:obj="obj"
:topoPrevDataS="topoPrevData"
:fromOverView="true"
:fromPrev="true"
:topologyIndexF="1">
</topologyL5>
</topologyPrev>
</div>
</el-dialog>
</div>
@@ -330,7 +332,7 @@
import topoTooltip from "./L5/topoTooltip";
import {getMetricTypeValue} from '../js/tools'
import bus from "../../../libs/bus";
import topologyL5 from './topologyL5'
import topologyPrev from './topologyPrev'
import axios from 'axios';
const canvasOptions={
@@ -456,7 +458,7 @@
endpointTable,
ExpressionInfo,
topoTooltip,
topologyL5,
topologyPrev,
},
computed:{},
props:{
@@ -484,9 +486,9 @@
watch:{
topologyIndexF:{
immediate:true,
deep:true,
handler(n){
this.topologyIndex=n
this.topologyIndex=n;
console.log(n,this.fromPrev);
}
},
obj:{
@@ -562,7 +564,6 @@
let endTime=this.filterTime[1];
let startTime=this.filterTime[0];
let step=bus.getStep(startTime,endTime);
console.log(data);
data.pens&&data.pens.forEach((item,index)=>{
this.chartGetData.push({id:item.id,res:[]});
let arr=item.data.expressArr.map((ele)=>{
@@ -631,7 +632,6 @@
let endTime=this.filterTime[1];
let startTime=this.filterTime[0];
let step=bus.getStep(startTime,endTime);
console.log(data);
data.pens&&data.pens.forEach((item,index)=>{
this.chartGetData.push({id:item.id,res:[]});
let arr=item.data.expressArr.map((ele)=>{
@@ -650,6 +650,30 @@
Promise.all(promiseArr).then((res)=>{
getTopology(this.topologyIndex).open(data);
getTopology(this.topologyIndex).lock(1);
if(this.fromOverView){
let flag=false;
let position={
x:this.$refs['topology-canvas'+this.topologyIndexF].offsetWidth,
y:this.$refs['topology-canvas'+this.topologyIndexF].offsetHeight,
}
getTopology(this.topologyIndex).centerView(50);
getTopology(this.topologyIndex).data.pens.forEach(item=>{
if(flag){
return
}
if(item.rect.x>position.x || item.rect.y>position.y){
getTopology(this.topologyIndex).fitView(50);
flag=true
}
});
// if(this.fromPrev){
// getTopology(this.topologyIndex).scaleTo(data.scale/2)
// }
// getTopology(this.topologyIndex).fitView();
this.getNodesArr();
}
});
})
});
@@ -697,7 +721,6 @@
}
clearInterval(timer);
data.pens.forEach((item=>{
console.log(item,this.iconArray.find(item1=>item1.id==item.imageId))
if(item.type===0&&item.data.imageId){
item.image=this.iconArray.find(item1=>item1.id==item.data.imageId).image
}
@@ -743,8 +766,6 @@
})
}
console.log(maxLevel)
if(maxLevel!==0){
if(pen.type===0){// 判断valueMapping 给相应的状态
let selLevel=pen.data.valueMapping.find(item=>item.level===maxLevel);
@@ -765,7 +786,6 @@
if(pen.type===0&&pen.animatePlay){// 判断valueMapping 给相应的状态
onChangeAnimate(pen,pen.animateType);
}else if(pen.type===1&&pen.animatePlay){// 判断valueMapping 给相应的状态
console.log(123123123);
onChangeAnimateLine(pen,pen.animateType);
}
}
@@ -925,7 +945,8 @@
},
//显示module的工具
showNodeTools(index){
showNodeTools(index,pen){
console.log(pen);
this.nodesArr.forEach((item,i)=>{
item.data.show=i===index;
})
@@ -1198,6 +1219,7 @@
}
break;
case 'resize':
console.log(this.topologyIndexF);
let domRect=document.getElementById('topology-canvas'+this.topologyIndexF).getBoundingClientRect();
this.toolShow.attrCord=[domRect.width-350,0];
this.toolShow.height=domRect.height;
@@ -1236,8 +1258,10 @@
case 'line':
case 'space':
case 'scale':
case 'translate':
this.moduleId='';
this.showNodeTools('');
this.popDataShowUpdate('',false)
break;
}
switch(event){
@@ -1397,7 +1421,6 @@
})
item.image=res2[index];
});
console.log(this.iconArray);
this.imgInit=true;
})
@@ -1594,6 +1617,11 @@
default:
return 1;
}
},
previewBeforeClose(done){
console.log(123123123123);
this.$emit('changeTopologyIndexF');
done();
}
},
destroyed(){
@@ -1859,7 +1887,7 @@
position: absolute;
top: 1px;
left: 2px;
transform: scale(0.9);
transform: scale(0.95);
z-index: 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,530 +0,0 @@
<template>
<div class="nz-chart-resize">
<div class="resize-shadow" ref="resizeShadow"></div>
<div class="resize-box resize-box-table" ref="resizeBox">
<div class="vis-network" :id="'chartTableDiv'+chartIndex" @mouseenter="caretShow=true" @mouseleave="caretShow=false">
<loading :ref="'localLoading'+chartIndex"></loading>
<div class="clearfix text-right edit-visnetwork" :class="{'dragTitle':dragTitleShow}" :id="'chartTitle'+chartIndex">
<el-popover
v-if="isError"
:close-delay=10
placement="top-start"
trigger="hover"
popper-class="chart-error-popper">
<div >{{errorContent}}</div>
<span slot="reference" style="" class="panel-info-corner panel-info-corner--error">
<i class="nz-icon nz-icon-warning fa"></i>
<span class="panel-info-corner-inner"></span>
</span>
</el-popover>
<span class="el-dropdown-link chart-title" @click.stop="dropdownMenuShow=!dropdownMenuShow">
<span></span>
<span>
<!--<span class="chart-title-text">{{chartData.title}}</span>-->
<!--<span class="chart-title-icon"><i class="nz-icon nz-icon-caret-bottom el-icon&#45;&#45;right" :class="{'visible':caretShow,'hidden':!caretShow}"></i></span>-->
</span>
<div style="height: 34px">
<button @click="editVisNetworkChange(true)" class="nz-btn nz-btn-size-normal nz-btn-style-light float-right pickTime" style="border-right: 1px solid rgba(162,162,162,0.50);margin-right: 12px" type="button" v-show="!editVisNetwork">
<i class="nz-icon nz-icon-edit" :title="$t('project.topology.edit')"></i>
</button>
<pick-time v-show="!editVisNetwork" :showTimePicker="false" class="float-right pickTime" :refresh-data-func="dateChange" v-model="searchTime" :use-chart-unit="false" ref="pickTime"></pick-time>
<!--<i class="nz-icon nz-icon-zoomin float-right"></i>-->
<!--<i class="nz-icon nz-icon-exit-full-screen float-right"></i>-->
</div>
</span>
</div>
<div class="vis-network-content">
<!--project主要信息-->
<div class="facade-top" v-if="!editVisNetwork">
<div class="facade-top-left" v-loading="projectInfo.loading">
<div class="facade-top-title">
Project information
</div>
<div>
<!--<span><span class="label">Id :</span>{{projectInfo.id}}</span>-->
<span><span class="label">Name :</span>{{projectInfo.name}}</span>
</div>
<div>
<span><span class="label">Description :</span>{{projectInfo.remark?projectInfo.remark:'--'}}</span>
</div>
<!--<div>-->
<!--<span>-->
<!--<span class="label">Alert state :</span>-->
<!--<div class="active-icon" style="background: #B7464A 100%;"></div>{{projectInfo.alertStat[0]}}-->
<!--<div class="active-icon" style="background: #E64E4E 100%;"></div>{{projectInfo.alertStat[1]}}-->
<!--<div class="active-icon" style="background: #F7B500 100%;"></div>{{projectInfo.alertStat[2]}}-->
<!--</span>-->
<!--</div>-->
<div>
<span><span class="label">Module Num :</span>{{projectInfo.moduleMum}}</span>
</div>
</div>
<div class="facade-top-right" v-loading="projectInfo.loading" style="padding: 20px 20px 0 20px;height: calc(100% - 20px);">
<div class="facade-top-title">
<span class="label" style="padding-left: 0;">Alert :</span>
{{total}}
</div>
<div class="facade-top-right-content">
<div>
<div class="content-P1-title">
{{returnSeverityLabel('P1')}}
</div>
<div>
{{projectInfo.alertStat[0] || 0}}
</div>
</div>
<div>
<div class="content-P2-title">
{{returnSeverityLabel('P2')}}
</div>
<div>
{{projectInfo.alertStat[1] || 0}}
</div>
</div>
<div style="margin-bottom: 20px;">
<div class="content-P3-title">
{{returnSeverityLabel('P3')}}
</div>
<div>
{{projectInfo.alertStat[2] || 0}}
</div>
</div>
</div>
</div>
</div>
<!--拓扑图-->
<topology
:editVisNetwork="editVisNetwork"
:nodesArray="nodesArray"
:edgesArray="edgesArray"
@setTopologyData="setTopologyData"
:isFullScreen="false"
ref="topology"
:allModuleInfo="allModuleInfo"
v-loading="topologyLoading"
@editVisNetworkChange="editVisNetworkChange"
@reload="reload"
@topologyLoad="topologyLoad"
>
</topology>
</div>
</div>
</div>
</div>
</template>
<script>
import loading from "@/components/common/loading";
import timePicker from '@/components/common/timePicker';
import topology from './topology'
import bus from '@/libs/bus';
// import other from './other'
export default {
name: 'visNetwork',
components: {
'loading': loading,
'time-picker':timePicker,
'topology':topology,
// other
},
props:{
chartIndex:{
type: Number,
default: 0,
},
chartData: {
type: Object
},
allModuleInfo:{},
projectInfo:{},
},
watch:{
// allModuleInfo:{
// immediate: true,
// deep: true,
// handler(n){
// this.getNetworkData(n);
// },
// },
projectInfo:{
immediate: true,
handler(n){
if(n.id){
this.getNetworkData(n);
this.total=this.projectInfo.alertStat[0]+this.projectInfo.alertStat[1]+this.projectInfo.alertStat[2];
if(!this.total){
this.total=0;
}
}
},
},
// alertData:{
// immediate: true,
// deep: true,
// handler(n){
// this.getNetworkData(n);
// },
// },
},
data () {
return {
firstLoad:false,
//其他
isError:false,
nodesArray:[],
nodesArrayOther:[],
edgesArray:[],
edgesArrayOther:[],
dragTitleShow:false,
dropdownMenuShow:false,
editVisNetwork:false,
topologyLoading:true,
total:1,
searchTime: bus.getTimezontDateRange(),
screenX:window.screen.width,
}
},
methods:{
// 设置拓扑图数据
setTopologyData(nodesArr,edgesArr){
this.nodesArray=nodesArr;
this.edgesArray=edgesArr;
},
getNetworkData(n){
this.topologyLoading=true;
this.editVisNetwork=false;
this.$get('/project/topo',{projectId:n.id}).then(res=>{
if(res.data.topo&&res.data.topo.nodes&&res.data.topo.nodes.length>0){
this.nodesArray=[];
this.edgesArray=[];
this.nodesArrayOther=this.formatNodesArr(res.data.topo.nodes);
this.edgesArrayOther=this.formatEdgesArr(res.data.topo.lines);
}else{
this.nodesArray=[];
this.edgesArray=[];
setTimeout(()=>{
this.topologyLoading=false;
if(this.$refs['topology']){
this.$refs['topology'].setData();
}
},100)
}
if(res.data.topo){
this.$refs['topology'].viewsCenter=res.data.topo.viewsCenter?res.data.topo.viewsCenter:{x:0,y:0};
this.$refs['topology'].zoom=res.data.topo.zoom?(res.data.topo.zoom*this.screenX/1920):1;
}
this.$refs['topology'].selNodeId='';
})
},
reload(){
this.topologyLoading=true;
this.editVisNetwork=false;
this.getNetworkData(this.projectInfo);
// this.$get('/project/topo',{projectId:this.projectInfo.id}).then(res=>{
// if(res.data.topo&&res.data.topo.nodes&&res.data.topo.nodes.length>0){
// this.nodesArray=[];
// this.edgesArray=[];
// this.nodesArrayOther=this.formatNodesArr(res.data.topo.nodes);
// this.edgesArrayOther=this.formatEdgesArr(res.data.topo.lines);
// }else{
// this.nodesArray=[];
// this.edgesArray=[];
// setTimeout(()=>{
// this.topologyLoading=false;
// this.$refs['topology'].setData();
// },500)
// }
// this.$refs['topology'].viewsCenter=res.data.topo.viewsCenter?res.data.topo.viewsCenter:{x:0,y:0};
// this.$refs['topology'].zoom=res.data.topo.zoom?(res.data.topo.zoom*this.screenX/1920):1;
// this.$refs['topology'].selNodeId='';
// })
},
formatNodesArr(arr){
let arr1=[];
if(!arr || arr.length===0){
this.topologyLoading=false;
return arr1
}
let promiseArr=[];
arr.forEach((item,index)=>{
item.shape='image';
item.id=item.moduleId;
if(this.allModuleInfo.module){
item.label=this.allModuleInfo.module.find(item1=>item1.id===item.id).name;
}
this.$get('/module/stat',{id:item.id}).then(res=>{
item.state=res.data;
// if(index===arr.length-1){
setTimeout(()=>{
this.nodesArray=[...this.nodesArrayOther];
this.edgesArray=[...this.edgesArrayOther];
setTimeout(()=>{
this.topologyLoading=false;
if(this.$refs['topology']){
this.$refs['topology'].setData();
}
},500)
})
// }
});
promiseArr.push( this.dealImg(`/project/topo/icon/${item.iconId}`))
});
Promise.all(promiseArr).then(res2=>{
res2.forEach((item,index)=>{
arr[index].image=item;
});
setTimeout(()=>{
this.nodesArray=[...this.nodesArrayOther];
this.edgesArray=[...this.edgesArrayOther];
this.topologyLoading=false;
if(this.$refs['topology']){
this.$refs['topology'].setData();
}
})
});
return arr
},
formatEdgesArr(arr){
let arr1=[];
if(!arr){return arr1}
arr.forEach((item)=>{
item.from=item.source;
item.to=item.target;
item.label='';
item.title='title';
item.expressions.forEach((item1,index)=>{
this.$get('/prom/api/v1/query?query=' + item1.metric).then(res=>{
// item.value=res.data.result[0].value;i
item1.value=res.data.result;
});
})
// item.dashes=(item.dashes?(new Array(100).fill(item.dashes[0])):item.dashes);
// if(index%2==0&&item.dashes){
// item.dataFlow='left';
// item.dashes[0]=0;
// item.dashes[1]=0;
// } else if(index%2==1&&item.dashes){
// item.dataFlow='right'
// }
});
return arr
},
dealImg(url) {
// 处理后端传过来的图片流乱码问题
if (url) {
return new Promise((resolve)=>{
this.$axios
.get(url, {
responseType: "arraybuffer"
})
.then(res => {
return ("data:image/jpeg;base64," +btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), "")));
})
.then(data => {
resolve(data)
})
.catch(err => {
});
})
}
},
// Severity Label
returnSeverityLabel(key){
return this.$CONSTANTS.alertMessage.severityData.find(s => {return s.value == key}).label
},
editVisNetworkChange(flag){
this.editVisNetwork=flag;
if(flag){
this.$refs.topology.popDataShowUpdate('',true);
this.$refs.topology.networkPopClose(true);
}
if(!flag){
// this.reload();
}
},
dateChange() {
if(this.editVisNetwork) {
return
}
this.reload();
},
topologyLoad(){
this.topologyLoading=true;
},
clearData(){
this.nodesArray=null;
this.nodesArrayOther=null;
},
},
mounted(){
this.firstLoad = false;
},
beforeDestroy(){
this.$refs['pickTime'].selectInterval();
this.clearData();
}
}
</script>
<style lang="scss">
@import './chart.scss';
</style>
<style scoped>
.pickTime{
margin-top: 10px;
}
.facade-top /deep/.active-icon{
margin-top: 0;
}
/*.nz-icon-edit{*/
/*margin-right: 12px;*/
/*margin-top: 10px;*/
/*}*/
.vis-network{
z-index: 0;
}
.vis-network .nz-icon-refresh{
margin-right: 12px;
margin-top: 10px;
color: #ee9d3f;
}
.table-container{
height: calc(100% - 30px);
}
.nz-icon{
cursor: pointer;
}
.resize-box .vis-network .text-right{
text-align: right;
}
.resize-box .vis-network .chartTitle .chart-title{
justify-content: space-between;
align-items: stretch;
}
.vis-network-content{
height: 100%;
}
.facade-top{
min-height: 138px;
display: flex;
margin: 12px 0;
height: calc(16% - 40px);
font-size: 12px;
position: absolute;
top: 5px;
left: 15px;
z-index: 10;
}
.facade-top > div{
height: calc(100% - 40px);
width: 18%;
min-width: 315px;
background: #FFFFFF;
margin-right: 9px;
padding: 20px;
border: 1px solid #FFFFFF;
box-shadow: 1px 2px 4px 0 rgba(0,0,0,0.12), -1px 1px 9px -1px rgba(205,205,205,0.77);
}
.facade-top-title{
font-size: 16px;
color: #333333;
font-weight: bold;
padding: 5px 0;
}
.facade-top-left{
display: flex;
flex-direction: column;
justify-content: space-around;
}
.special.label{
margin-left: 30px;
}
.facade-top .facade-top-right{
width: auto;
min-width: 100px;
}
.facade-top-right-content{
display: flex;
justify-content: space-around;
justify-items: center;
flex-direction: column;
height: calc(100% - 30px);
align-items:flex-start;
}
.facade-top-right-content > div{
min-width: 84px;
height: 22px;
display: flex;
justify-content: space-between;
color: #fff;
text-align: center;
margin-bottom: 5px;
line-height: 22px;
}
.facade-top-right-content > div > div:last-child{
text-align: center;
border-radius: 0 4px 4px 0;
flex: 1;
height: calc(100% - 2px);
padding: 0 8px;
min-width: 40px;
}
.content-P1-title{
background: #F2866E;
border-radius: 4px 0 0 4px;
width: 40px;
height: 100%;
}
.content-P1-title + div{
border: 1px solid #F4907A;
font-size: 12px;
color: #F4907A;
}
.content-P2-title{
background: #F89984;
border-radius: 4px 0 0 4px;
width: 40px;
height: 100%;
}
.content-P2-title + div{
border: 1px solid #F9A28F;
font-size: 12px;
color: #F9A28F;
}
.content-P3-title{
background: #F7BA78;
border-radius: 4px 0 0 4px;
width: 40px;
height: 100%;
}
.content-P3-title + div{
border: 1px solid #F7BA78;
font-size: 12px;
color: #F7BA78;
}
.right-content-P1{
border: 1px solid ;
}
.align--center{
text-align: center;
}
.label{
padding: 0 15px 0 0;
}
.edit-visnetwork{
position: absolute;
top: 5px;
right: 5px;
z-index: 1;
}
</style>

View File

@@ -182,7 +182,7 @@
<template v-else-if="pageType == 'project'">
<!--<panel-tab from="project" :obj="currentProject" targetTab.sync="panel"></panel-tab>-->
<!--<facade :obj="currentProject" targetTab.sync="panel" ref="facade" v-if="reloadFacade"/>-->
<topologyL5 :obj="currentProject" targetTab.sync="panel" ref="facade" v-if="reloadFacade"/>
<topologyL5 :obj="currentProject" targetTab.sync="panel" ref="facade" :topologyIndexF="topologyIndexF" v-if="reloadFacade" @changeTopologyIndexF="changeTopologyIndexF"/>
</template>
<transition name="el-zoom-in-bottom">
@@ -218,7 +218,6 @@
import loading from "../../common/loading";
import panelTab from '../../common/bottomBox/tabs/panelTab'
import bus from '../../../libs/bus'
import facade from '@/components/common/project/projectFacade'
import topologyL5 from '@/components/common/project/topologyL5'
import deleteButton from "../../common/deleteButton";
@@ -228,7 +227,6 @@
'export-excel':exportXLSX,
'loading':loading,
'panel-tab':panelTab,
facade,
topologyL5,
'delete-button':deleteButton,
},
@@ -392,6 +390,7 @@
},
scrollbarWrap: null,
delFlag:false,
topologyIndexF:0,
}
},
methods:{
@@ -778,6 +777,10 @@
}
return '';
},
changeTopologyIndexF(){
console.log(132123132123123);
this.topologyIndexF=0;
},
},
created(){
this.currentProject=this.$store.state.currentProject;