feat:新功能

1 增加图表类型singleStat:新增,修改,删除,全屏,列表显示图表数据,拖拽改变大小,拖拽改变位置,按时间查询,刷新,预览
This commit is contained in:
hyx
2020-05-07 21:02:09 +08:00
parent 7f15d3563d
commit de1b85b236
9 changed files with 1156 additions and 278 deletions

View File

@@ -92,10 +92,19 @@
@on-drag-chart="editChartForDrag" @on-drag-chart="editChartForDrag"
@on-edit-chart-block="editData" @on-edit-chart-block="editData"
:panel-id="filter.panelId" :panel-id="filter.panelId"
:chart-index="index" :chart-index="index"
:editChartId="'editChartId' + item.id"></line-chart-block> :editChartId="'editChartId' + item.id"></line-chart-block>
<chart-single-stat v-if="item.type === 'singleStat'" :ref="'editChart'+item.id" :key="'inner' + item.id"
@on-refresh-data="refreshChart"
@on-search-data="searchData"
@on-remove-chart-block="removeChart"
@on-drag-chart="editChartForDrag"
@on-edit-chart-block="editData"
:panel-id="filter.panelId"
:chart-index="index"
:editChartId="'editChartId' + item.id"></chart-single-stat>
<chart-table v-if="item.type === 'table'" :ref="'editChart'+item.id" :key="'inner' + item.id" <chart-table v-if="item.type === 'table'" :ref="'editChart'+item.id" :key="'inner' + item.id"
@on-refresh-data="refreshChart" @on-refresh-data="refreshChart"
@on-search-data="searchData" @on-search-data="searchData"
@@ -126,6 +135,7 @@ import bus from '../../libs/bus';
import lineChartBlock from './line-chart-block'; import lineChartBlock from './line-chart-block';
import chartTable from './chart-table'; import chartTable from './chart-table';
import chartUrl from './chart-url'; import chartUrl from './chart-url';
import chartSingleStat from './chart-single-stat';
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
export default { export default {
@@ -136,6 +146,7 @@ export default {
lineChartBlock, lineChartBlock,
chartTable, chartTable,
chartUrl, chartUrl,
chartSingleStat,
draggable, draggable,
}, },
data() { data() {
@@ -542,7 +553,6 @@ export default {
this.dataTotalListBak.forEach((item)=>{ this.dataTotalListBak.forEach((item)=>{
chartListTmp.push(item); chartListTmp.push(item);
}); });
//chartListTmp = [...this.dataTotalListBak];
} }
this.dataTotalList = [...chartListTmp]; this.dataTotalList = [...chartListTmp];
@@ -621,10 +631,6 @@ export default {
}; };
if (!param.query) delete param.query; if (!param.query) delete param.query;
//根据panelId获得panel下的所有图表 //根据panelId获得panel下的所有图表
//let searchTitleStr = '';
//if(this.filter.searchName&&this.filter.searchName!=''){
//searchTitleStr = '?title='+this.filter.searchName;
//}
this.$get('panel/'+ params.panelId+'/charts').then(response => { this.$get('panel/'+ params.panelId+'/charts').then(response => {
if (response.code === 200) { if (response.code === 200) {
if(response.data.list){ if(response.data.list){
@@ -651,12 +657,6 @@ export default {
this.dataList = this.dataTotalList; this.dataList = this.dataTotalList;
} }
this.$nextTick(() => { this.$nextTick(() => {
/*
if (this.dataList.length > 0 && this.$refs.editChart) {
this.$refs.editChart.forEach((item, i) => {
item.showLoad(this.dataList[i]);//之后要实现
});
}*/
if (this.dataList.length > 0 ) { if (this.dataList.length > 0 ) {
this.dataList.forEach((item) => { this.dataList.forEach((item) => {
this.$refs['editChart'+item.id][0].showLoad(item);//之后要实现 this.$refs['editChart'+item.id][0].showLoad(item);//之后要实现
@@ -678,12 +678,14 @@ export default {
let chartType = item.type; let chartType = item.type;
if(chartType!=='url'){ if(chartType!=='url'){
if(isSearch){ if(isSearch){
this.getChartDataForSearch(item,realIndex);/// this.getChartDataForSearch(item,realIndex);
//this.getChartData(item, realIndex);
}else { }else {
this.getChartData(item, realIndex); this.getChartData(item, realIndex);
} }
}else { }else {
if (!isSearch && this.$refs['editChart'+item.id] && this.$refs['editChart'+item.id][0]) {
this.$refs['editChart'+item.id][0].showLoad(item);
}
this.setSize(item.span, realIndex); // 设置该图表宽度 this.setSize(item.span, realIndex); // 设置该图表宽度
} }
}); });
@@ -700,6 +702,7 @@ export default {
let filter = chartData.filter; let filter = chartData.filter;
let legend = chartData.legend; let legend = chartData.legend;
let series = chartData.series; let series = chartData.series;
let singleStatRlt = chartData.singleStatRlt;
if(this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0) { if(this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0) {
if (chartItem.type === 'table') {//表格 if (chartItem.type === 'table') {//表格
if (filterType === 'showFullScreen') {//全屏查询 if (filterType === 'showFullScreen') {//全屏查询
@@ -717,12 +720,66 @@ export default {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, series, this.$refs['editChart'+chartItem.id][0].setData(chartItem, series,
panelId, filter, legend,'',errorMsg); panelId, filter, legend,'',errorMsg);
} }
}else if(chartItem.type ==='singleStat'){
if (filterType === 'showFullScreen') {//全屏查询
this.$refs['editChart'+chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter, filterType,errorMsg);
} else {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter,'',errorMsg);
}
} }
} }
}else { }else {
this.getChartData(chartItem, realIndex); this.getChartData(chartItem, realIndex);
} }
}, },
/*
getSingleStatRlt(statistics,result){
let dataArray = [];
if(result){
result.forEach((item)=>{
dataArray.push(item[1]);
})
}
let statisticsRlt = '';
if(dataArray.length>0){
if(statistics==='min'){//min最小值
statisticsRlt = dataArray.reduce(function(a , b){
return b < a ? b : a;
});
}else if(statistics==='max'){// max最大值
statisticsRlt = dataArray.reduce(function(a , b){
return b > a ? b : a;
});
}else if(statistics==='average'){// average平均值
let sum = 0;
dataArray.forEach((item)=>{
sum =Number(sum) + Number(item);
})
statisticsRlt = sum/dataArray.length;
}else if(statistics==='total'){//total总计
dataArray.forEach((item)=>{
statisticsRlt =Number(statisticsRlt) + Number(item);
})
}else if(statistics==='first'){//first第一个值
statisticsRlt = dataArray[0];
}else if(statistics==='last'){// last最后一个值
statisticsRlt = dataArray[dataArray.length-1];
}else if(statistics==='range'){//range : max - min
let min = dataArray.reduce(function(a , b){
return b < a ? b : a;
});
let max = dataArray.reduce(function(a , b){
return b > a ? b : a;
});
statisticsRlt = max-min;
}else if(statistics==='different'){//different : last - first
statisticsRlt = dataArray[dataArray.length-1]-dataArray[0];
}
}
return statisticsRlt;
},*/
// 获取一个图表具体数据,图表信息图表位置index // 获取一个图表具体数据,图表信息图表位置index
getChartData(chartInfo, pos, filterType) { getChartData(chartInfo, pos, filterType) {
const chartItem = chartInfo; const chartItem = chartInfo;
@@ -732,11 +789,6 @@ export default {
// 没有数据的设置提示信息暂无数据-针对每一个图 // 没有数据的设置提示信息暂无数据-针对每一个图
if (len === 0) { if (len === 0) {
this.$nextTick(() => { this.$nextTick(() => {
/*
if(this.$refs.editChart[index]){
this.$refs.editChart[index].setData(chartItem, [], this.filter.panelId, this.filter);//????怎么设置的无数据??
}*/
if(this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0){ if(this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0){
this.$refs['editChart'+chartItem.id][0].setData(chartItem, [], this.filter.panelId, this.filter);//????怎么设置的无数据?? this.$refs['editChart'+chartItem.id][0].setData(chartItem, [], this.filter.panelId, this.filter);//????怎么设置的无数据??
} }
@@ -774,6 +826,7 @@ export default {
axios.all(axiosArr).then((res) => { axios.all(axiosArr).then((res) => {
if (res.length > 0) { if (res.length > 0) {
const series = []; const series = [];
let singleStatRlt = '';
const legend = []; const legend = [];
const tableData = []; const tableData = [];
const sumData = { const sumData = {
@@ -788,102 +841,112 @@ export default {
if (response.status === 'success') { if (response.status === 'success') {
errorMsg = ""; errorMsg = "";
if (response.data.result) { if (response.data.result) {
// console.log(response.data.result)
// 循环处理每个elements下获取的数据列 // 循环处理每个elements下获取的数据列
response.data.result.forEach((queryItem,resIndex) => { if(chartItem.type==='singleStat'){
const seriesItem = { if(response.data.result.length===1){
theData: { let statistics = chartItem.param.statistics;
name: '', if(response.data.result[0].values){
symbol:'emptyCircle', //去掉点 singleStatRlt = bus.getSingleStatRlt(statistics,response.data.result[0].values);
symbolSize:[2,2], }
smooth:true, //曲线变平滑 }else if(response.data.result.length > 1){
showSymbol:false, singleStatRlt = this.$t("dashboard.panel.singleStatErrorTip");
data: [], }
type:chartInfo.type, }else {
}, response.data.result.forEach((queryItem,resIndex) => {
const seriesItem = {
theData: {
name: '',
symbol:'emptyCircle', //去掉点
symbolSize:[2,2],
smooth:true, //曲线变平滑
showSymbol:false,
data: [],
type:chartInfo.type,
},
//visible: true, //visible: true,
//threshold: null, //threshold: null,
metric_name: '', metric_name: '',
}; };
if(chartInfo.type === 'stackArea'){ if(chartInfo.type === 'stackArea'){
seriesItem.theData.type='line'; seriesItem.theData.type='line';
seriesItem.theData.stack=chartInfo.title; seriesItem.theData.stack=chartInfo.title;
seriesItem.theData.areaStyle={"opacity": 0.3}; seriesItem.theData.areaStyle={"opacity": 0.3};
} }
// 图表中每条线的名字,后半部分 // 图表中每条线的名字,后半部分
let host = '';//up, let host = '';//up,
if(queryItem.metric.__name__){
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"]] ]
// 判断是否有数据, && tagsArr.length > 0
if (dpsArr.length > 0 && this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0) {
tagsArr.forEach((tag, i) => {
if (tag !== '__name__') {
host += `${tag}="${queryItem.metric[tag]}",`;
}
});
if(host.endsWith(',')){host = host.substr(0,host.length-1);}
if(queryItem.metric.__name__){ if(queryItem.metric.__name__){
host +="}"; host = `${queryItem.metric.__name__}{`;//up,
} }
if(!host || host===''){ const tagsArr = Object.keys(queryItem.metric);//["__name__","asset","idc","instance","job","module","project"]
host = chartItem.elements[innerPos].expression; // 设置时间-数据格式对
} const dpsArr = Object.entries(queryItem.values);//[ ["0",[1577959830.781,"0"]], ["1",[1577959845.781,"0"]] ]
//处理legend别名 // 判断是否有数据, && tagsArr.length > 0
if (dpsArr.length > 0 && this.$refs['editChart'+chartItem.id] && this.$refs['editChart'+chartItem.id].length>0) {
let alias=this.$refs['editChart'+chartItem.id][0].dealLegendAlias(host,chartItem.elements[innerPos].legend); tagsArr.forEach((tag, i) => {
if(!alias || alias===''){ if (tag !== '__name__') {
alias = chartItem.elements[innerPos].expression; host += `${tag}="${queryItem.metric[tag]}",`;
} }
if(alias){
host = alias;
}
legend.push({name:host+resIndex,alias:alias});
// 图表中每条线的名字,去掉最后的逗号与空格:metric名称, 标签1=a,标签2=c
seriesItem.theData.name = host+resIndex;
//alert(seriesItem.theData.name);
seriesItem.metric_name = seriesItem.theData.name;
// 将秒改为毫秒
//alert('table=='+JSON.stringify(queryItem))
seriesItem.theData.data = queryItem.values.map((dpsItem, dpsIndex) => {
/*曲线汇总暂不需要
if (sumData.data[dpsIndex]) {
const sumNum = sumData.data[dpsIndex][1] || 0;
sumData.data[dpsIndex][1] = sumNum + dpsItem[1];
} else {
sumData.data[dpsIndex] = [dpsItem[0] * 1000, dpsItem[1]];
}
*/
let t_date = new Date(dpsItem[0] * 1000);
let timeTmp = bus.timeFormate(t_date, 'yyyy-MM-dd hh:mm:ss');
tableData.push({//表格数据
// label: host.slice(host.indexOf('{') + 1,host.indexOf('}')),//label
// metric: queryItem.metric.__name__?queryItem.metric.__name__:'',//metric列
element:{element:host,alias:alias},
time: timeTmp,//采集时间
value: dpsItem[1],//数值
}); });
return [dpsItem[0] * 1000, dpsItem[1]]; if(host.endsWith(',')){host = host.substr(0,host.length-1);}
}); if(queryItem.metric.__name__){
series.push(seriesItem.theData); host +="}";
}
if(!host || host===''){
host = chartItem.elements[innerPos].expression;
}
//处理legend别名
} else if (chartItem.elements && chartItem.elements[innerPos]) { let alias=this.$refs['editChart'+chartItem.id][0].dealLegendAlias(host,chartItem.elements[innerPos].legend);
// 无数据提示 if(!alias || alias===''){
/* alias = chartItem.elements[innerPos].expression;
const currentInfo = chartItem.elements[innerPos]; }
const errorMsg = `图表 ${chartItem.title} 中 ${currentInfo.metric},${currentInfo.tags} 无数据`; if(alias){
this.$message.warning({ host = alias;
duration: 15, }
content: errorMsg, legend.push({name:host+resIndex,alias:alias});
closable: true, // 图表中每条线的名字,去掉最后的逗号与空格:metric名称, 标签1=a,标签2=c
}); seriesItem.theData.name = host+resIndex;
*/ //alert(seriesItem.theData.name);
} seriesItem.metric_name = seriesItem.theData.name;
}); // 将秒改为毫秒
//alert('table=='+JSON.stringify(queryItem))
seriesItem.theData.data = queryItem.values.map((dpsItem, dpsIndex) => {
/*曲线汇总暂不需要
if (sumData.data[dpsIndex]) {
const sumNum = sumData.data[dpsIndex][1] || 0;
sumData.data[dpsIndex][1] = sumNum + dpsItem[1];
} else {
sumData.data[dpsIndex] = [dpsItem[0] * 1000, dpsItem[1]];
}
*/
let t_date = new Date(dpsItem[0] * 1000);
let timeTmp = bus.timeFormate(t_date, 'yyyy-MM-dd hh:mm:ss');
tableData.push({//表格数据
// label: host.slice(host.indexOf('{') + 1,host.indexOf('}')),//label
// metric: queryItem.metric.__name__?queryItem.metric.__name__:'',//metric列
element:{element:host,alias:alias},
time: timeTmp,//采集时间
value: dpsItem[1],//数值
});
return [dpsItem[0] * 1000, dpsItem[1]];
});
series.push(seriesItem.theData);
} else if (chartItem.elements && chartItem.elements[innerPos]) {
// 无数据提示
/*
const currentInfo = chartItem.elements[innerPos];
const errorMsg = `图表 ${chartItem.title} 中 ${currentInfo.metric},${currentInfo.tags} 无数据`;
this.$message.warning({
duration: 15,
content: errorMsg,
closable: true,
});
*/
}
});
}
} }
}else{ }else{
if(response.msg){ if(response.msg){
@@ -903,6 +966,7 @@ export default {
const chartData = { const chartData = {
chartItem:chartItem, chartItem:chartItem,
series:series, series:series,
singleStatRlt:singleStatRlt,
legend:legend, legend:legend,
tableData:tableData, tableData:tableData,
panelId:this.filter.panelId, panelId:this.filter.panelId,
@@ -930,6 +994,14 @@ export default {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, series, this.$refs['editChart'+chartItem.id][0].setData(chartItem, series,
this.filter.panelId, this.filter, legend,'',errorMsg); this.filter.panelId, this.filter, legend,'',errorMsg);
} }
} else if(chartItem.type ==='singleStat'){
if (filterType === 'showFullScreen') {//全屏查询
this.$refs['editChart'+chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter, filterType,errorMsg);
} else {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter,'',errorMsg);
}
} }
} }
} else { } else {
@@ -951,6 +1023,14 @@ export default {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, [], this.filter.panelId, this.$refs['editChart'+chartItem.id][0].setData(chartItem, [], this.filter.panelId,
this.filter); this.filter);
} }
}else if(chartItem.type ==='singleStat'){
if (filterType === 'showFullScreen') {//全屏查询
this.$refs['editChart'+chartItem.id][0].setData(chartItem, '',
this.filter.panelId, this.filter, filterType);
} else {
this.$refs['editChart'+chartItem.id][0].setData(chartItem, '',
this.filter.panelId, this.filter);
}
} }
} }
} }

View File

@@ -0,0 +1,182 @@
/* ---------edit-chart-move--------- */
.clearfix:after{
display: block;
content: "";
clear: both;
}
.clearfix{
margin-bottom: 10px;
}
.loading-font{
color:#232f3e !important;
}
.dialog-tool {
margin-right: 40px;
}
.hidden{
visibility: hidden;
}
.visible{
visibility: visible;
}
.nz-chart-dropdown {
height: 147px;
li {
/*padding: 0 20px !important;*/
padding-left:15px !important;
padding-right:0px !important;
width:140px;
text-align: left;
i {
margin-right: 10px;
}
}
}
.chart-single-stat {
width: 100%;
height: 100%;//calc(100% - 40px);
position: relative;
background: #FFF;
border: 1px solid #d8dce1;
padding: 0px 0px;
margin-bottom: 10px;
padding-bottom: 3px;
.single-stat-container{
padding-left: 8px;
padding-right: 8px;
display:table;
text-align:center;
width:calc(100% - 16px);
.single-stat-content{
text-align:center;
vertical-align: middle;
display:table-cell;
font-size:30px;
}
}
.single-stat-screen-container{
height:100%;
display:table;
text-align:center;
width:calc(100% - 16px);
color:#000;
.single-stat-content{
text-align:center;
vertical-align: middle;
display:table-cell;
font-size:30px;
}
}
.vue-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
cursor: se-resize;
box-sizing: border-box;
}
.vue-resizable-handle:after {
border-right: 2px solid #555;
border-bottom: 2px solid #555;
content: "";
position: absolute;
right: 3px;
bottom: 3px;
width: 5px;
height: 5px;
box-sizing: inherit;
}
.chartTitle:hover {
background-color:#d8dce1;
}
.dragTitle{
background-color:#d8dce1;
}
.chartTitle {
text-align: center;
width: 100%;
line-height: 28px;
.nz-chart-top{
width:100%;
}
.el-dropdown-link {
cursor: move;
}
.el-icon-arrow-down {
font-size: 12px;
}
.chart-title {
font-weight: bold;
font-size: 18px;
line-height: 26px;
color: #333;
margin: -3px 0 3px 3px;
display:flex;
justify-content:center;
align-items:center;
.chart-title-text{
max-width:calc(100% - 20px);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
cursor: pointer;
}
.chart-title-icon{
display: inline-block;
cursor: pointer;
}
}
}
.edit:after{
display: block;
content: "";
clear: both;
}
.button-panel-height{
height:26px;
}
.button-panel-height button{
height:26px;
}
.edit {
position: absolute;
right: 20px;
top: 17px;
z-index: 10;
}
.chart-select {
position: absolute;
left: 40px;
top: 25px;
z-index: 10;
font-size: 14px;
.chart-select-btn {
margin-right: 10px;
cursor: pointer;
&.active {
color: #5aacff;
}
}
}
/*没有数据显示*/
.null {
position: absolute;
top: 50%;
width: 100%;
text-align: center;
font-size: 24px;
font-weight: 600;
}
.element-bottom-border {
border-bottom: 1px solid #dfe7f2;
margin-bottom:-20px;
}
.element-top-border {
padding-top: 10px;
border-top: 1px solid #dfe7f2;
margin-top:-25px;
}
}

View File

@@ -0,0 +1,428 @@
<style lang="scss" scoped>
@import './chart-single-stat.scss';
</style>
<style>
.max-width-90{
max-width: 90px;
}
</style>
<template>
<div class="chart-single-stat" :id="'chartSingleStatDiv'+chartIndex" v-show="divFirstShow" @mouseenter="caretShow=true" @mouseleave="caretShow=false">
<loading :ref="'localLoading'+chartIndex"></loading>
<div class="clearfix chartTitle" :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>
<el-dropdown trigger="click" v-show="firstShow" class="nz-chart-top" :key="'chartDropdown'+chartIndex" v-clickoutside="clickos">
<el-dropdown-menu style="display: none"></el-dropdown-menu>
<span class="el-dropdown-link chart-title" @click="dropdownMenuShow=!dropdownMenuShow">
<span class="chart-title-text">{{data.title}}</span>
<span class="chart-title-icon"><i class="el-icon-caret-bottom el-icon--right" :class="{'visible':caretShow,'hidden':!caretShow}"></i></span>
</span>
<ul slot="dropdown" v-show="dropdownMenuShow" :id="'dropdownUl'+chartIndex" class="el-dropdown-menu nz-chart-dropdown" style="position: absolute; top: 30px; left: calc(50% - 79px); transform-origin: center top; z-index: 1000;" >
<li @click="refreshChart" class="el-dropdown-menu__item">
<i class="global-active-color el-icon-refresh-right" style="font-size: 16px;"></i><span>{{$t('dashboard.refresh')}}</span></li>
<li @click="editChart" class="el-dropdown-menu__item">
<i class="nz-icon nz-icon-edit" style="font-size: 14px; margin-right: 11px; margin-left: 1px;"></i>{{$t('dashboard.edit')}}</li>
<li @click="removeChart" class="el-dropdown-menu__item">
<i class="el-icon-delete" style="font-size: 16px;"></i>{{$t('dashboard.delete')}}</li>
<li @click="showAllScreen" class="el-dropdown-menu__item">
<i class="el-icon-full-screen" style="font-size: 16px;"></i>{{$t('dashboard.screen')}}</li>
</ul>
</el-dropdown>
</div>
<div class="mt-10 single-stat-container" v-cloak v-show="firstShow" >
<div :id="'chartContainer'+chartIndex" ref="chartContainer" class="single-stat-content" >
{{serieSingleStat}}
</div>
</div>
<!--全屏-->
<el-dialog class="nz-dialog table-chart-dialog" :title="$t('dashboard.panel.view')"
:visible.sync="screenModal"
width="96%" @close="screenModal = false" >
<div slot="title">
<span class="nz-dialog-title">{{data.title}}</span>
<div class="float-right panel-calendar dialog-tool">
<time-picker ref="calendarPanel" class="nz-dashboard-picker" style="margin-top: -12px;" @change="dateChange"></time-picker>
</div>
</div>
<div class="single-stat-screen-container" >
<div id="chartScreenContainer" ref="chartScreenContainer" class="single-stat-content" >
{{serieSingleStat}}
</div>
</div>
<loading :ref="'localLoadingScreen'+chartIndex"></loading>
</el-dialog>
<span class="vue-resizable-handle" @mousedown="dragResize"></span>
</div>
</template>
<script>
import bus from '../../libs/bus';
import {Loading} from 'element-ui';
import chartDataFormat from './chartDataFormat'
import loading from "../common/loading";
import timePicker from '../common/timePicker'
export default {
name: 'chartSingleStat',
components: {
'loading': loading,
'time-picker':timePicker
},
props: {
// 看板id
panelId: {
type: Number,
default: 0,
},
editChartId: {
type: String,
default: 'editChartId',
},
chartIndex:{
type: Number,
default: 0,
}
},
data() {
return {
data: {}, // 该图表信息,chartItem
unit:{},
isError:false,
errorContent:'',
seriesItem: [], // 保存信息
seriesItemScreen:[],//全屏数据
serieSingleStat:'',
images: '',
//toolbox: false,
loading:Object,
items: {
metric_name: [], // 每条数据列名称
xAxis: [],
theData: [], // series数据组
},
panelIdInner: '', // 看板id=panelId,原写作chart,由set_data获取
firstLoad: false, // 是否第一次加载
//showLoading:true,
//showLoadingScreen:false,
//showTable:true,
chartType: 'table', // 图表类型
screenModal: false,
// 查询数据使用
filter: {
start_time: '',
end_time: '',
},
stableFilter: {}, // 保存数据使用,初始化起止时间,单图or多图等
firstShow: false, // 默认不显示操作按钮,
caretShow:false,
dragTitleShow:false,
dropdownMenuShow:false,
minHeight:200,
chartSpaceHeight:5,//top-border: 1,bottom-border: 1,padding-bottome:3
titleHeight:38,//title-height:28,magrin-bottom:10
divFirstShow:false,
searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],//全屏显示的时间
oldSearchTime: [],
};
},
created() {
},
computed: {},
watch: {},
methods: {
dragResize:function(e){
var diffWidth =20; //界面的宽度空白的地方的宽度
var chartBoxPadding = 22;
var targetDiv= document.getElementById('chartSingleStatDiv'+this.chartIndex); //e.target.parentNode.parentNode;.children[0]
var targetDivContainer= document.getElementById('listContainer'); //e.target.parentNode.parentNode;.children[0]
var maxWidth = targetDivContainer.offsetWidth-diffWidth;
var minWidth = maxWidth/12;
var stepWidth = maxWidth/12;
var stepHeight = 10;
//得到点击时该容器的宽高:
var targetDivHeight=targetDiv.offsetHeight;
var targetDivWidth=targetDiv.offsetWidth;
var startY=e.clientY;
var startX=e.clientX;
var _this=this;
document.onmousemove=function(e){
e.preventDefault();
//得到鼠标拖动的宽高距离:取绝对值
var distY=Math.abs(e.clientY-startY);
var distX=Math.abs(e.clientX-startX);
//往上方拖动:
if( e.clientY < startY){
targetDiv.style.height=targetDivHeight-distY+'px';
//heightTmp = targetDivHeight-distY;
}
if( e.clientX < startX){
targetDiv.style.width=targetDivWidth-distX+'px';
//widthTmp = targetDivWidth-distX;
}
//往下方拖动:
if (e.clientY > startY) {
targetDiv.style.height=(targetDivHeight+distY)+'px';
//heightTmp = targetDivHeight+distY;
}
if (e.clientX > startX) {
targetDiv.style.width=(targetDivWidth+distX)+'px';
//widthTmp = targetDivWidth+distX;
}
if(parseInt(targetDiv.style.height)<=_this.minHeight){
targetDiv.style.height=_this.minHeight+'px';
//heightTmp = _this.minHeight;
}
if(parseInt(targetDiv.style.width)>=maxWidth){
targetDiv.style.width=maxWidth+'px';
//widthTmp = maxWidth;
}
if(parseInt(targetDiv.style.width)<=minWidth){
targetDiv.style.width=minWidth+'px';
//widthTmp = minWidth;
}
//调整表格大小
let containerHeight = parseInt(targetDiv.style.height);
let containerWidth = parseInt(targetDiv.style.width);
const chartBox = document.getElementsByClassName('chartBox');
chartBox[_this.chartIndex].style.width = (containerWidth+chartBoxPadding)+'px';
//chartBox[_this.chartIndex].style.height = `${containerHeight}px`;
//表格的高度
const tableBox = document.getElementById('chartContainer'+_this.chartIndex);
tableBox.style.height = `${containerHeight-_this.titleHeight}px`;//-75-32+25
}
document.onmouseup=function(){
let targetDivHeightNew = parseInt(targetDiv.style.height);
//let targetDivHeightNew = heightTmp
let targetDivWidthNew = parseInt(targetDiv.style.width);
//let targetDivWidthNew = widthTmp;
let diffHeight = Math.abs(targetDivHeight-targetDivHeightNew);
if(targetDivHeight>targetDivHeightNew){
let finalDiffHeight = Math.floor(diffHeight/stepHeight)*stepHeight;
//alert('oldWidth='+targetDivHeight+"===diffHeight+"+diffHeight+"==finalDiffHeight="+finalDiffHeight);
targetDiv.style.height = (targetDivHeight-finalDiffHeight)+'px';
}
if(targetDivHeight<targetDivHeightNew){
let finalDiffHeight = Math.ceil(diffHeight/stepHeight)*stepHeight;
targetDiv.style.height = (targetDivHeight+finalDiffHeight)+'px';
}
var span = _this.data.span;
if(targetDivWidth>targetDivWidthNew){
span = Math.floor((targetDivWidthNew*12)/maxWidth);
let finalWidth = Math.floor((targetDivWidthNew*12)/maxWidth)*stepWidth;
if((finalWidth)<minWidth){
targetDiv.style.width=minWidth+'px';
span = 1;
}else {
targetDiv.style.width = finalWidth+'px';
}
}
if(targetDivWidth<targetDivWidthNew){
span = Math.ceil((targetDivWidthNew*12)/maxWidth);
let spanUnit = Math.ceil((targetDivWidthNew*12)/maxWidth);
let finalWidth = spanUnit*stepWidth;
if(finalWidth>maxWidth || spanUnit===12){
targetDiv.style.width=maxWidth+'px';
span = 12;
}else {
targetDiv.style.width = finalWidth+'px';
}
}
//调整表格大小
let containerHeight = parseInt(targetDiv.style.height);
let containerWidth = parseInt(targetDiv.style.width);
const chartBox = document.getElementsByClassName('chartBox');
chartBox[_this.chartIndex].style.width = (containerWidth+chartBoxPadding)+'px';
//chartBox[_this.chartIndex].style.height = `${containerHeight}px`;
//表格的高度
const tableBox = document.getElementById('chartContainer'+_this.chartIndex);
tableBox.style.height = `${containerHeight-_this.titleHeight}px`;
const modifyParams = {
id:_this.data.id,
span:span,
height:(containerHeight+_this.chartSpaceHeight),
prev:parseInt(_this.data.prev),
next:parseInt(_this.data.next),
}
_this.$put('panel/'+ _this.panelIdInner+'/charts/modify',modifyParams).then(response => {
if (response.code === 200) {
//更新当前图表数据
_this.data.span= span;
_this.data.height= containerHeight+_this.chartSpaceHeight;
_this.$emit('on-drag-chart', _this.data);
}else {
if(response.msg){
_this.$message.error(response.msg);
}else if(response.error){
_this.$message.error(response.error);
}else {
_this.$message.error(response);
}
}
});
document.onmousemove=null;
document.onmouseup = null;
}
},
startLoading(area){
if(area==='screen'){
this.$refs['localLoadingScreen'+this.chartIndex].startLoading();
}else {
//this.showLoading = true;
this.$refs['localLoading'+this.chartIndex].startLoading();
}
},
endLoading(area){
if(area==='screen'){
//this.showLoadingScreen = false;
this.$refs['localLoadingScreen'+this.chartIndex].endLoading();
}else {
//this.showLoading = false;
this.$refs['localLoading'+this.chartIndex].endLoading();
}
},
clearData(){
},
showLoad(chartItem) {
//设置高度 chart-table
this.$nextTick(() => {
const chartBox = document.getElementById('chartSingleStatDiv'+this.chartIndex);
let height = chartItem.height;
if(height<this.minHeight){
height = this.minHeight;
}
chartBox.style.height = `${height-this.chartSpaceHeight}px`;
const singleStatBox = document.getElementById('chartContainer'+this.chartIndex);
singleStatBox.style.height = `${height-this.chartSpaceHeight-this.titleHeight}px`;// -75-32
});
this.startLoading();
this.divFirstShow = true;
},
// 重新请求数据 刷新操作-local
refreshChart() {
this.dropdownMenuShow=false;
this.startLoading();
this.firstShow = false;
this.$emit('on-refresh-data', this.data.id);
},
// 编辑图表
editChart() {
this.dropdownMenuShow=false;
this.$emit('on-edit-chart-block', this.data.id);
},
// 删除该图表
removeChart() {
this.dropdownMenuShow=false;
this.$emit('on-remove-chart-block', this.data.id);
},
//全屏时间条件查询
dateChange(time) {
this.searchTime = [...time];
this.seriesItemScreen = [];
this.serieSingleStat = "";
this.startLoading('screen');
this.$emit('on-search-data', this.data.id, this.searchTime);
},
clickos() {
this.dropdownMenuShow=false;
},
clearChart(){
this.data = {};
},
// 全屏查看
showAllScreen() {
this.dropdownMenuShow=false;
this.searchTime = [];
this.$set(this.searchTime, 0, this.oldSearchTime[0]);
this.$set(this.searchTime, 1, this.oldSearchTime[1]);
this.$refs.calendarPanel.setCustomTime(this.searchTime);
this.seriesItemScreen = this.seriesItem;
this.screenModal = true;
},
// 设置数据, filter区分
setData(chartItem, seriesItem, panelId, filter,area,errorMsg) {
if(errorMsg && errorMsg!==''){
this.isError = true;
this.errorContent = errorMsg;
}else {
this.isError = false;
this.errorContent = '';
}
if(area==='showFullScreen'){//全屏按时间查询
this.data = chartItem;
this.unit = chartDataFormat.getUnit(this.data.unit);
if(Number(seriesItem)){
let singleStatTmp =parseFloat(Number(seriesItem).toFixed(2));
this.serieSingleStat = chartDataFormat.getUnit(chartItem.unit?chartItem.unit:2).compute(singleStatTmp,null,2);
}else {
this.serieSingleStat =seriesItem;
}
this.searchTime[0] = filter.start_time;//将列表的查询时间复制给全屏的查询时间
this.searchTime[1] = filter.end_time;
this.endLoading('screen');
}else{
//设置高度 chart-table
this.$nextTick(() => {
const chartBox = document.getElementById('chartSingleStatDiv'+this.chartIndex);
let height = chartItem.height;
if(height<this.minHeight){
height = this.minHeight;
}
chartBox.style.height = `${height-this.chartSpaceHeight}px`;
const singleStatBox = document.getElementById('chartContainer'+this.chartIndex);
singleStatBox.style.height = `${height-this.chartSpaceHeight-this.titleHeight}px`;// -75-32
});
this.divFirstShow = true;
this.firstShow = true; // 展示操作按键
this.panelIdInner = panelId;
this.data = chartItem;
this.unit = chartDataFormat.getUnit(this.data.unit);
if(Number(seriesItem)){
let singleStatTmp =parseFloat(Number(seriesItem).toFixed(2));
this.serieSingleStat = chartDataFormat.getUnit(chartItem.unit?chartItem.unit:2).compute(singleStatTmp,null,2);
}else {
this.serieSingleStat =seriesItem;
}
if (filter) { // 保存数据,用于同步时间
this.searchTime[0] = filter.start_time;//将列表的查询时间复制给全屏的查询时间
this.searchTime[1] = filter.end_time;
this.oldSearchTime[0] = this.searchTime[0];
this.oldSearchTime[1] = this.searchTime[1];
}
this.endLoading();
}
},
},
mounted() {
this.firstLoad = false;
},
beforeDestroy() {
this.clearChart();
},
};
</script>

View File

@@ -72,6 +72,18 @@
</div> </div>
</template> </template>
<template v-if="chart.type==='singleStat'">
<div id="chartSingleStatPreview" @mouseenter="mouseEnterFullChart" @mouseleave="mouseLeaveFullChart"
style=" height:100%;display:table;text-align:center;width:calc(100% - 16px);color:#000;" >
<div class="line-area" ref="singleStatArea" id="singleStatArea" style="margin-top:0px; text-align:center;
vertical-align: middle;
display:table-cell;
font-size:30px;">
{{serieSingleStat}}
</div>
</div>
</template>
<template v-if="chart.type==='table'"> <template v-if="chart.type==='table'">
<div id="chartTablePreview" :class="{'visible':tableShow,'hidden':!tableShow}" > <div id="chartTablePreview" :class="{'visible':tableShow,'hidden':!tableShow}" >
<el-table id="tableContainer" style="margin-top: 10px;" class="nz-table" height="95%" :data="seriesItemScreen" border tooltip-effect="light" v-scrollBar:el-table > <el-table id="tableContainer" style="margin-top: 10px;" class="nz-table" height="95%" :data="seriesItemScreen" border tooltip-effect="light" v-scrollBar:el-table >
@@ -130,6 +142,7 @@
//seriesItem: [], // 保存信息 //seriesItem: [], // 保存信息
isError:false, isError:false,
errorContent:'', errorContent:'',
serieSingleStat:'',
seriesItemScreen:[], seriesItemScreen:[],
pageSizes:[50,100,200], pageSizes:[50,100,200],
screenPageObj:{ screenPageObj:{
@@ -175,89 +188,6 @@
chartSpaceHeight:5,//top-border: 1,bottom-border: 1,padding-bottome:3 chartSpaceHeight:5,//top-border: 1,bottom-border: 1,padding-bottome:3
titleHeight:50, titleHeight:50,
legendHeight:80, legendHeight:80,
//oldChartBoxCss:'',
/*
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]);
}
}]
},*/
}; };
}, },
computed: { computed: {
@@ -282,6 +212,8 @@
}else if(chartType==='url'){ }else if(chartType==='url'){
this.urlShow = false; this.urlShow = false;
chartContainerId = 'chartUrlPreview'; chartContainerId = 'chartUrlPreview';
}else if (chartType === 'singleStat') {
chartContainerId = 'chartSingleStatPreview';
} }
//设置高度 chart-table //设置高度 chart-table
@@ -376,6 +308,9 @@
this.setTableData([]); this.setTableData([]);
} else if (chartItem.type === 'line' || chartItem.type === 'bar' || chartItem.type === 'stackArea' || chartItem.type === 4) { } else if (chartItem.type === 'line' || chartItem.type === 'bar' || chartItem.type === 'stackArea' || chartItem.type === 4) {
this.setData(chartItem, []); this.setData(chartItem, []);
}else if(chartItem.type ==='singleStat'){
this.serieSingleStat = "";
this.$refs.loadingPreview.endLoading();
} }
}); });
} else { } else {
@@ -399,6 +334,7 @@
axios.all(axiosArr).then((res) => { axios.all(axiosArr).then((res) => {
if (res.length > 0) { if (res.length > 0) {
const series = []; const series = [];
let singleStatRlt = '';
const legend = []; const legend = [];
const tableData = []; const tableData = [];
const sumData = { const sumData = {
@@ -412,89 +348,101 @@
this.isError = false; this.isError = false;
this.errorContent = ""; this.errorContent = "";
if (response.data.result) { if (response.data.result) {
// console.log(response.data.result) if(chartItem.type==='singleStat'){
// 循环处理每个elements下获取的数据列 if(response.data.result.length===1){
response.data.result.forEach((queryItem,resInnerPos) => { let statistics = chartItem.param.statistics;
const seriesItem = { if(response.data.result[0].values){
theData: { singleStatRlt = bus.getSingleStatRlt(statistics,response.data.result[0].values);
name: '', }
symbol:'emptyCircle', //去掉点 }else if(response.data.result.length > 1){
symbolSize:[2,2], singleStatRlt = this.$t("dashboard.panel.singleStatErrorTip");
smooth:true, //曲线变平滑
showSymbol:false,
data: [],
type:chartItem.type,
},
metric_name: '',
};
if(chartItem.type === 'stackArea'){
seriesItem.theData.type='line';
seriesItem.theData.stack=chartItem.title;
seriesItem.theData.areaStyle={"opacity": 0.3};
} }
// 图表中每条线的名字,后半部分 }else {
let host = '';//up, // 循环处理每个elements下获取的数据列
if(queryItem.metric.__name__){ response.data.result.forEach((queryItem, resInnerPos) => {
host = `${queryItem.metric.__name__}{`;//up, const seriesItem = {
} theData: {
const tagsArr = Object.keys(queryItem.metric);//["__name__","asset","idc","instance","job","module","project"] name: '',
// 设置时间-数据格式对 symbol: 'emptyCircle', //去掉点
const dpsArr = Object.entries(queryItem.values);//[ ["0",[1577959830.781,"0"]], ["1",[1577959845.781,"0"]] ] symbolSize: [2, 2],
// 判断是否有数据, && tagsArr.length > 0 smooth: true, //曲线变平滑
if (dpsArr.length > 0 ) { showSymbol: false,
tagsArr.forEach((tag, i) => { data: [],
if (tag !== '__name__') { type: chartItem.type,
host += `${tag}="${queryItem.metric[tag]}",`; },
} metric_name: '',
}); };
if(host.endsWith(',')){host = host.substr(0,host.length-1);} if (chartItem.type === 'stackArea') {
if(queryItem.metric.__name__){ seriesItem.theData.type = 'line';
host +="}"; seriesItem.theData.stack = chartItem.title;
seriesItem.theData.areaStyle = {"opacity": 0.3};
} }
if(!host || host===''){ // 图表中每条线的名字,后半部分
host = chartItem.elements[innerPos].expression; let host = '';//up,
if (queryItem.metric.__name__) {
host = `${queryItem.metric.__name__}{`;//up,
} }
//处理legend别名 const tagsArr = Object.keys(queryItem.metric);//["__name__","asset","idc","instance","job","module","project"]
let alias=this.dealLegendAlias(host,chartItem.elements[innerPos].legend); // 设置时间-数据格式对
if(!alias || alias===''){ const dpsArr = Object.entries(queryItem.values);//[ ["0",[1577959830.781,"0"]], ["1",[1577959845.781,"0"]] ]
alias = chartItem.elements[innerPos].expression; // 判断是否有数据, && tagsArr.length > 0
} if (dpsArr.length > 0) {
if(alias){ tagsArr.forEach((tag, i) => {
host = alias; if (tag !== '__name__') {
} host += `${tag}="${queryItem.metric[tag]}",`;
legend.push({name:host+resInnerPos,alias:alias}); }
// 图表中每条线的名字,去掉最后的逗号与空格:metric名称, 标签1=a,标签2=c
seriesItem.theData.name = host+resInnerPos;
seriesItem.metric_name = seriesItem.theData.name;
// 将秒改为毫秒
//alert('table=='+JSON.stringify(queryItem))
seriesItem.theData.data = queryItem.values.map((dpsItem, dpsIndex) => {
let t_date = new Date(dpsItem[0] * 1000);
let timeTmp = bus.timeFormate(t_date, 'yyyy-MM-dd hh:mm:ss');
tableData.push({//表格数据
// label: host.slice(host.indexOf('{') + 1,host.indexOf('}')),//label
// metric: queryItem.metric.__name__?queryItem.metric.__name__:'',//metric列
element:{element:host,alias:alias},
time: timeTmp,//采集时间
value: dpsItem[1],//数值
}); });
return [dpsItem[0] * 1000, dpsItem[1]]; if (host.endsWith(',')) {
}); host = host.substr(0, host.length - 1);
series.push(seriesItem.theData); }
if (queryItem.metric.__name__) {
host += "}";
}
if (!host || host === '') {
host = chartItem.elements[innerPos].expression;
}
//处理legend别名
let alias = this.dealLegendAlias(host, chartItem.elements[innerPos].legend);
if (!alias || alias === '') {
alias = chartItem.elements[innerPos].expression;
}
if (alias) {
host = alias;
}
legend.push({name: host + resInnerPos, alias: alias});
// 图表中每条线的名字,去掉最后的逗号与空格:metric名称, 标签1=a,标签2=c
seriesItem.theData.name = host + resInnerPos;
seriesItem.metric_name = seriesItem.theData.name;
// 将秒改为毫秒
//alert('table=='+JSON.stringify(queryItem))
seriesItem.theData.data = queryItem.values.map((dpsItem, dpsIndex) => {
let t_date = new Date(dpsItem[0] * 1000);
let timeTmp = bus.timeFormate(t_date, 'yyyy-MM-dd hh:mm:ss');
tableData.push({//表格数据
// label: host.slice(host.indexOf('{') + 1,host.indexOf('}')),//label
// metric: queryItem.metric.__name__?queryItem.metric.__name__:'',//metric列
element: {element: host, alias: alias},
time: timeTmp,//采集时间
value: dpsItem[1],//数值
});
return [dpsItem[0] * 1000, dpsItem[1]];
});
series.push(seriesItem.theData);
} else if (chartItem.elements && chartItem.elements[innerPos]) { } else if (chartItem.elements && chartItem.elements[innerPos]) {
// 无数据提示 // 无数据提示
/* /*
const currentInfo = chartItem.elements[innerPos]; const currentInfo = chartItem.elements[innerPos];
const errorMsg = `图表 ${chartItem.title} 中 ${currentInfo.metric},${currentInfo.tags} 无数据`; const errorMsg = `图表 ${chartItem.title} 中 ${currentInfo.metric},${currentInfo.tags} 无数据`;
this.$message.warning({ this.$message.warning({
duration: 15, duration: 15,
content: errorMsg, content: errorMsg,
closable: true, closable: true,
}); });
*/ */
} }
}); });
}
} }
}else{ }else{
alert('error') alert('error')
@@ -515,6 +463,14 @@
if (series.length && chartItem.type === 4) {//曲线汇总 if (series.length && chartItem.type === 4) {//曲线汇总
} }
this.setData(chartItem, series, legend); this.setData(chartItem, series, legend);
}else if(chartItem.type ==='singleStat'){
if(Number(singleStatRlt)){
let singleStatTmp =parseFloat(Number(singleStatRlt).toFixed(2));
this.serieSingleStat = chartDataFormat.getUnit(chartItem.unit?chartItem.unit:2).compute(singleStatTmp,null,2);
}else {
this.serieSingleStat =singleStatRlt;
}
this.$refs.loadingPreview.endLoading();
} }
//} //}
} else { } else {
@@ -524,6 +480,9 @@
this.setTableData([]); this.setTableData([]);
} else if (type === 'line' || type === 'bar' || type === 'stackArea' || type === 4) { } else if (type === 'line' || type === 'bar' || type === 'stackArea' || type === 4) {
this.setData(chartItem, []); this.setData(chartItem, []);
}else if(chartItem.type ==='singleStat'){
this.serieSingleStat = "";
this.$refs.loadingPreview.endLoading();
} }
//} //}
} }
@@ -1031,7 +990,7 @@
iframe.src=""; iframe.src="";
} }
this.isStackArea = false; this.isStackArea = false;
this.serieSingleStat = '';
}, },
// 重新请求数据 刷新操作 // 重新请求数据 刷新操作
/* /*
@@ -1065,6 +1024,10 @@
this.showLegend = false; this.showLegend = false;
this.$refs.loadingPreview.startLoading(); this.$refs.loadingPreview.startLoading();
this.getQueryChart(); this.getQueryChart();
}else if (chartType === 'singleStat') {
this.serieSingleStat = "";
this.$refs.loadingPreview.startLoading();
this.getChartData();
} }
}, },
// 查询数据,修改日期查询全屏数据 // 查询数据,修改日期查询全屏数据

View File

@@ -102,6 +102,7 @@ const cn = {
selectPanelTitle: "选择面板", selectPanelTitle: "选择面板",
createPanelTitleSec: "新增面板", createPanelTitleSec: "新增面板",
editPanelTitle: "面板", editPanelTitle: "面板",
singleStatErrorTip:'Only queries that return single series/table is supported',
panelForm: { panelForm: {
panelName: "面板名称", panelName: "面板名称",
panelId: "ID" panelId: "ID"
@@ -113,6 +114,7 @@ const cn = {
chartName: "图表名称", chartName: "图表名称",
type: "类型", type: "类型",
url: "URL", url: "URL",
statistics:'Statistics',
typeVal: { typeVal: {
line: { line: {
label: "曲线图" label: "曲线图"
@@ -128,8 +130,21 @@ const cn = {
}, },
url: { url: {
label: "URL" label: "URL"
},
singleStat:{
label:"SingleStat"
} }
}, },
statisticsVal:{
min:'Min',
max:'Max',
average:'Average',
total:'Total',
first:'First',
last:'Last',
range:'Range',
different:'Different',
},
width: "宽", width: "宽",
high: "高", high: "高",
metric: "指标", metric: "指标",

View File

@@ -107,6 +107,7 @@ const en = {
selectPanelTitle:'Select', //"选择面板" selectPanelTitle:'Select', //"选择面板"
createPanelTitleSec:'New panel',//"新增面板" createPanelTitleSec:'New panel',//"新增面板"
editPanelTitle: 'Panel', //"面板" editPanelTitle: 'Panel', //"面板"
singleStatErrorTip:'Only queries that return single series/table is supported',
panelForm:{ panelForm:{
panelName:'Panel name', //"面板名称" panelName:'Panel name', //"面板名称"
panelId:"ID" //ID panelId:"ID" //ID
@@ -121,6 +122,7 @@ const en = {
unit:"Unit", unit:"Unit",
url:"URL", url:"URL",
legend:'Legend', legend:'Legend',
statistics:'Statistics',
legendTip:'Controls the name of the time series, using name or pattern. For example {{hostname}} will be replaced with label value for the label hostname.', legendTip:'Controls the name of the time series, using name or pattern. For example {{hostname}} will be replaced with label value for the label hostname.',
typeVal:{ typeVal:{
line:{ line:{
@@ -137,8 +139,21 @@ const en = {
}, },
url:{ url:{
label:"URL" label:"URL"
},
singleStat:{
label:"SingleStat"
} }
}, },
statisticsVal:{
min:'Min',
max:'Max',
average:'Average',
total:'Total',
first:'First',
last:'Last',
range:'Range',
different:'Different',
},
width:'Width', //"宽" width:'Width', //"宽"
high:'High', //"高" high:'High', //"高"
metric:'Metric', //"指标" metric:'Metric', //"指标"

View File

@@ -190,7 +190,7 @@
<div v-if="!isUrl" class="right-box-sub-title">{{$t('dashboard.panel.chartForm.metric')}}</div> <div v-if="!isUrl" class="right-box-sub-title">{{$t('dashboard.panel.chartForm.metric')}}</div>
<div v-if="!isUrl" class="line-100"></div> <div v-if="!isUrl" class="line-100"></div>
<el-row v-if="!isUrl" class="element-item" v-for="(elem, index) in elements" :key="'ele' + index"> <el-row v-if="!isUrl && !isSingleStat" class="element-item" v-for="(elem, index) in elements" :key="'ele' + index">
<chart-metric ref="chartTag" <chart-metric ref="chartTag"
:pointer="index" :pointer="index"
:metric-list="metricList" :metric-list="metricList"
@@ -201,10 +201,39 @@
@sub-save-ok="subOk" @sub-save-ok="subOk"
@on-add-target-success="getTarget" @on-add-target-success="getTarget"
></chart-metric> ></chart-metric>
</el-row> </el-row>
<button v-if="!isUrl" type="button" @click="addTarget" class="nz-btn nz-btn-size-normal nz-btn-style-light" style="margin-left: 1px;"> <el-row v-if="isSingleStat" class="element-item" v-for="(elem, index) in elements" :key="'ele' + index">
<chart-metric ref="chartTag"
:has-legend="false"
:is-single-stat="true"
:pointer="index"
:metric-list="metricList"
:metricCascaderList="metricCascaderList"
:metricAllData="metricAllData"
:count-total="elements.length"
@on-delete-target="deleteTarget"
@sub-save-ok="subOk"
@on-add-target-success="getTarget"
></chart-metric>
</el-row>
<!--
<el-form-item prop="param.statistics" v-show="isSingleStat">
<el-row :gutter="4">
<el-col :span="4">
{{$t('dashboard.panel.chartForm.statistics')}}&nbsp;
</el-col>
<el-col :span="20">
<el-select class="right-box-row-with-btn" popper-class="chart-box-dropdown-mini" v-model="chart.param.statistics" placeholder="" size="small">
<el-option v-for="item in statisticsList" :key="item.id" :label="item.name" :value="item.id">
<span class="panel-dropdown-label-txt" >{{item.name}}</span>
</el-option>
</el-select>
</el-col>
</el-row>
</el-form-item>
-->
<button v-if="!isUrl && !isSingleStat" type="button" @click="addTarget" class="nz-btn nz-btn-size-normal nz-btn-style-light" style="margin-left: 1px;">
<span class="top-tool-btn-txt">{{$t('dashboard.panel.chartForm.addMetric')}}</span> <span class="top-tool-btn-txt">{{$t('dashboard.panel.chartForm.addMetric')}}</span>
</button> </button>
@@ -267,6 +296,7 @@
panel: '' panel: ''
}, },
isUrl:false, isUrl:false,
isSingleStat:false,
rules: { rules: {
title: [ title: [
{required: true, message: this.$t('validate.required'), trigger: 'blur'} {required: true, message: this.$t('validate.required'), trigger: 'blur'}
@@ -295,6 +325,10 @@
{ {
id:'url', id:'url',
name:this.$t("dashboard.panel.chartForm.typeVal.url.label") name:this.$t("dashboard.panel.chartForm.typeVal.url.label")
},
{
id:'singleStat',
name:this.$t("dashboard.panel.chartForm.typeVal.singleStat.label")
} }
], ],
elements: [1], // 指标部分 tarNum elements: [1], // 指标部分 tarNum
@@ -331,6 +365,7 @@
} }
this.rightBox.show = show; this.rightBox.show = show;
this.isUrl = false; this.isUrl = false;
this.isSingleStat = false;
}, },
clickos() { clickos() {
this.esc(); this.esc();
@@ -560,6 +595,7 @@
panelId = this.autocompleteExist(this.panelName2); panelId = this.autocompleteExist(this.panelName2);
if (panelId) { if (panelId) {
this.panelId = panelId; this.panelId = panelId;
console.log('___params___',params)
this.$post('panel/' + this.panelId + '/charts', params).then(response => { this.$post('panel/' + this.panelId + '/charts', params).then(response => {
if (response.code === 200) { if (response.code === 200) {
this.esc(); this.esc();
@@ -616,6 +652,9 @@
height: this.chart.height, height: this.chart.height,
type: this.chart.type, type: this.chart.type,
unit:this.chart.unit, unit:this.chart.unit,
param:{
statistics:target.statistics
}
}; };
//生成指标数组 //生成指标数组
@@ -779,6 +818,18 @@
//this.chartModal = true;//????控制弹出框显示和隐藏的,不需要了 //this.chartModal = true;//????控制弹出框显示和隐藏的,不需要了
this.initOpen(); // 获取metric, productId数据 this.initOpen(); // 获取metric, productId数据
}, },
setIsUrl(){
this.isUrl = true;
this.isSingleStat = false;
},
setIsSingleStat(){
this.isUrl = false;
this.isSingleStat = true;
},
setIsOtherChart(){
this.isSingleStat = false;
this.isUrl = false;
},
// 编辑chart时使用, set_tdata // 编辑chart时使用, set_tdata
editData(data, panelId) { editData(data, panelId) {
//alert('data='+JSON.stringify(data)+"=="+panelId); //alert('data='+JSON.stringify(data)+"=="+panelId);
@@ -799,9 +850,24 @@
this.chart.unit=data.unit; this.chart.unit=data.unit;
if(this.chart.type==='url'){ if(this.chart.type==='url'){
this.chart.param.url = data.param.url; this.chart.param.url = data.param.url;
this.isUrl = true; this.setIsUrl();
this.elements = [1]; this.elements = [1];
}else if(this.chart.type==='singleStat'){
this.setIsSingleStat();
this.elements = [];
bus.chartAddInfo.metricTarget = [];
data.elements.forEach((item, index) => {
this.elements.push(index);
});
this.$nextTick(() => {
const cSet = this.$refs.chartTag;
// 派发charttag数据
cSet.forEach((item, index) => {
item.setMdata(data.elements[index],data.param.statistics);
});
});
}else{ }else{
this.setIsOtherChart();
//this.getSuggestMetric();//获得指标列表 //this.getSuggestMetric();//获得指标列表
// 指标 // 指标
this.elements = []; this.elements = [];
@@ -862,9 +928,27 @@
let chartType = this.chart.type; let chartType = this.chart.type;
this.chart.param.url=''; this.chart.param.url='';
if(chartType==='url'){ if(chartType==='url'){
this.isUrl = true; this.setIsUrl();
/*if(this.$refs.chartTag){
this.$refs.chartTag.forEach((item, index) => {
item.setNotSingleStat();
});
}*/
}else if(chartType==='singleStat'){
this.elements = [1];
this.setIsSingleStat();
/*if(this.$refs.chartTag){
this.$refs.chartTag.forEach((item, index) => {
item.setSingleStat();
});
}*/
}else { }else {
this.isUrl = false; this.setIsOtherChart();
/*if(this.$refs.chartTag){
this.$refs.chartTag.forEach((item, index) => {
item.setNotSingleStat();
});
}*/
} }
}, },
/*panel搜索建议*/ /*panel搜索建议*/

View File

@@ -268,6 +268,22 @@
<el-col :span="20"><el-input v-model="elementInfo.legend" type="text" size="small"></el-input></el-col> <el-col :span="20"><el-input v-model="elementInfo.legend" type="text" size="small"></el-input></el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item prop="statistics" v-show="isSingleStat">
<el-row :gutter="4">
<el-col :span="4">
{{$t('dashboard.panel.chartForm.statistics')}}&nbsp;
</el-col>
<el-col :span="20">
<el-select class="right-box-row-with-btn" popper-class="chart-box-dropdown-mini" v-model="elementInfo.statistics" placeholder="" size="small">
<el-option v-for="item in statisticsList" :key="item.id" :label="item.name" :value="item.id">
<span class="panel-dropdown-label-txt" >{{item.name}}</span>
</el-option>
</el-select>
</el-col>
</el-row>
</el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script>
@@ -297,6 +313,10 @@ export default {
hasLegend:{ hasLegend:{
type:Boolean, type:Boolean,
default:true default:true
},
isSingleStat:{
type:Boolean,
default:false
} }
}, },
components: { components: {
@@ -313,8 +333,44 @@ export default {
tagList: [], // 标签列表 tagList: [], // 标签列表
selectedTagList:[],//已选中的标签列表 selectedTagList:[],//已选中的标签列表
expression:'', expression:'',
legend:'' legend:'',
statistics:'last'
}, },
//isSingleStat:false,
statisticsList:[
{
id:"min",
name:this.$t("dashboard.panel.chartForm.statisticsVal.min")
},
{
id:"max",
name:this.$t("dashboard.panel.chartForm.statisticsVal.max")
},
{
id:"average",
name:this.$t("dashboard.panel.chartForm.statisticsVal.average")
},
{
id:"total",
name:this.$t("dashboard.panel.chartForm.statisticsVal.total")
},
{
id:"first",
name:this.$t("dashboard.panel.chartForm.statisticsVal.first")
},
{
id:"last",
name:this.$t("dashboard.panel.chartForm.statisticsVal.last")
},
{
id:"range",
name:this.$t("dashboard.panel.chartForm.statisticsVal.range")
},
{
id:"different",
name:this.$t("dashboard.panel.chartForm.statisticsVal.different")
},
],
labelValueCascaderOptions:[],//label及value改为级联后显示用的待选label及value labelValueCascaderOptions:[],//label及value改为级联后显示用的待选label及value
labelValueCascaderVal:[],//label及value改为级联后选择的label及value labelValueCascaderVal:[],//label及value改为级联后选择的label及value
//metricCascaderList:[], //metricCascaderList:[],
@@ -516,6 +572,14 @@ export default {
}); });
}); });
}, },
setSingleStat(){
this.hasLegend = false;
this.isSingleStat = true;
},
setNotSingleStat(){
this.hasLegend = true;
this.isSingleStat = false;
},
// (最后整体保存添加的图标的时候执行)保存, chartdata点击确认后保存本身数据并返回给chartdata // (最后整体保存添加的图标的时候执行)保存, chartdata点击确认后保存本身数据并返回给chartdata
saveTarget(pointer,optType) { saveTarget(pointer,optType) {
if (this.pointer === pointer) { if (this.pointer === pointer) {
@@ -530,6 +594,7 @@ export default {
this.elementInfo.metric = this.elementInfo.metric[2]; this.elementInfo.metric = this.elementInfo.metric[2];
} }
this.convertLabelValueCascadeVal();//将labelvalue级联选择的值转换为selectTagList里 this.convertLabelValueCascadeVal();//将labelvalue级联选择的值转换为selectTagList里
console.log('___saveTarget___',this.elementInfo)
this.$emit('on-add-target-success', this.elementInfo, pointer,optType); this.$emit('on-add-target-success', this.elementInfo, pointer,optType);
} }
}); });
@@ -1116,10 +1181,11 @@ export default {
}, },
// 编辑已有图表状态时,先填充数据 // 编辑已有图表状态时,先填充数据
setMdata(data) { setMdata(data,statistics) {
this.setDataFlag = true; this.setDataFlag = true;
this.target = Object.assign({}, data); this.target = Object.assign({}, data);
//this.pointer =
this.elementInfo.statistics = statistics;
if(this.target.type==='expert'){ if(this.target.type==='expert'){
this.tableShow = 2; this.tableShow = 2;
this.elementInfo.type = this.target.type; this.elementInfo.type = this.target.type;

View File

@@ -210,6 +210,51 @@ export default new Vue({
} }
return num.toFixed(2); return num.toFixed(2);
}, },
getSingleStatRlt(statistics,result){
let dataArray = [];
if(result){
result.forEach((item)=>{
dataArray.push(item[1]);
})
}
let statisticsRlt = '';
if(dataArray.length>0){
if(statistics==='min'){//min最小值
statisticsRlt = dataArray.reduce(function(a , b){
return b < a ? b : a;
});
}else if(statistics==='max'){// max最大值
statisticsRlt = dataArray.reduce(function(a , b){
return b > a ? b : a;
});
}else if(statistics==='average'){// average平均值
let sum = 0;
dataArray.forEach((item)=>{
sum =Number(sum) + Number(item);
})
statisticsRlt = sum/dataArray.length;
}else if(statistics==='total'){//total总计
dataArray.forEach((item)=>{
statisticsRlt =Number(statisticsRlt) + Number(item);
})
}else if(statistics==='first'){//first第一个值
statisticsRlt = dataArray[0];
}else if(statistics==='last'){// last最后一个值
statisticsRlt = dataArray[dataArray.length-1];
}else if(statistics==='range'){//range : max - min
let min = dataArray.reduce(function(a , b){
return b < a ? b : a;
});
let max = dataArray.reduce(function(a , b){
return b > a ? b : a;
});
statisticsRlt = max-min;
}else if(statistics==='different'){//different : last - first
statisticsRlt = dataArray[dataArray.length-1]-dataArray[0];
}
}
return statisticsRlt;
},
computeTimezone:function(sourceTime){ computeTimezone:function(sourceTime){
let offset=localStorage.getItem('nz-sys-timezone'); let offset=localStorage.getItem('nz-sys-timezone');
if(offset&& offset != 'undefined' && offset != null){ if(offset&& offset != 'undefined' && offset != null){