feat:新增功能
1.指标预览->预览图表功能 2.指标预览->单图展示的创建看板和选择已有看板 3.指标预览->单图展示和多图展示的切换及对应曲线展示 说明:多图展示的创建看板和选择已有看板未实现,国际化未实现,样式需要进一步调整,图表展示中tip信息显示位置需要调整 fix:修改BUG 1.dashboard无需分页pageSize为-1 2.panel图表line类型曲线设置为平滑 3.panel图表y轴数据格式化
This commit is contained in:
@@ -166,6 +166,8 @@ export default {
|
||||
const seriesItem = {
|
||||
theData: {
|
||||
name: '',
|
||||
symbol:'none', //去掉点
|
||||
smooth:true, //曲线变平滑
|
||||
data: [],
|
||||
type:chartInfo.type,
|
||||
//visible: true,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="line-chart-block" >
|
||||
|
||||
<div class="edit">
|
||||
<div class="list-icon" >
|
||||
<div class="list-icon" v-if="firstShow">
|
||||
<span @click="refreshChart" :title="$t('dashboard.refresh')" class="set-icon" v-if="showSetting">
|
||||
<i class="el-icon-refresh-right"></i>
|
||||
</span>
|
||||
@@ -108,8 +108,9 @@ export default {
|
||||
},
|
||||
stableFilter: {}, // 保存数据使用,初始化起止时间,单图or多图等
|
||||
legend:[],
|
||||
// firstShow: false, // 默认不显示操作按钮,
|
||||
firstShow: false, // 默认不显示操作按钮,
|
||||
searchTime:[new Date().setHours(new Date().getHours()-1),new Date()],
|
||||
oldSearchTime:[],
|
||||
pickerOptions: {
|
||||
shortcuts: [
|
||||
{
|
||||
@@ -207,7 +208,7 @@ export default {
|
||||
methods: {
|
||||
// chartSite用于区分是全屏显示还是局部显示
|
||||
initChart(chartInfo, dataArg, ele, chartSite,legend) {
|
||||
//this.firstShow = true; // 展示操作按键
|
||||
this.firstShow = true; // 展示操作按键
|
||||
const self = this;
|
||||
this.chartType = ''; // 图表类型
|
||||
if ( chartInfo.type === 4) {//line,bar
|
||||
@@ -227,6 +228,8 @@ export default {
|
||||
textStyle: {
|
||||
//display: 'inline-block',//无此属性
|
||||
width: '300px',
|
||||
fontStyle:'normal',
|
||||
fontWeight:'normal'
|
||||
}
|
||||
},
|
||||
color: ['#7bbfea', '#b3424a', '#f05b72', '#596032', '#bd6758',
|
||||
@@ -344,6 +347,35 @@ export default {
|
||||
splitLine:{
|
||||
show:true
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: function(num,index) {
|
||||
if (num >= 1000) {
|
||||
const kbNum = num / 1000;
|
||||
if (kbNum >= 1000) {
|
||||
const mbNum = kbNum / 1000;
|
||||
if (mbNum > 1000) {
|
||||
const gbNum = mbNum / 1000;
|
||||
/*
|
||||
if (gbNum > 1000) {
|
||||
const tbNum = gbNum / 1000;
|
||||
if (tbNum > 1000) {
|
||||
const pbNum = tbNum / 1000;
|
||||
return `${pbNum.toFixed(2)}PB`;
|
||||
}
|
||||
return `${tbNum.toFixed(2)}TB`;
|
||||
}*/
|
||||
return `${parseFloat(gbNum.toFixed(2))}B`;
|
||||
}
|
||||
return `${parseFloat(mbNum.toFixed(2))}M`;
|
||||
}
|
||||
return `${parseFloat(kbNum.toFixed(2))}K`;
|
||||
}
|
||||
return parseFloat(num.toFixed(2));
|
||||
//alert(1);
|
||||
//return value;
|
||||
//return this.getNumStr(value);
|
||||
},
|
||||
},
|
||||
//boundaryGap:[0,0.2]
|
||||
},
|
||||
useUTC: false,//使用本地时间
|
||||
@@ -406,6 +438,7 @@ export default {
|
||||
return obj;
|
||||
});
|
||||
*/
|
||||
this.echartStore.clear();
|
||||
this.echartStore.setOption(option);//创建图表
|
||||
this.echartStore.hideLoading();
|
||||
this.echartStore.resize({height:chartInfo.height});//,width:`${ele.clientWidth-100}`}
|
||||
@@ -473,6 +506,7 @@ export default {
|
||||
this.seriesItem = seriesItem;
|
||||
this.searchTime[0] = filter.start_time;
|
||||
this.searchTime[1] = filter.end_time;
|
||||
this.oldSearchTime = this.searchTime;
|
||||
this.initChart(chartItem, seriesItem, this.$refs.lineChartArea, 'local',legend);
|
||||
/*
|
||||
if (chartItem.type === 'line' || chartItem.type === 'bar' || chartItem.type === 4) {
|
||||
@@ -505,12 +539,20 @@ export default {
|
||||
});
|
||||
*/
|
||||
},
|
||||
changeDate(st){
|
||||
this.oldSearchTime=st;
|
||||
this.searchTime = st;
|
||||
this.filter.start_time = st[0];
|
||||
this.filter.end_time = st[1];
|
||||
},
|
||||
// 全屏查看
|
||||
showAllScreen() {
|
||||
// 初始化同步时间
|
||||
this.filter.start_time = this.stableFilter.start_time;
|
||||
this.filter.end_time = this.stableFilter.end_time;
|
||||
this.searchTime = this.oldSearchTime;
|
||||
this.screenModal = true;
|
||||
this.dateChange();
|
||||
},
|
||||
dateChange(time) {
|
||||
this.filter.start_time = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss');
|
||||
@@ -528,7 +570,6 @@ export default {
|
||||
}
|
||||
let axiosArr = [];
|
||||
this.$nextTick(() => {
|
||||
if (type === 'list') { // 普通模式,主控台使用
|
||||
let startTime = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss');
|
||||
let endTime = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss');
|
||||
if(!startTime || !endTime){//如果时间为空,则默认取最近1小时
|
||||
@@ -539,38 +580,18 @@ export default {
|
||||
this.searchTime[1] = endTime;
|
||||
}
|
||||
let step = bus.getStep(startTime,endTime);
|
||||
if (type === 'list') { // 普通模式,主控台使用
|
||||
axiosArr = this.data.elements.map((ele) => {
|
||||
const filterItem = ele;
|
||||
return this.$get('/prom/api/v1/query_range?query='+filterItem.expression+"&start="+startTime+"&end="+endTime+'&step='+step);
|
||||
});
|
||||
} else if (type === 'dashboard') { // 概览模式,指标概览中使用
|
||||
/*
|
||||
// 概览模式,需要区分单独一个和多个
|
||||
if (this.stableFilter.chartCount === 'multiple') {
|
||||
// 所有tag标签
|
||||
const tagAllArr = this.proTags(this.data.tags);
|
||||
// 根据title格式化的标签
|
||||
const titles = this.data.title.split(',');
|
||||
const titleArr = titles.map(item => item.trim());
|
||||
// 获取所需标签
|
||||
const tagArr = this.getCompilation(tagAllArr, titleArr);
|
||||
axiosArr = [getQueryChart({
|
||||
product_id: this.productId,
|
||||
metric: this.data.metric,
|
||||
tags: tagArr.toString(),
|
||||
start: this.filter.start_time,
|
||||
end: this.filter.end_time,
|
||||
})];
|
||||
axiosArr = [this.$get('/prom/api/v1/query_range?query='+this.data.title+"&start="+startTime+"&end="+endTime+'&step='+step)];
|
||||
} else {
|
||||
axiosArr = [getQueryChart({
|
||||
product_id: this.productId,
|
||||
metric: this.data.metric,
|
||||
tags: this.data.tags,
|
||||
start: this.filter.start_time,
|
||||
end: this.filter.end_time,
|
||||
})];
|
||||
axiosArr = [this.$get('/prom/api/v1/query_range?query='+this.data.elements[0].expression+"&start="+startTime+"&end="+endTime+'&step='+step)];
|
||||
}
|
||||
*/
|
||||
}
|
||||
// 一个图表
|
||||
axios.all(axiosArr).then((res) => {
|
||||
@@ -591,6 +612,8 @@ export default {
|
||||
const seriesItem = {
|
||||
theData: {
|
||||
name: '',
|
||||
symbol:'none', //去掉点
|
||||
smooth:true, //曲线变平滑
|
||||
data: [],
|
||||
type:this.data.type,
|
||||
//visible: true,
|
||||
@@ -669,6 +692,31 @@ export default {
|
||||
this.echartStore.showLoading();
|
||||
}
|
||||
},
|
||||
// 获取格式
|
||||
getNumStr(num) {
|
||||
if (num >= 1000) {
|
||||
const kbNum = num / 1000;
|
||||
if (kbNum >= 1000) {
|
||||
const mbNum = kbNum / 1000;
|
||||
if (mbNum > 1000) {
|
||||
const gbNum = mbNum / 1000;
|
||||
/*
|
||||
if (gbNum > 1000) {
|
||||
const tbNum = gbNum / 1000;
|
||||
if (tbNum > 1000) {
|
||||
const pbNum = tbNum / 1000;
|
||||
return `${pbNum.toFixed(2)}PB`;
|
||||
}
|
||||
return `${tbNum.toFixed(2)}TB`;
|
||||
}*/
|
||||
return `${gbNum.toFixed(2)}B`;
|
||||
}
|
||||
return `${mbNum.toFixed(2)}M`;
|
||||
}
|
||||
return `${kbNum.toFixed(2)}K`;
|
||||
}
|
||||
return num.toFixed(2);
|
||||
},
|
||||
/*
|
||||
handleClose(done) {
|
||||
/*
|
||||
@@ -816,30 +864,7 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 获取格式
|
||||
getNumStr(num) {
|
||||
if (num >= 1000) {
|
||||
const kbNum = num / 1000;
|
||||
if (kbNum >= 1000) {
|
||||
const mbNum = kbNum / 1000;
|
||||
if (mbNum > 1000) {
|
||||
const gbNum = mbNum / 1000;
|
||||
if (gbNum > 1000) {
|
||||
const tbNum = gbNum / 1000;
|
||||
if (tbNum > 1000) {
|
||||
const pbNum = tbNum / 1000;
|
||||
return `${pbNum.toFixed(2)}PB`;
|
||||
}
|
||||
return `${tbNum.toFixed(2)}TB`;
|
||||
}
|
||||
return `${gbNum.toFixed(2)}GB`;
|
||||
}
|
||||
return `${mbNum.toFixed(2)}MB`;
|
||||
}
|
||||
return `${kbNum.toFixed(2)}KB`;
|
||||
}
|
||||
return num.toFixed(2);
|
||||
},
|
||||
|
||||
// 获取tag数组
|
||||
proTags(data) {
|
||||
const dou = data.indexOf(',');
|
||||
|
||||
@@ -25,6 +25,7 @@ const cn = {
|
||||
},
|
||||
//面板-侧滑框
|
||||
createPanelTitle: "创建面板",
|
||||
selectPanelTitle:"选择面板",
|
||||
createPanelTitleSec:"创建新面板",
|
||||
editPanelTitle: "编辑面板",
|
||||
panelForm:{
|
||||
|
||||
@@ -34,6 +34,7 @@ const en = {
|
||||
},
|
||||
//面板-侧滑框
|
||||
createPanelTitle: "Create Panel",
|
||||
selectPanelTitle:"Select Panel",
|
||||
createPanelTitleSec:"Create New Panel",
|
||||
editPanelTitle: "Panel",
|
||||
panelForm:{
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
<template key="metricPrePanelBox">
|
||||
<transition name="right-box">
|
||||
<div class="right-box right-box-panel z-top" v-if="rightBox.show">
|
||||
<!-- begin--顶部按钮-->
|
||||
<div class="right-box-top-btns">
|
||||
<button type="button" @click="save" class="nz-btn nz-btn-size-normal nz-btn-style-normal">
|
||||
<span class="top-tool-btn-txt">{{$t('overall.save')}}</span>
|
||||
</button>
|
||||
<button type="button" @click="esc" class="nz-btn nz-btn-size-normal nz-btn-style-light nz-btn-style-square">
|
||||
<span class="top-tool-btn-txt"><i class="el-icon-close"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- end--顶部按钮-->
|
||||
|
||||
<!-- begin--标题-->
|
||||
<div class="right-box-title">{{rightBox.title}}</div>
|
||||
<!-- end--标题-->
|
||||
|
||||
<!-- begin--表单-->
|
||||
<div class="right-box-form">
|
||||
<el-form :model="chartSaveInfo" ref="chartSaveInfo">
|
||||
<el-form-item label="Chart Name" prop="title" :rules="{ required: true, type: 'string', message: '请输入图表名称', trigger: 'change' }">
|
||||
<el-input size="small" maxlength="64" show-word-limit v-model="chartSaveInfo.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isCreatePanel" label="Panel Name" prop="name" :rules="{ required: true, type: 'string', message: '请输入看板名称', trigger: 'change' }">
|
||||
<el-input size="small" maxlength="64" show-word-limit v-model="chartSaveInfo.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-else label="Select Panel" prop="panelId" :rules="{ required: true, type: 'number', message: '请选择看板', trigger: 'change' }">
|
||||
<el-select ref="panelSelect" width="100%" v-model="chartSaveInfo.panelId"
|
||||
popper-class="" placeholder="" size="small"
|
||||
@change="panelSelect"
|
||||
filterable>
|
||||
<el-option v-for="(item, index) in panelList"
|
||||
:key="index"
|
||||
:value="item.id"
|
||||
:label="item.name">{{item.name}}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- end--表单-->
|
||||
|
||||
<!-- begin--底部按钮-->
|
||||
<!--
|
||||
<div class="right-box-bottom-btns">
|
||||
<div @click="esc()" :class="{'right-box-bottom-btn-50': true}" class="right-box-bottom-btn right-box-bottom-btn-cancel">{{$t('overall.cancel')}}</div><div @click="save()" class="right-box-bottom-btn right-box-bottom-btn-50">{{panel.id == '' ? $t('overall.create') : $t('overall.save')}}</div>
|
||||
</div>
|
||||
-->
|
||||
<!-- end--底部按钮-->
|
||||
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<script>
|
||||
import bus from '../../../libs/bus';
|
||||
export default {
|
||||
name: "metricPrePanelBox",
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
elementTarget:Object,
|
||||
seriesData:Object,
|
||||
chartCount:Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rightBox: { //面板弹出框相关
|
||||
show: false,
|
||||
title: this.$t('dashboard.panel.createPanelTitle')
|
||||
},
|
||||
isCreatePanel: false,
|
||||
// 创建看板信息
|
||||
chartSaveInfo: {
|
||||
title: '', // 图表名称
|
||||
name: '', // panel名称
|
||||
panelId: '', // 选择以后panelId
|
||||
},
|
||||
panelList: [],
|
||||
panelItem: {}, // 保存看板信息
|
||||
panelId: 0,
|
||||
createChartList: [], // 创建多个图表的图表信息
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show(show) {
|
||||
this.rightBox.show = show;
|
||||
},
|
||||
setTitle(title) {
|
||||
this.rightBox.title = title;
|
||||
},
|
||||
setIsCreatePanel(isCreate) {
|
||||
this.isCreatePanel = isCreate;
|
||||
},
|
||||
setChartTitle(title){
|
||||
this.chartSaveInfo.title = title;
|
||||
},
|
||||
// 选择看板
|
||||
panelSelect(id) {
|
||||
if (id) {
|
||||
const panel = this.panelList.find(p => p.id === id);
|
||||
if (panel) {
|
||||
this.panelItem = panel;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 生成图表的时候,使用该函数,汇总创建图表参数
|
||||
getOptions() {
|
||||
//this.$refs.chartInfo.validate((valid) => {
|
||||
const params = {
|
||||
//panelId: this.panelId,
|
||||
// title: this.chartSaveInfo.title,
|
||||
type: this.chartInfo.type,
|
||||
span: this.chartInfo.span,
|
||||
height: this.chartInfo.height,
|
||||
};
|
||||
// 多图模式
|
||||
if (this.chartCount === 'multiple') {
|
||||
this.createChartList = [];
|
||||
//alert(JSON.stringify(this.seriesData));
|
||||
this.seriesData.forEach((queryItem) => {
|
||||
const soleParam = Object.assign({}, params);
|
||||
const elements = [];
|
||||
|
||||
let tagStr = ''; // tag字符串
|
||||
let host = `${queryItem.metric}, `; // 名称
|
||||
const tagsArr = Object.keys(queryItem.tags);
|
||||
// 根据图表展示时获取的tag进行组装名称以及tag字符串
|
||||
tagsArr.forEach((tag) => {
|
||||
if (tag !== 'uuid') {
|
||||
host += `${tag}=${queryItem.tags[tag]}, `;
|
||||
if (tagStr) {
|
||||
tagStr += `,${tag}=${queryItem.tags[tag]}`;
|
||||
} else {
|
||||
tagStr += `${tag}=${queryItem.tags[tag]}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 图表中每条线的名字,去掉最后的逗号与空格
|
||||
host = host.substring(0, host.length - 2);
|
||||
soleParam.title = host;
|
||||
|
||||
elements.push({
|
||||
expression: this.elementTarget.metric,
|
||||
type: this.elementTarget.type,
|
||||
});
|
||||
soleParam.elements = elements;
|
||||
//if (valid) {
|
||||
this.addMultipleChart(soleParam);
|
||||
//}
|
||||
});
|
||||
} else if (this.chartCount === 'single') {
|
||||
params.title = this.chartSaveInfo.title;
|
||||
const elements = [];
|
||||
if(this.elementTarget.type==='normal'){
|
||||
const metricStr = bus.tagsToString(this.elementTarget.metric,this.elementTarget.selectedTagList);
|
||||
elements.push({
|
||||
expression: metricStr,
|
||||
type: this.elementTarget.type,
|
||||
});
|
||||
}else if(this.elementTarget.type==='expert'){
|
||||
elements.push({
|
||||
expression: this.elementTarget.expression,
|
||||
type: this.elementTarget.type,
|
||||
});
|
||||
}
|
||||
params.elements = elements;
|
||||
//if (valid) {
|
||||
this.addCharts(params);
|
||||
//}
|
||||
}
|
||||
//});
|
||||
},
|
||||
// 新建单个图表single
|
||||
addCharts(params) {
|
||||
this.$post('panel/'+this.panelId+'/charts', params).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.elementTarget = {};
|
||||
//this.saveDisabled = true; // 创建成功后,不能再次创建??
|
||||
this.$emit('reload');
|
||||
this.esc();
|
||||
this.$message({duration: 1000, type: 'success', message: this.$t("tip.saveSuccess")});
|
||||
/*
|
||||
this.$confirm(this.$t("tip.confirmDelete"), {
|
||||
confirmButtonText: this.$t("tip.yes"),
|
||||
cancelButtonText: this.$t("tip.no"),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
|
||||
});
|
||||
*/
|
||||
/*
|
||||
this.$Modal.confirm({
|
||||
title: '创建成功',
|
||||
content: `是否前去看板:${this.panelItem.name},查看创建的图表`,
|
||||
onOk: () => {
|
||||
this.$router.push({
|
||||
path: `/console/panel/detail/${this.panelId}/${this.productId}`,
|
||||
query: {
|
||||
product: this.$route.query.product,
|
||||
panel: this.panelItem.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
onCancel: () => {
|
||||
this.cancel();
|
||||
},
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
this.$message.error(response.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
save: function() {
|
||||
this.$refs.chartSaveInfo.validate((flag) => {
|
||||
if (flag) { // 再判断弹出窗口内内容是否正确
|
||||
if (this.isCreatePanel) { // 创建看板
|
||||
this.panelItem.name = this.chartSaveInfo.name;
|
||||
this.$post('panel', this.panelItem).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.panelId = response.data.panel.id;
|
||||
this.panelItem = response.data.panel;
|
||||
this.getOptions();
|
||||
//this.esc();
|
||||
//this.$message({duration: 1000, type: 'success', message: this.$t("tip.saveSuccess")});
|
||||
//this.$emit("reload");----询问是否去查看
|
||||
} else {
|
||||
this.$message.error(response.msg);
|
||||
}
|
||||
});
|
||||
} else { // 选择看板
|
||||
this.panelId = this.chartSaveInfo.panelId;
|
||||
this.getOptions();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
esc: function() {
|
||||
this.rightBox.show = false;
|
||||
// 取消创建modal
|
||||
this.panelList = [];
|
||||
this.chartSaveInfo.panelId = ''; // 选择panel
|
||||
this.chartSaveInfo.name = ''; // panel名称创建
|
||||
if (this.$refs.chartSaveInfo) {
|
||||
this.$refs.chartSaveInfo.resetFields();
|
||||
}
|
||||
if (this.$refs.panelSelect) {
|
||||
this.$refs.panelSelect.reset();
|
||||
}
|
||||
},
|
||||
getTableData: function() {
|
||||
this.$get('panel?pageNo=1&pageSize=-1').then(response => {
|
||||
if (response.code === 200) {
|
||||
this.panelList = response.data.list;
|
||||
}else {
|
||||
this.panelList = [];
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted: function() {
|
||||
|
||||
},
|
||||
watch: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.z-top{
|
||||
z-index: 50;
|
||||
}
|
||||
</style>
|
||||
@@ -354,6 +354,7 @@
|
||||
}
|
||||
},
|
||||
// 格式化tag为字符串表达式
|
||||
/*
|
||||
tagsToString(metric,arr) {
|
||||
let str = metric;
|
||||
let sepStr = '';
|
||||
@@ -385,6 +386,7 @@
|
||||
}
|
||||
return str;
|
||||
},
|
||||
*/
|
||||
// 新建图表
|
||||
addCharts(params) {
|
||||
this.$post('panel/'+this.panelId+'/charts', params).then(response => {
|
||||
@@ -429,7 +431,7 @@
|
||||
const elements = [];
|
||||
this.elementTarget.forEach((elem,index) => {
|
||||
if(elem.type==='normal'){
|
||||
const metricStr = this.tagsToString(elem.metric,elem.selectedTagList);
|
||||
const metricStr = bus.tagsToString(elem.metric,elem.selectedTagList);
|
||||
elements.push({
|
||||
//id:index+1,
|
||||
//metric: elem.metric,//指标名称
|
||||
@@ -469,7 +471,7 @@
|
||||
|
||||
// 获取metric列表
|
||||
getSuggestMetric() {
|
||||
this.$get('metric', {pageNo: 1, pageSize: 9999}).then(response => {
|
||||
this.$get('metric', {pageNo: 1, pageSize: -1}).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.metricList = response.data.list;
|
||||
}else {
|
||||
|
||||
@@ -57,6 +57,12 @@
|
||||
.star-red{
|
||||
color:#ff1818;
|
||||
}
|
||||
.full-width{
|
||||
width:100%;
|
||||
}
|
||||
.mt1{
|
||||
margin-top:1px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<el-form :model="elementInfo" ref="elementInfo" >
|
||||
@@ -84,9 +90,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="tableShow == 2">
|
||||
<el-col span="22">
|
||||
<el-col span="22" class="mt1">
|
||||
<el-form-item prop="expression" :rules="{ required: true, message:$t('validate.required'), trigger: 'blur' }"><!--expression和metric的验证只能有一个,不能同时存在??:rules="{ required: true, type: 'string', message: '', trigger: 'change' }"-->
|
||||
<el-input size="mini" ref="metricExpression" type="textarea" maxlength="1024" show-word-limit v-model="elementInfo.expression" :placeholder="this.$t('dashboard.metric.expertTip')" ></el-input>
|
||||
<el-input size="mini" class="full-width" ref="metricExpression" type="textarea" maxlength="1024" show-word-limit v-model="elementInfo.expression" :placeholder="this.$t('dashboard.metric.expertTip')" ></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col span="2">
|
||||
@@ -96,7 +102,7 @@
|
||||
<el-row v-if="tableShow == 1">
|
||||
<el-col span="22" >
|
||||
<el-form-item :label-width="80" prop="metric" :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }"><!--:rules="{ required: true, type: 'string', message: '', trigger: 'change' }"-->
|
||||
<el-select ref="metricSelect" filterable placeholder="" popper-class="" size="small" v-model="elementInfo.metric" @change="selectMetric">
|
||||
<el-select ref="metricSelect" class="full-width" filterable placeholder="" popper-class="" size="small" v-model="elementInfo.metric" @change="selectMetric">
|
||||
<el-option v-for="(item, index) in metricShowList.arr" :key="item.metric + index"
|
||||
:value="item.metric">{{item.metric}}</el-option>
|
||||
</el-select>
|
||||
@@ -243,7 +249,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 选择metric
|
||||
selectMetric() {
|
||||
if (this.elementInfo.metric) {//选择了metric,则设置tagList,否则设置为空
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
<style scoped>
|
||||
.without-bottom {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.ivu-select-dropdown {
|
||||
max-height: 100px;
|
||||
}
|
||||
.error-info-text {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
padding-top: 6px;
|
||||
color: #ed3f14;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
}
|
||||
.error-text {
|
||||
color: #ed3f14;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.nz-btn-style-higher{
|
||||
line-height: 22px;
|
||||
}
|
||||
.li-list-part {
|
||||
width: 90%;
|
||||
height: 130px;
|
||||
border: 1px solid #cfcfcf;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.li-list-part-label-val-list {
|
||||
width: 100%;
|
||||
height: 165px;
|
||||
border: 1px solid #cfcfcf;
|
||||
overflow-y: auto;
|
||||
margin-top: -10px;/*21*/
|
||||
border: 0px;
|
||||
}
|
||||
.no-list-style{
|
||||
list-style: none;
|
||||
}
|
||||
.li-cursor{
|
||||
cursor: pointer;
|
||||
}
|
||||
.activeColor {
|
||||
background-color: #409EFF;
|
||||
}
|
||||
.metric-title-label{
|
||||
margin-bottom:8px;
|
||||
}
|
||||
.metric-title-position{
|
||||
margin-bottom:-5px;
|
||||
}
|
||||
.metric-title-row-position{
|
||||
margin-top:-10px;
|
||||
}
|
||||
.star-red{
|
||||
color:#ff1818;
|
||||
}
|
||||
.full-width{
|
||||
width:100%;
|
||||
}
|
||||
.mt1{
|
||||
margin-top:1px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<el-form :model="elementInfo" ref="elementInfo" >
|
||||
<el-row >
|
||||
<el-col span="16">
|
||||
<span class="star-red">*</span> {{$t('dashboard.panel.chartForm.metric')}}
|
||||
</el-col>
|
||||
<el-col span="8">
|
||||
<div class="nz-btn-group float-left" v-show="tableShow == 2">
|
||||
<button @click="clickTabelShow(1,'normal')" class="nz-btn nz-btn-size-small nz-btn-style-light float-left">
|
||||
<span>{{$t('dashboard.metric.normal')}}</span>
|
||||
</button>
|
||||
<button @click="" class="nz-btn nz-btn-size-small nz-btn-disabled nz-btn-style-normal float-left">
|
||||
<span>{{$t('dashboard.metric.expert')}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="nz-btn-group float-left" v-show="tableShow == 1">
|
||||
<button @click="" class="nz-btn nz-btn-size-small nz-btn-disabled nz-btn-style-normal float-left">
|
||||
<span>{{$t('dashboard.metric.normal')}}</span>
|
||||
</button>
|
||||
<button @click="clickTabelShow(2,'expert')" class="nz-btn nz-btn-size-small nz-btn-style-light float-left">
|
||||
<span>{{$t('dashboard.metric.expert')}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="tableShow == 2">
|
||||
<el-col span="22" class="mt1">
|
||||
<el-form-item prop="expression" :rules="{ required: true, message:$t('validate.required'), trigger: 'blur' }"><!--expression和metric的验证只能有一个,不能同时存在??:rules="{ required: true, type: 'string', message: '', trigger: 'change' }"-->
|
||||
<el-input size="mini" @input="changeExpression" class="full-width" ref="metricExpression" type="textarea" maxlength="1024" show-word-limit v-model="elementInfo.expression" :placeholder="this.$t('dashboard.metric.expertTip')" ></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col span="2">
|
||||
<button type="button" v-if="countTotal > 1" @click="deleteTarget" class="nz-btn nz-btn-size-normal nz-btn-style-light nz-btn-style-square nz-btn-style-higher"><span class="top-tool-btn-txt"><i class="el-icon-close"></i></span></button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="tableShow == 1">
|
||||
<el-col span="22" >
|
||||
<el-form-item :label-width="80" prop="metric" :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }"><!--:rules="{ required: true, type: 'string', message: '', trigger: 'change' }"-->
|
||||
<el-select ref="metricSelect" class="full-width" filterable placeholder="" popper-class="" size="small" v-model="elementInfo.metric" @change="selectMetric">
|
||||
<el-option v-for="(item, index) in metricShowList.arr" :key="item.metric + index"
|
||||
:value="item.metric">{{item.metric}}</el-option>
|
||||
</el-select>
|
||||
<span v-if="metricShowList.text" class="error-info-text">{{metricShowList.text}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col span="2">
|
||||
<button type="button" v-if="countTotal > 1" @click="deleteTarget" class="nz-btn nz-btn-size-normal nz-btn-style-light nz-btn-style-square nz-btn-style-higher"><span class="top-tool-btn-txt"><i class="el-icon-close"></i></span></button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="elementInfo.metric && tableShow == 1"><!--v-if="elementInfo.tagList.length > 0"-->
|
||||
<el-col span="12">
|
||||
<div class="metric-title-label">{{elementInfo.metric}}</div>
|
||||
<div class="li-list-part">
|
||||
<ul class="no-list-style">
|
||||
<li class="li-cursor" v-if="!item.isSelect"
|
||||
v-for="(item,index) in elementInfo.tagList"
|
||||
@click="getLidata(index,item)"
|
||||
:key="index">
|
||||
<div>
|
||||
<span >{{ item.name }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col span="12">
|
||||
<div class="li-list-part-label-val-list" >
|
||||
<el-form-item class="metric-title-position" v-for="(item, index) in elementInfo.selectedTagList" :key="index" :label="item.name" :label-width="100" :ref="'tagItem' + index" :prop="'tagList.' + index + '.value'" >
|
||||
<el-row class="metric-title-row-position" >
|
||||
<!--多选列表 -->
|
||||
<el-col span="20" >
|
||||
<el-select v-model="item.value" ref="tagSelect" size="small"
|
||||
placeholder=""
|
||||
collapse-tags
|
||||
filterable
|
||||
@change="changeTag"
|
||||
multiple>
|
||||
<el-option v-for="(op, j) in elementInfo.selectedTagList[index].list" :key="op + j" :value="op">{{op}}</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col span="4" >
|
||||
<button type="button" @click="deleteMetricLabel(item,index)" class="nz-btn nz-btn-size-normal nz-btn-style-light nz-btn-style-square nz-btn-style-higher"><span class="top-tool-btn-txt"><i class="el-icon-close"></i></span></button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<script>
|
||||
import bus from '../../../libs/bus';
|
||||
|
||||
export default {
|
||||
name: 'chartTag',
|
||||
props: {
|
||||
// 序号
|
||||
pointer: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// metric列表
|
||||
metricList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
countTotal: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
//multipleSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableShow: 1, // 1.normal; 2.expert
|
||||
// 指标信息
|
||||
elementInfo: {
|
||||
metric: '',//当前选中的metric名称
|
||||
type:'normal',
|
||||
// name: '',
|
||||
tagList: [], // 标签列表
|
||||
selectedTagList:[],//已选中的标签列表
|
||||
expression:''
|
||||
},
|
||||
metricLoading: false,
|
||||
keydataList: [], // tag标签键列表
|
||||
target: null, // 获取到的数据
|
||||
tagSet: null, // 根据你metric获取的tags信息
|
||||
setDataFlag: false, // true时为获取数据,编辑状态
|
||||
vendorCount: '',
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
// (最后整体保存添加的图标的时候执行)保存, chartdata点击确认后保存本身数据并返回给chartdata
|
||||
saveTarget() {
|
||||
this.$refs.elementInfo.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('on-add-target-success', this.elementInfo);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
// 删除该选项,第一步,传递要删除的参数
|
||||
deleteTarget() {
|
||||
//alert('metric第一步,删除的指针,之后回调box的第一个步'+this.pointer);
|
||||
this.$emit('on-delete-target', this.pointer);
|
||||
},
|
||||
// 第二步,on-delete-target回调,保存数据
|
||||
subSave() {
|
||||
//alert('metric第二步,bus.chartAddInfo.metricTarget,指针'+JSON.stringify(bus.chartAddInfo.metricTarget)+'==pointer'+this.pointer);
|
||||
bus.chartAddInfo.metricTarget[this.pointer] = this.elementInfo;
|
||||
//alert('metric第二步,保存信息到bus'+JSON.stringify(this.elementInfo))
|
||||
this.$emit('sub-save-ok');
|
||||
},
|
||||
// 第三步,将数据重新赋值,sub-save-ok回调
|
||||
setSubdata(index) {
|
||||
//alert('metric第三步,bus='+JSON.stringify(bus.chartAddInfo.metricTarget));
|
||||
//alert('metric第三步,bus('+this.pointer+')='+JSON.stringify(bus.chartAddInfo.metricTarget[this.pointer]));
|
||||
this.elementInfo = bus.chartAddInfo.metricTarget[this.pointer];
|
||||
//alert('metric第三步,index'+index+',如果index是当前pointer('+this.pointer+'),则继续,把bus中的值赋值给当前metric')
|
||||
//alert('metric第三步,elementInfo='+JSON.stringify(this.elementInfo));
|
||||
if(this.elementInfo.type==='expert'){
|
||||
//alert('metric第三步,expert');
|
||||
// 当该项expression为空时,重置一下
|
||||
if (!this.elementInfo.expression && this.$refs.metricExpression) {
|
||||
this.$refs.metricExpression.reset();
|
||||
}
|
||||
this.clickTabelShow(2,'expert');
|
||||
}else {
|
||||
// alert('metric第三步,normal');
|
||||
// 当该项metric为空时,重置一下
|
||||
if (!this.elementInfo.metric && this.$refs.metricSelect) {
|
||||
this.$refs.metricSelect.reset();
|
||||
}
|
||||
this.clickTabelShow(1,'normal');
|
||||
}
|
||||
},
|
||||
|
||||
// 选择metric
|
||||
selectMetric() {
|
||||
if (this.elementInfo.metric) {//选择了metric,则设置tagList,否则设置为空
|
||||
this.getSuggestTags(this.elementInfo.metric);
|
||||
} else {
|
||||
this.elementInfo.tagList = [];
|
||||
}
|
||||
this.$emit('on-change-condition');
|
||||
},
|
||||
// 获取tags列表
|
||||
getSuggestTags(metric) {
|
||||
this.$get('metric/labelName?metric='+metric).then(response => {
|
||||
this.elementInfo.selectedTagList = [];
|
||||
this.elementInfo.tagList = [];
|
||||
if (response.code === 200) {
|
||||
if(response.data.list){
|
||||
//this.elementInfo.tagList = response.data.list;
|
||||
response.data.list.forEach((item) => {
|
||||
const tagObj = {
|
||||
name: item.name,
|
||||
isSelect:false//当前元素是否被选中,默认都未选中
|
||||
};
|
||||
this.elementInfo.tagList.push(tagObj);
|
||||
});
|
||||
}else{
|
||||
response.data.forEach((item) => {
|
||||
const tagObj = {
|
||||
name: item.name,
|
||||
isSelect:false //当前元素是否被选中,默认都未选中
|
||||
};
|
||||
this.elementInfo.tagList.push(tagObj);
|
||||
});
|
||||
}
|
||||
//this.elementInfo.tagList = response.data.list;
|
||||
}else {
|
||||
this.elementInfo.tagList = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
getStyles(width) {
|
||||
return `width: ${width}px;`;
|
||||
},
|
||||
filterMethod(value, option) {
|
||||
return option.toUpperCase().indexOf(value.toUpperCase()) !== -1;
|
||||
},
|
||||
|
||||
changeTag(){
|
||||
this.$emit('on-change-condition');
|
||||
},
|
||||
changeExpression(v){
|
||||
this.$emit('on-change-condition');
|
||||
},
|
||||
// 编辑已有图表状态时,先填充数据
|
||||
setMdata(data) {
|
||||
//alert('metricSetData'+JSON.stringify(data));
|
||||
this.setDataFlag = true;
|
||||
this.target = Object.assign({}, data);
|
||||
//this.pointer =
|
||||
if(this.target.type==='expert'){
|
||||
this.tableShow = 2;
|
||||
this.elementInfo.type = this.target.type;
|
||||
this.elementInfo.expression = this.target.expression;
|
||||
}else {
|
||||
this.tableShow = 1;
|
||||
this.elementInfo.type = this.target.type;
|
||||
//解析expression,=>标签列表,值列表(index对应),设置selectedTagList及tagList里的isSelect为true
|
||||
var expression = this.target.expression;
|
||||
//alert('expression=='+expression);
|
||||
if(expression.indexOf('{')>-1){
|
||||
this.elementInfo.metric = expression.substring(0,expression.indexOf('{'));
|
||||
}else {
|
||||
this.elementInfo.metric = expression;
|
||||
}
|
||||
|
||||
//alert(this.elementInfo.metric);
|
||||
//this.selectMetric(); // 获取tag
|
||||
this.$get('metric/labelName?metric='+this.elementInfo.metric).then(response => {
|
||||
this.elementInfo.selectedTagList = [];
|
||||
this.elementInfo.tagList = [];
|
||||
if (response.code === 200) {
|
||||
//this.elementInfo.tagList = response.data.list;
|
||||
if(response.data.list){
|
||||
response.data.list.forEach((item) => {
|
||||
const tagObj = {
|
||||
name: item.name,
|
||||
isSelect:false//当前元素是否被选中,默认都未选中
|
||||
};
|
||||
this.elementInfo.tagList.push(tagObj);
|
||||
});
|
||||
}else {
|
||||
response.data.forEach((item) => {
|
||||
const tagObj = {
|
||||
name: item.name,
|
||||
isSelect:false//当前元素是否被选中,默认都未选中
|
||||
};
|
||||
this.elementInfo.tagList.push(tagObj);
|
||||
});
|
||||
}
|
||||
if(expression.indexOf('{')>-1){
|
||||
let labValArrStr = expression.substring(expression.indexOf('{')+1,expression.indexOf('}'));
|
||||
this.stringToTags(labValArrStr);
|
||||
}
|
||||
}else {
|
||||
this.elementInfo.tagList = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
//字符串格式化为对象metric{a='1',b=~'2|3|4'}===>a='1',b=~'2|3|4'
|
||||
stringToTags(str) {
|
||||
let labArr = str.split(',');
|
||||
labArr.forEach((item, index) => {//b=~'1|2|3'
|
||||
let labName = item.substring(0,item.indexOf('='));
|
||||
this.elementInfo.tagList.every((tagItem,index) => {
|
||||
if(tagItem.name===labName){
|
||||
tagItem.isSelect = true;
|
||||
return false;
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//查询metricLabel名称对应的LabelValue
|
||||
this.$get('metric/labelVal?metric='+this.elementInfo.metric+"&name="+labName).then(response => {
|
||||
const tagObj = {
|
||||
name:labName,//选中的metricLabel名称
|
||||
list:[],//metricLabel名称对应的LabelValue
|
||||
value:[]//最终选择的值
|
||||
};
|
||||
let labVal = item.substring(item.indexOf('=')+1,item.length);
|
||||
if(labVal.indexOf('~')!=-1){
|
||||
labVal = labVal.substring(2,labVal.length-1);
|
||||
let valArr = labVal.split('|');
|
||||
valArr.forEach((labItem, labIndex) => {
|
||||
tagObj.value.push(labItem);
|
||||
});
|
||||
}else {
|
||||
labVal = labVal.substring(1,labVal.length-1);
|
||||
tagObj.value.push(labVal);
|
||||
}
|
||||
if (response.code === 200) {
|
||||
if(response.data.list){
|
||||
response.data.list.forEach((resItem) => {
|
||||
tagObj.list.push(resItem.value)
|
||||
});
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}else{
|
||||
response.data.forEach((resItem) => {
|
||||
tagObj.list.push(resItem.value)
|
||||
});
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}
|
||||
}else {
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
clearHistory() {
|
||||
this.elementInfo.metric = '';
|
||||
this.setDataFlag = false;
|
||||
if (this.$refs.elementInfo) {
|
||||
this.$refs.elementInfo.resetFields();//???
|
||||
}
|
||||
if (this.$refs.metricSelect) {
|
||||
this.$refs.metricSelect.reset();
|
||||
}
|
||||
this.elementInfo.tagList = [];
|
||||
},
|
||||
// 获取文本宽度
|
||||
getWidth(str) {
|
||||
const sensor = document.createElement('pre');
|
||||
sensor.innerHTML = str;
|
||||
sensor.style.display = 'inline-block';
|
||||
sensor.style.width = 'auto';
|
||||
sensor.style.visibility = 'hidden';
|
||||
sensor.style.height = 0;
|
||||
sensor.style.position = 'relative';
|
||||
sensor.style['z-index'] = -10;
|
||||
document.body.appendChild(sensor);
|
||||
const width = sensor.offsetWidth;
|
||||
document.body.removeChild(sensor);
|
||||
const widthL = width > 180 ? width : 180;
|
||||
return widthL;
|
||||
},
|
||||
// 将tag添加到相应框内
|
||||
proTags(data) {
|
||||
const dou = data.indexOf(',');
|
||||
// 只有一组tag
|
||||
if (dou === -1) {
|
||||
const set = data.split('=');
|
||||
const tagValueArr = set[1].indexOf('|') > -1 ? set[1].split('|') : [set[1]];
|
||||
const tagIndex = this.elementInfo.tagList.findIndex(t => t.name === set[0]);
|
||||
if (tagIndex > -1) {
|
||||
this.elementInfo.tagList[tagIndex].value = tagValueArr;
|
||||
}
|
||||
} else { // 多组tag
|
||||
const mid = data.split(','); // ['key=v1','key=v2|v3',....]
|
||||
mid.forEach((item) => {
|
||||
const setInner = item.split('=');
|
||||
const innerValueArr = setInner[1].indexOf('|') > -1 ?
|
||||
setInner[1].split('|') : [setInner[1]];
|
||||
const tagIndex = this.elementInfo.tagList.findIndex(t => t.name === setInner[0]);
|
||||
if (tagIndex > -1) {
|
||||
this.elementInfo.tagList[tagIndex].value = innerValueArr;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
//metricLabelName单击事件
|
||||
getLidata(index, item) {
|
||||
if(!item.isSelect){
|
||||
this.vendorCount = index;
|
||||
//查询metricLabel名称对应的LabelValue
|
||||
this.$get('metric/labelVal?metric='+this.elementInfo.metric+"&name="+item.name).then(response => {
|
||||
const tagObj = {
|
||||
name: item.name,//选中的metricLabel名称
|
||||
list:[],//metricLabel名称对应的LabelValue
|
||||
value:[]//最终选择的值
|
||||
};
|
||||
//this.elementInfo.selectedTagList = [];
|
||||
if (response.code === 200) {
|
||||
if(response.data.list){
|
||||
response.data.list.forEach((item) => {
|
||||
tagObj.list.push(item.value)
|
||||
});
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}else{
|
||||
response.data.forEach((item) => {
|
||||
tagObj.list.push(item.value)
|
||||
});
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}
|
||||
}else {
|
||||
this.elementInfo.selectedTagList.push(tagObj);
|
||||
}
|
||||
});
|
||||
item.isSelect = true;
|
||||
}
|
||||
this.$emit('on-change-condition');
|
||||
},
|
||||
//删除MetricLabel时,需要将tagList中的isSelect设置为false,并删除elementInfo.selectedTagList里对应的元素
|
||||
deleteMetricLabel(item,index) {
|
||||
this.elementInfo.tagList.forEach((tagItem) => {
|
||||
if(tagItem.name===item.name){
|
||||
tagItem.isSelect = false;
|
||||
}
|
||||
});
|
||||
this.elementInfo.selectedTagList.splice(index,1);
|
||||
//this.$emit('on-delete-target', this.pointer);
|
||||
this.$emit('on-change-condition');
|
||||
},
|
||||
clickTabelShow(val,type){
|
||||
this.tableShow = val;
|
||||
this.elementInfo.type = type;
|
||||
if(val===2){
|
||||
this.elementInfo.metric='';
|
||||
}
|
||||
if(val===1){
|
||||
this.elementInfo.expression='';
|
||||
}
|
||||
this.$emit('on-change-condition');
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
metricShowList() {
|
||||
const obj = {
|
||||
arr: [...this.metricList],
|
||||
text: '',
|
||||
};
|
||||
return obj;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('clear_history', () => {
|
||||
this.clearHistory();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,51 @@
|
||||
.metric-dashboard {
|
||||
width: 100%;
|
||||
height:100%;
|
||||
// padding: 6px 10px 6px;
|
||||
.box-content {
|
||||
//position: relative;
|
||||
width:calc(100% - 13px);
|
||||
}
|
||||
.table-list {
|
||||
margin-top:30px;
|
||||
overflow-y:auto;
|
||||
height: 100%;
|
||||
}
|
||||
.row-width{
|
||||
//width:calc(100% - 0px);
|
||||
}
|
||||
.chartBox {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
.chartBoxMul {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
.common-detail-top-title {
|
||||
font-size: 16px;
|
||||
color: #5697f1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.chart-das {
|
||||
height: 98%;
|
||||
.border-area {
|
||||
// border: 1px solid #d6d6d6;
|
||||
}
|
||||
}
|
||||
.metric-title{
|
||||
border-left: 3px solid #e07700;
|
||||
font-weight: bold;
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
<style scoped>
|
||||
.metricPreview {
|
||||
height: 100%;
|
||||
width:100%;
|
||||
}
|
||||
</style>
|
||||
*/
|
||||
@@ -1,10 +1,8 @@
|
||||
<style scoped>
|
||||
.metricPreview {
|
||||
height: 100%;
|
||||
}
|
||||
<style lang="scss">
|
||||
@import './metricPreview.scss';
|
||||
</style>
|
||||
<template>
|
||||
<div class="metricPreview">
|
||||
<div class="main-container metric-dashboard">
|
||||
<div class="content-left">
|
||||
<div class="sidebar-title">{{$t('dashboard.title')}}</div>
|
||||
<div class="sidebar-info">
|
||||
@@ -14,17 +12,169 @@
|
||||
</div>
|
||||
<div class="content-right">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="top-tools" >
|
||||
<div class="float-left metric-title" >指标预览
|
||||
</div>
|
||||
<div class="float-right mr-10">
|
||||
<el-date-picker size="small" ref="calendar"
|
||||
format="yyyy/MM/dd HH:mm"
|
||||
@change="dateChange"
|
||||
v-model="searchTime"
|
||||
type="datetimerange"
|
||||
:picker-options="pickerOptions"
|
||||
:range-separator="$t('dashboard.panel.to')"
|
||||
:start-placeholder="$t('dashboard.panel.startTime')"
|
||||
:end-placeholder="$t('dashboard.panel.endTime')"
|
||||
align="right">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-list" >
|
||||
<div class="box-content" >
|
||||
<el-row :gutter="20" class="row-width" >
|
||||
<el-col :span="12" >
|
||||
<div >{{$t('dashboard.panel.chartForm.metric')}}</div>
|
||||
<metric-set ref="metricSet" @on-view-chart="getChartParam"></metric-set>
|
||||
</el-col>
|
||||
<el-col :span="12" >
|
||||
<el-row class="border-area" v-show="chartCount === 'single'">
|
||||
<div class="chartBox">
|
||||
<line-chart-block
|
||||
:show-setting="false"
|
||||
ref="editChartSingle"
|
||||
@on-refresh-data="refreshChart"
|
||||
@on-remove-chart-block="removeChart"
|
||||
@on-edit-chart-block="editData"
|
||||
></line-chart-block>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row class="border-area" v-show="chartCount === 'multiple'">
|
||||
<div class="chartBoxMul" v-for="(item, index) in lineList">
|
||||
<line-chart-block
|
||||
:show-setting="false"
|
||||
ref="editChartMultiple"
|
||||
@on-refresh-data="refreshChart"
|
||||
@on-remove-chart-block="removeChart"
|
||||
@on-edit-chart-block="editData"
|
||||
></line-chart-block>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import bus from '../../../libs/bus';
|
||||
import metricSet from './metricSet';
|
||||
import lineChartBlock from '../../charts/line-chart-block';
|
||||
|
||||
export default {
|
||||
name: "metricPreview",
|
||||
components: {
|
||||
lineChartBlock,
|
||||
metricSet
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
filter: {
|
||||
start_time: '',
|
||||
end_time: '',
|
||||
},
|
||||
total: 0, // 总数
|
||||
selectedData: null, // 选中数据
|
||||
searchName: '', // 搜索名称
|
||||
showTagModal: false,
|
||||
tagSet: null, // 根据你metric获取的tags信息
|
||||
metricInfo: {}, // 保存参数信息
|
||||
chartCount: 'single', // multiple
|
||||
lineList: [], // 线列表
|
||||
searchTime:[new Date().setHours(new Date().getHours()-1),new Date()],
|
||||
//searchTime:[new Date().setMinutes(new Date().getMinutes()-1),new Date()],
|
||||
pickerOptions: {
|
||||
shortcuts: [
|
||||
{
|
||||
text: this.$t("dashboard.panel.recOne"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setHours(start.getHours() - 1);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
},{
|
||||
text: this.$t("dashboard.panel.recFour"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setHours(start.getHours() - 4);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: this.$t("dashboard.panel.recOneDay"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 1);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: this.$t("dashboard.panel.yesterday"),
|
||||
onClick(picker) {
|
||||
const start = new Date();
|
||||
const end = new Date();
|
||||
start.setDate(start.getDate() - 1);
|
||||
start.setHours(0);
|
||||
start.setMinutes(0);
|
||||
start.setSeconds(0);
|
||||
end.setDate(end.getDate() - 1);
|
||||
end.setHours(23);
|
||||
end.setMinutes(59);
|
||||
end.setSeconds(59);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
},{
|
||||
text: this.$t("dashboard.panel.recSevenDay"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: this.$t("dashboard.panel.recOneMonth"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: this.$t("dashboard.panel.curMonth"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(1);
|
||||
start.setHours(0);
|
||||
start.setMinutes(0);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
},{
|
||||
text: this.$t("dashboard.panel.lastMonth"),
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(1);
|
||||
start.setMonth(start.getMonth() - 1);
|
||||
end.setDate(0);
|
||||
start.setStart();
|
||||
end.setEnd();
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -37,10 +187,204 @@ export default {
|
||||
t: +new Date()
|
||||
}
|
||||
});
|
||||
},
|
||||
// 获取默认时间
|
||||
getInit() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setHours(start.getHours() - 1);
|
||||
start.setSeconds(0);
|
||||
end.setSeconds(59);
|
||||
this.filter.start_time = bus.timeFormate(start, 'yyyy-MM-dd hh:mm:ss');
|
||||
this.filter.end_time = bus.timeFormate(end, 'yyyy-MM-dd hh:mm:ss');
|
||||
},
|
||||
dateChange(time) {
|
||||
this.filter.start_time = `${time[0]}:00`;
|
||||
this.filter.end_time = `${time[1]}:59`;
|
||||
this.getChartParam(this.metricInfo, this.chartCount);
|
||||
if (this.chartCount === 'single') {
|
||||
this.$refs.editChartSingle.changeDate(this.searchTime);
|
||||
} else if (this.chartCount === 'multiple') {
|
||||
if (this.lineList.length > 0) {
|
||||
this.$refs.editChartMultiple.forEach((item) => {
|
||||
item.changeDate(this.searchTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
// 获取图表信息
|
||||
getChartParam(params, chartCount) {
|
||||
this.chartCount = chartCount;
|
||||
this.metricInfo = params;
|
||||
if (this.chartCount === 'single') {
|
||||
this.$refs.editChartSingle.showLoad();
|
||||
} else if (this.chartCount === 'multiple') {
|
||||
if (this.lineList.length > 0) {
|
||||
this.$refs.editChartMultiple.forEach((item) => {
|
||||
item.showLoad();
|
||||
});
|
||||
}
|
||||
}
|
||||
const startTime = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss');
|
||||
const endTime = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss');
|
||||
this.filter.start_time = startTime;
|
||||
this.filter.end_time = endTime;
|
||||
let step = bus.getStep(startTime,endTime);
|
||||
this.$get('/prom/api/v1/query_range?query='+params.elements[0].expression+"&start="+startTime+"&end="+endTime+'&step='+step).then(response => {
|
||||
this.$refs.metricSet.loading = false;
|
||||
if (response.status === 'success') {
|
||||
if (response.data.result) {
|
||||
this.lineList = response.data.result;
|
||||
// 如果只有一组数据,强制显示一条
|
||||
if (response.data.result.length === 1) {
|
||||
this.chartCount = 'single';
|
||||
}
|
||||
}
|
||||
this.getChartData(response, params);
|
||||
}else {
|
||||
this.chartCount = 'single';
|
||||
// 图表不可保存
|
||||
this.$refs.metricSet.saveDisabled = true;
|
||||
this.$refs.metricSet.isSave = false;
|
||||
this.chartCount = 'single';
|
||||
if(response.msg){
|
||||
this.$message.error(response.msg);
|
||||
}else {
|
||||
this.$message.error(response);
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.editChartSingle.setData(params, [], 0, this.filter);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 获取一个图表具体数据
|
||||
getChartData(response, params) {
|
||||
const chartItem = Object.assign({}, params);
|
||||
chartItem.title = params.metric || '预览图';
|
||||
const series = [];
|
||||
const legend = [];
|
||||
// 一个图表
|
||||
response.data.result.forEach((queryItem) => {
|
||||
const seriesItem = {
|
||||
theData: {
|
||||
name: '',
|
||||
symbol:'none', //去掉点
|
||||
smooth:true, //曲线变平滑
|
||||
data: [],
|
||||
type:chartItem.type,
|
||||
//visible: true,
|
||||
//threshold: null,
|
||||
},
|
||||
metric_name: '',
|
||||
};
|
||||
// 图表中每条线的名字,后半部分
|
||||
let host = `${queryItem.metric.__name__}{`;//up,
|
||||
const tagsArr = Object.keys(queryItem.metric);//["__name__","asset","idc","instance","job","module","project"]
|
||||
// 设置时间-数据格式对
|
||||
const dpsArr = Object.entries(queryItem.values);//[ ["0",[1577959830.781,"0"]], ["1",[1577959845.781,"0"]] ]
|
||||
// 判断是否有数据
|
||||
if (dpsArr.length > 0 && tagsArr.length > 0) {
|
||||
tagsArr.forEach((tag, i) => {
|
||||
if (tag !== '__name__') {
|
||||
host += `${tag}="${queryItem.metric[tag]}",`;
|
||||
}
|
||||
});
|
||||
if(host.endsWith(',')){host = host.substr(0,host.length-1);}
|
||||
host +="}";
|
||||
legend.push(host);
|
||||
// 图表中每条线的名字,去掉最后的逗号与空格
|
||||
seriesItem.theData.name = host;
|
||||
seriesItem.metric_name = seriesItem.theData.name;
|
||||
// 将秒改为毫秒
|
||||
seriesItem.theData.data = queryItem.values.map(dpsItem =>
|
||||
[dpsItem[0] * 1000, dpsItem[1]]);
|
||||
series.push(seriesItem.theData);
|
||||
} else {/*
|
||||
const errorMsg = `metric: ${params.metric} 和tags ${params.tags} 组合下无数据`;
|
||||
this.$message.error({
|
||||
duration: 15,
|
||||
content: errorMsg,
|
||||
closable: true,
|
||||
});
|
||||
*/
|
||||
}
|
||||
});
|
||||
// 将获取的数据运用于创建多个图表备用
|
||||
this.$refs.metricSet.setSeries(response.data.result.values);//???
|
||||
if (this.chartCount === 'single') {
|
||||
this.setSize(chartItem.span, 0);
|
||||
const filterParams = Object.assign({}, this.filter);
|
||||
filterParams.chartCount = 'single';
|
||||
this.$nextTick(() => {
|
||||
this.$refs.editChartSingle.setData(chartItem, series, 0, filterParams,legend);
|
||||
});
|
||||
} else if (this.chartCount === 'multiple') {
|
||||
const filterParams = Object.assign({}, this.filter);
|
||||
filterParams.chartCount = 'multiple';
|
||||
this.setSize(chartItem.span, 'all');
|
||||
this.$nextTick(() => {
|
||||
series.forEach((serieData, index) => {
|
||||
// 设置每个图表名称
|
||||
const chartInfoParams = Object.assign({}, chartItem);
|
||||
chartInfoParams.title = serieData.name;
|
||||
this.$refs.editChartMultiple[index]
|
||||
.setData(chartInfoParams, [serieData], 0, filterParams,[legend[index]]);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
// 设置图表的宽度
|
||||
setSize(size, index) {
|
||||
this.$nextTick(() => {
|
||||
const chartBox = document.getElementsByClassName('chartBox');
|
||||
if (index === 0) {
|
||||
chartBox[index].style.width = `${(size / 12) * 100}%`;
|
||||
} else {
|
||||
const chartBoxMul = document.getElementsByClassName('chartBoxMul');
|
||||
Array.prototype.slice.call(chartBoxMul).forEach((item) => {
|
||||
const obj = item;
|
||||
obj.style.width = `${(size / 12) * 100}%`;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
refreshChart() {},
|
||||
removeChart() {},
|
||||
editData() {},
|
||||
/*
|
||||
|
||||
|
||||
// 查看指标确认
|
||||
viewConfirm() {
|
||||
this.showTagModal = false;
|
||||
},
|
||||
// 取消查看
|
||||
viewCancel() {
|
||||
this.showTagModal = false;
|
||||
this.selectedData = {};
|
||||
},
|
||||
// 查看详情
|
||||
viewDetail(item) {
|
||||
this.selectedData = item;
|
||||
},
|
||||
// eslint-disable-next-line
|
||||
search: _.debounce(function() { // 输入框筛选
|
||||
}, 300),
|
||||
// 刷新
|
||||
reload() {
|
||||
this.getChartParam(this.metricInfo, this.chartCount);
|
||||
},
|
||||
// 滚动条复位
|
||||
refresh_scroll() {
|
||||
window.scrollTo(0, 0);
|
||||
},
|
||||
|
||||
*/
|
||||
},
|
||||
mounted: function() {
|
||||
this.getInit();
|
||||
},
|
||||
watch: {
|
||||
|
||||
|
||||
59
nezha-fronted/src/components/page/dashboard/metricSet.scss
Normal file
59
nezha-fronted/src/components/page/dashboard/metricSet.scss
Normal file
@@ -0,0 +1,59 @@
|
||||
.metric-set {
|
||||
/*搜索栏样式*/
|
||||
.search-data {
|
||||
width: 100%;
|
||||
padding: 5px 15px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: #f5f7f9;
|
||||
}
|
||||
.search-data-title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.metric-form {
|
||||
padding-top: 20px;
|
||||
box-sizing: border-box;
|
||||
// height: 69%;
|
||||
// max-height: 400px;
|
||||
// overflow: auto;
|
||||
}
|
||||
.operate-area {
|
||||
border-top: 1px solid #dfe7f2;
|
||||
border-bottom: 1px solid #dfe7f2;
|
||||
padding: 5px 0;
|
||||
.operate-area-title {
|
||||
padding: 5px 0;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.element-item {
|
||||
padding-top: 20px;
|
||||
border-top: 1px dashed #dfe7f2;
|
||||
}
|
||||
.ivu-form-item .ivu-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.host-form-item {
|
||||
.ivu-form-item-content {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
.pt-5{
|
||||
padding-top:5px;
|
||||
}
|
||||
.pb-5{
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.mt-10{
|
||||
margin-top:10px;
|
||||
}
|
||||
.nx-btn-disabled{
|
||||
cursor:not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// .setdata {
|
||||
// height: 100%;
|
||||
// position: relative;
|
||||
// }
|
||||
498
nezha-fronted/src/components/page/dashboard/metricSet.vue
Normal file
498
nezha-fronted/src/components/page/dashboard/metricSet.vue
Normal file
@@ -0,0 +1,498 @@
|
||||
<style lang="scss">
|
||||
@import 'metricSet';
|
||||
</style>
|
||||
<template>
|
||||
<div class="metric-set" >
|
||||
<div class="metric-form">
|
||||
<el-row class="element-item" >
|
||||
<chart-metric ref="chartTag"
|
||||
:metric-list="metricList"
|
||||
@on-add-target-success="getTarget"
|
||||
@on-change-condition="getCondition"
|
||||
></chart-metric>
|
||||
</el-row>
|
||||
<el-row class="pt-5 pb-5">
|
||||
<button type="primary" @click="preview" :disabled="loading" class="nz-btn nz-btn-size-normal nz-btn-style-normal ">预览图表</button>
|
||||
<button :disabled="saveDisabled || loading" type="primary" @click="preview('change')"
|
||||
:class="{'nz-btn nx-btn-disabled' : (saveDisabled || loading), 'nz-btn nz-btn-size-normal nz-btn-style-normal' : !(saveDisabled || loading)}"
|
||||
>{{chartSwitchWord}}</button>
|
||||
<!-- <Button type="primary" @click="addTarget">添加指标</Button> -->
|
||||
</el-row>
|
||||
<el-row class="operate-area">
|
||||
<div class="operate-area-title">保存图表到看板:</div>
|
||||
<button :disabled="saveDisabled" type="primary" @click="createNew"
|
||||
:class="{'nz-btn nx-btn-disabled' : saveDisabled , 'nz-btn nz-btn-size-normal nz-btn-style-normal' : !saveDisabled}"
|
||||
>创建看板</button>
|
||||
<button :disabled="saveDisabled" type="primary" @click="selectPanel"
|
||||
:class="{'nz-btn nx-btn-disabled' : saveDisabled , 'nz-btn nz-btn-size-normal nz-btn-style-normal' : !saveDisabled}"
|
||||
>选择已有看板</button>
|
||||
</el-row>
|
||||
<el-row class="mt-10">
|
||||
<el-checkbox :disabled="saveDisabled" v-model="isSave">options</el-checkbox>
|
||||
</el-row>
|
||||
<el-form :model="chartInfo" ref="chartInfo" v-show="isSave">
|
||||
<el-row>
|
||||
<div class="common-float-left">
|
||||
<el-form-item :label-width="80" label="图宽" prop="span"
|
||||
:rules="{ required: true, type: 'number', message: '请选择图表宽度', trigger: 'change' }">
|
||||
<el-select style="width:130px;" size="small" v-model="chartInfo.span" transfer>
|
||||
<el-option v-for="item in spanList" :key="item" :label="'span-' + item" :value="item">
|
||||
span-{{item}}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="common-float-left">
|
||||
<el-form-item :label-width="80" label="图高" prop="height"
|
||||
:rules="{ required: true, type: 'number', message: '请输入图表高度', trigger: 'change' }">
|
||||
<el-input-number :min="400" size="small" v-model="chartInfo.height" style="width: 130px" placeholder="请输入图表高度"></el-input-number>px
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="common-float-left">
|
||||
<el-form-item :label-width="80" label="类型" prop="type"
|
||||
:rules="{ required: true, message: '请选择图表类型', trigger: 'change' }">
|
||||
<el-select transfer style="width:130px;" v-model="chartInfo.type" size="small">
|
||||
<el-option v-for="item in typeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
{{item.name}}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<metric-pre-panel-box :chartInfo="chartInfo" :elementTarget="elementTarget" :seriesData="seriesData" :chartCount="chartCount" @reload="reload" ref="panelBox"></metric-pre-panel-box>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import bus from '../../../libs/bus';
|
||||
import chartMetric from "./chartMetricForPreview";
|
||||
import metricPrePanelBox from "../../common/rightBox/metricPrePanelBox";
|
||||
|
||||
export default {
|
||||
name: 'metricSet',
|
||||
props: {
|
||||
},
|
||||
components: {
|
||||
'chart-metric':chartMetric,
|
||||
'metric-pre-panel-box':metricPrePanelBox
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
total: 0,
|
||||
loading: false, // 加载中
|
||||
chartModal: false, // 展示弹出框
|
||||
// 新建信息
|
||||
chartInfo: {
|
||||
title: '', // 名称
|
||||
span: 12, // 宽度
|
||||
height: 400, // 高度
|
||||
type: 'line', // 类型
|
||||
},
|
||||
chartId: 0,
|
||||
elements: [1], // 指标部分 tarNum
|
||||
elementTarget: {}, // 获取chartTag数据后保存
|
||||
// 宽度列表
|
||||
spanList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
typeList: [
|
||||
{
|
||||
id:"line",
|
||||
name:this.$t("dashboard.panel.chartForm.typeVal.line.label")
|
||||
},
|
||||
{
|
||||
id:"bar",
|
||||
name:this.$t("dashboard.panel.chartForm.typeVal.bar.label")
|
||||
}
|
||||
],
|
||||
//productId: 0,
|
||||
panelId: 0,
|
||||
metricList: [], // metric列表
|
||||
isSave: false, // 是否要保存
|
||||
saveDisabled: true, // 不可保存
|
||||
createModal: false, // 创建看板panel
|
||||
panelList: [],
|
||||
// 创建看板信息
|
||||
chartSaveInfo: {
|
||||
title: '', // 图表名称
|
||||
name: '', // panel名称
|
||||
panelId: '', // 选择以后panelId
|
||||
}, // 保存看板
|
||||
isCreatePanel: false,
|
||||
createModalTitle: '',
|
||||
chartCount: 'single', // multiple多图,single单图
|
||||
metricInfo: {}, // 保存从chartTag中获取的seriesData
|
||||
createChartList: [], // 创建多个图表的图表信息
|
||||
seriesData: [], // 查询图表后生成的series信息,用于生成多个图表时提供图表title
|
||||
panelItem: {}, // 保存看板信息
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
chartSwitchWord() {
|
||||
const word = this.chartCount === 'single' ? '多图展示' : '单图展示';
|
||||
return word;
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
// 父级调用保存series,作为多个图表生成title
|
||||
setSeries(data) {
|
||||
this.seriesData = data;
|
||||
},
|
||||
// 默认打开
|
||||
initOpen() {
|
||||
this.getSuggestMetric();
|
||||
},
|
||||
// chart-tag中条件更改时,触发不能创建
|
||||
getCondition() {
|
||||
this.saveDisabled = true;
|
||||
},
|
||||
reload(){
|
||||
this.saveDisabled = true;
|
||||
this.elementTarget = {};
|
||||
},
|
||||
// 创建看板
|
||||
createNew() {
|
||||
this.$refs.panelBox.show(true);
|
||||
//this.panel = {id: '', name: ''};
|
||||
this.$refs.panelBox.setTitle(this.$t("dashboard.panel.createPanelTitle"));
|
||||
this.$refs.panelBox.setIsCreatePanel(true);
|
||||
this.$refs.panelBox.setChartTitle(this.metricInfo.metric);
|
||||
},
|
||||
// 选择看板
|
||||
selectPanel() {
|
||||
this.$refs.panelBox.show(true);
|
||||
this.$refs.panelBox.setTitle(this.$t("dashboard.panel.selectPanelTitle"));
|
||||
this.$refs.panelBox.setIsCreatePanel(false);
|
||||
this.$refs.panelBox.setChartTitle(this.metricInfo.metric);
|
||||
this.$refs.panelBox.getTableData();
|
||||
},
|
||||
// 取消创建modal
|
||||
cancel() {
|
||||
this.panelList = [];
|
||||
this.chartSaveInfo.panelId = ''; // 选择panel
|
||||
this.chartSaveInfo.name = ''; // panel名称创建
|
||||
if (this.$refs.chartSaveInfo) {
|
||||
this.$refs.chartSaveInfo.resetFields();
|
||||
}
|
||||
if (this.$refs.panelSelect) {
|
||||
this.$refs.panelSelect.reset();
|
||||
}
|
||||
this.createModal = false;
|
||||
},
|
||||
// 重置已选择的看板
|
||||
initSaveInfo() {
|
||||
this.chartSaveInfo.name = ''; // panel名称创建
|
||||
this.chartSaveInfo.panelId = ''; // 选择panel
|
||||
},
|
||||
close() {
|
||||
this.elementTarget = {}; // 初始化清空参数
|
||||
this.initInfo();
|
||||
this.chartModal = false;
|
||||
},
|
||||
// 初始化信息
|
||||
initInfo() {
|
||||
this.chartInfo.title = '';
|
||||
this.chartInfo.type = 1;
|
||||
this.chartInfo.span = 12;
|
||||
this.chartInfo.height = 400;
|
||||
this.elements = [1];
|
||||
this.elementTarget = {};
|
||||
},
|
||||
// 生成预览图表
|
||||
preview(params) {
|
||||
if (params === 'change') {
|
||||
this.chartCount = this.chartCount === 'single' ? 'multiple' : 'single';
|
||||
}
|
||||
this.elementTarget = {}; // 初始化清空参数
|
||||
// 触发每个tag组件内部进行校验
|
||||
this.$refs.chartTag.saveTarget(); // => getTartget
|
||||
// 保存图表时进行参数认证
|
||||
if (this.isSave) {
|
||||
this.$refs.chartInfo.validate();
|
||||
}
|
||||
},
|
||||
// 获取每个tag组件内部校验后数据,点击生成图表时触发
|
||||
getTarget(target) {
|
||||
// 由于条件限制,每次其实只有一个target
|
||||
this.elementTarget = JSON.parse(JSON.stringify(target));
|
||||
this.$refs.chartInfo.validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
// 保存图表到看板
|
||||
const params = Object.assign({}, this.chartInfo);
|
||||
|
||||
//params.tags = this.tagsToString(this.elementTarget.tagList);
|
||||
const elements = [];
|
||||
//params.elementTargetType = this.elementTarget.type;
|
||||
if(this.elementTarget.type==='normal'){
|
||||
const metricStr = bus.tagsToString(this.elementTarget.metric,this.elementTarget.selectedTagList);
|
||||
//params.expression = metricStr;
|
||||
elements.push({
|
||||
expression: metricStr,
|
||||
type: this.elementTarget.type,
|
||||
});
|
||||
params.metric = this.elementTarget.metric;
|
||||
}else if(this.elementTarget.type==='expert'){
|
||||
//params.expression = this.elementTarget.expression;
|
||||
elements.push({
|
||||
expression: this.elementTarget.expression,
|
||||
type: this.elementTarget.type,
|
||||
});
|
||||
params.metric = this.elementTarget.expression;
|
||||
}
|
||||
params.elements = elements;
|
||||
//params.expression
|
||||
this.metricInfo = params;
|
||||
this.saveDisabled = false; // 查询成功以后,可以进行保存操作
|
||||
// 将参数返回,进行查询
|
||||
this.$emit('on-view-chart', params, this.chartCount);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 确认创建图表
|
||||
createConfirm() {
|
||||
this.$refs.chartInfo.validate((valid) => {
|
||||
if (valid) { // 先判断参数正确与否
|
||||
this.$refs.chartSaveInfo.validate((flag) => {
|
||||
if (flag) { // 再判断弹出窗口内内容是否正确
|
||||
if (this.isCreatePanel) { // 创建看板
|
||||
this.addPanels();
|
||||
} else { // 选择看板
|
||||
this.panelId = this.chartSaveInfo.panelId;
|
||||
this.getOptions();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 创建看板接口
|
||||
addPanels() {
|
||||
addPanels({
|
||||
productId: this.productId,
|
||||
name: this.chartSaveInfo.name,
|
||||
}).then((res) => {
|
||||
if (res.status === 200 && res.data.code === 200) {
|
||||
this.panelId = res.data.panel.id;
|
||||
this.panelItem = res.data.panel;
|
||||
this.getOptions();
|
||||
} else {
|
||||
this.$Message.warning('创建看板失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 选择看板
|
||||
panelSelect(id) {
|
||||
if (id) {
|
||||
const panel = this.panelList.find(p => p.id === id);
|
||||
if (panel) {
|
||||
this.panelItem = panel;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 生成图表的时候,使用该函数,汇总创建图表参数
|
||||
getOptions() {
|
||||
this.$refs.chartInfo.validate((valid) => {
|
||||
const params = {
|
||||
productId: this.productId,
|
||||
panelId: this.panelId,
|
||||
// title: this.chartSaveInfo.title,
|
||||
type: this.chartInfo.type,
|
||||
span: this.chartInfo.span,
|
||||
height: this.chartInfo.height,
|
||||
};
|
||||
// 多图模式
|
||||
if (this.chartCount === 'multiple') {
|
||||
this.createChartList = [];
|
||||
this.seriesData.forEach((queryItem) => {
|
||||
const soleParam = Object.assign({}, params);
|
||||
const elements = [];
|
||||
let tagStr = ''; // tag字符串
|
||||
let host = `${queryItem.metric}, `; // 名称
|
||||
const tagsArr = Object.keys(queryItem.tags);
|
||||
// 根据图表展示时获取的tag进行组装名称以及tag字符串
|
||||
tagsArr.forEach((tag) => {
|
||||
if (tag !== 'uuid') {
|
||||
host += `${tag}=${queryItem.tags[tag]}, `;
|
||||
if (tagStr) {
|
||||
tagStr += `,${tag}=${queryItem.tags[tag]}`;
|
||||
} else {
|
||||
tagStr += `${tag}=${queryItem.tags[tag]}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 图表中每条线的名字,去掉最后的逗号与空格
|
||||
host = host.substring(0, host.length - 2);
|
||||
soleParam.title = host;
|
||||
elements.push({
|
||||
metric: this.elementTarget.metric,
|
||||
tags: tagStr,
|
||||
});
|
||||
soleParam.elements = elements;
|
||||
if (valid) {
|
||||
this.addMultipleChart(soleParam);
|
||||
}
|
||||
});
|
||||
} else if (this.chartCount === 'single') {
|
||||
params.title = this.chartSaveInfo.title;
|
||||
const elements = [];
|
||||
const tagStr = this.tagsToString(this.elementTarget.tagList);
|
||||
elements.push({
|
||||
metric: this.elementTarget.metric,
|
||||
tags: tagStr,
|
||||
});
|
||||
params.elements = elements;
|
||||
if (valid) {
|
||||
this.addCharts(params);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 新建单个图表single
|
||||
addCharts(params) {
|
||||
addCharts(params).then((res) => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.code === 200) {
|
||||
this.$Message.success('添加成功');
|
||||
this.createModal = false;
|
||||
this.elementTarget = {};
|
||||
this.saveDisabled = true; // 创建成功后,不能再次创建
|
||||
// this.initInfo();
|
||||
this.$Modal.confirm({
|
||||
title: '创建成功',
|
||||
content: `是否前去看板:${this.panelItem.name},查看创建的图表`,
|
||||
onOk: () => {
|
||||
this.$router.push({
|
||||
path: `/console/panel/detail/${this.panelId}/${this.productId}`,
|
||||
query: {
|
||||
product: this.$route.query.product,
|
||||
panel: this.panelItem.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
onCancel: () => {
|
||||
this.cancel();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.$Message.error(`创建失败:${res.data.message || res.statusText}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 创建多个图表
|
||||
addMultipleChart(params) {
|
||||
this.createChartList.push(params);
|
||||
if (this.seriesData.length === this.createChartList.length) {
|
||||
const api = [];
|
||||
this.createChartList.forEach((item) => {
|
||||
api.push(addCharts(item));
|
||||
});
|
||||
axios.all(api).then((res) => {
|
||||
let successFlag = true;
|
||||
res.forEach((item) => {
|
||||
if (item.data.code !== 200) {
|
||||
successFlag = false;
|
||||
}
|
||||
});
|
||||
if (successFlag) {
|
||||
this.saveDisabled = true; // 创建成功后,不能再次创建
|
||||
this.$Message.success('添加成功');
|
||||
this.createModal = false;
|
||||
this.elementTarget = {};
|
||||
this.createChartList = [];
|
||||
this.$Modal.confirm({
|
||||
title: '创建成功',
|
||||
content: `是否前去看板:${this.panelItem.name},查看创建的图表`,
|
||||
onOk: () => {
|
||||
this.$router.push({
|
||||
path: `/console/panel/detail/${this.panelId}/${this.productId}`,
|
||||
query: {
|
||||
product: this.$route.query.product,
|
||||
panel: this.panelItem.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.$Message.error('添加失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
// 增加指标,tarNum
|
||||
addTarget() {
|
||||
this.elements.push(1);
|
||||
},
|
||||
// 获取metric列表
|
||||
getSuggestMetric(id) {
|
||||
this.$get('metric', {pageNo: 1, pageSize: -1}).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.metricList = response.data.list;
|
||||
}else {
|
||||
this.metricList = [];
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取文本宽度
|
||||
getWidth(str) {
|
||||
const sensor = document.createElement('pre');
|
||||
sensor.innerHTML = str;
|
||||
sensor.style.display = 'inline-block';
|
||||
sensor.style.width = 'auto';
|
||||
sensor.style.visibility = 'hidden';
|
||||
sensor.style.height = 0;
|
||||
sensor.style.position = 'relative';
|
||||
sensor.style['z-index'] = -10;
|
||||
document.body.appendChild(sensor);
|
||||
const width = sensor.offsetWidth;
|
||||
document.body.removeChild(sensor);
|
||||
return width;
|
||||
},
|
||||
// 创建打开
|
||||
createData(panelId) {
|
||||
this.panelId = panelId;
|
||||
this.elementTarget = {}; // 初始化清空参数
|
||||
this.initInfo(); // 初始化图表信息
|
||||
this.chartModal = true;
|
||||
this.initOpen(); // 获取metric, productId数据
|
||||
this.elements = [1];
|
||||
},
|
||||
/*
|
||||
tagsToString(arr) {
|
||||
let str = '';
|
||||
arr.forEach((item, index) => {
|
||||
if (index === 0) {
|
||||
str += item.value.indexOf('*') > -1 ? `${item.name}=*` : `${item.name}=${item.value.join('|')}`;
|
||||
} else {
|
||||
str += item.value.indexOf('*') > -1 ? `,${item.name}=*` : `,${item.name}=${item.value.join('|')}`;
|
||||
}
|
||||
});
|
||||
return str;
|
||||
},
|
||||
*/
|
||||
},
|
||||
mounted() {
|
||||
this.initOpen();
|
||||
/*
|
||||
bus.$on('on-shrink-change', () => {
|
||||
this.preview();
|
||||
});
|
||||
*/
|
||||
},
|
||||
beforeDestroy() {
|
||||
/*
|
||||
bus.$off('on-shrink-change');
|
||||
|
||||
*/
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
@@ -293,7 +293,7 @@
|
||||
},
|
||||
pageObj: {
|
||||
pageNo: 1,
|
||||
pageSize: 9999,//此处获取所有数据,所以设置一个较大的值
|
||||
pageSize: -1,//此处获取所有数据,所以设置一个较大的值
|
||||
total:0
|
||||
},
|
||||
chartsData: [],//中间部分图表相关数据
|
||||
@@ -461,7 +461,7 @@
|
||||
});
|
||||
},
|
||||
getTableData: function() {
|
||||
this.$get('panel').then(response => {
|
||||
this.$get('panel?pageNo=1&pageSize=-1').then(response => {
|
||||
if (response.code === 200) {
|
||||
this.panelData = response.data.list;
|
||||
if( response.data.list.length>0 ){
|
||||
|
||||
@@ -118,6 +118,38 @@ export default new Vue({
|
||||
});
|
||||
return fm;
|
||||
},
|
||||
// 格式化tag为字符串表达式
|
||||
tagsToString(metric,arr) {
|
||||
let str = metric;
|
||||
let sepStr = '';
|
||||
arr.forEach((item, index) => {
|
||||
if (index === 0) {
|
||||
str +="{"
|
||||
if(item.value.length===1){
|
||||
str += `${item.name}='${item.value.join('|')}'`;
|
||||
sepStr = ',';
|
||||
}else if(item.value.length>1){
|
||||
str += `${item.name}=~'${item.value.join('|')}'`;
|
||||
sepStr = ',';
|
||||
}
|
||||
} else {
|
||||
if(item.value.length===1){
|
||||
str += sepStr+`${item.name}='${item.value.join('|')}'`;
|
||||
sepStr = ',';
|
||||
}else if(item.value.length>1){
|
||||
str += sepStr+`${item.name}=~'${item.value.join('|')}'`;
|
||||
sepStr = ',';
|
||||
}
|
||||
}
|
||||
});
|
||||
if(str.indexOf('{')>-1){
|
||||
str +="}";
|
||||
}
|
||||
if(str.endsWith('{}')){
|
||||
str = str.substring(0,str.indexOf('{'));
|
||||
}
|
||||
return str;
|
||||
},
|
||||
getStep(startTime,endTime){
|
||||
const start = new Date(startTime);
|
||||
const end = new Date(endTime);
|
||||
|
||||
Reference in New Issue
Block a user