Merge branch 'dev-3.2' of https://git.mesalab.cn/nezha/nezha-fronted into dev-3.2

This commit is contained in:
@changcode
2021-12-23 14:54:06 +08:00
13 changed files with 585 additions and 340 deletions

View File

@@ -13,6 +13,19 @@
</span> </span>
</el-popover> </el-popover>
</span> </span>
<span v-if="!isError&&!showAllData&&allDataLength>20" class="chart-header-error moreTitle">
<el-popover
placement="top-start"
:close-delay=10
trigger="hover"
popper-class="chart-warring-popper">
<div class="moreTitle">{{$t('dashboard.panel.moreTitle')}}{{$t('dashboard.panel.showAll')}}{{allDataLength}}</div>
<span slot="reference" class="panel-info-corner panel-info-corner--error" @click="loadMore">
<i class="nz-icon nz-icon-warning fa"></i>
<span class="panel-info-corner-inner"></span>
</span>
</el-popover>
</span>
<div class="chart-header__title">{{chartInfo.name}}</div> <div class="chart-header__title">{{chartInfo.name}}</div>
<div class="chart-header__tools"> <div class="chart-header__tools">
<span v-if="chartInfo.remark" class="chart-header__tool top-tool-btn-group"> <span v-if="chartInfo.remark" class="chart-header__tool top-tool-btn-group">
@@ -33,25 +46,10 @@
<script> <script>
import bus from '@/libs/bus' import bus from '@/libs/bus'
import lodash from 'lodash' import lodash from 'lodash'
import chartHeaderMixin from "@/components/chart/chartHeaderMixin";
export default { export default {
name: 'ChartScreenHeader', name: 'ChartScreenHeader',
props: { mixins: [chartHeaderMixin],
chartInfo: Object,
from: String,
isGroup: {
type: Boolean,
default: false
},
error: {
type: String,
default: ''
},
isError: {
type: Boolean,
default: false
},
chartData: {}
},
computed: { computed: {
timeRange () { timeRange () {
return this.$store.getters.getTimeRange return this.$store.getters.getTimeRange
@@ -75,7 +73,6 @@ export default {
this.setSearchTime(nowTimeType.type, nowTimeType.value, nowTimeType) this.setSearchTime(nowTimeType.type, nowTimeType.value, nowTimeType)
this.filter.start_time = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss') this.filter.start_time = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss')
this.filter.end_time = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss') this.filter.end_time = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss')
console.log(this.filter)
this.filter.value = this.searchTime[2] this.filter.value = this.searchTime[2]
this.filter.id = this.$refs.pickTime.$refs.timePicker.showTime.id this.filter.id = this.$refs.pickTime.$refs.timePicker.showTime.id
setTimeout(() => { setTimeout(() => {
@@ -134,14 +131,6 @@ export default {
} }
}, },
watch: { watch: {
isError: {
immediate: true,
handler (n) {
if (n) {
this.errorText = this.chartData.filter(item => item.error).map(item => item.error).join('\n')
}
}
},
timeRange: { timeRange: {
immediate: true, immediate: true,
handler (n) { handler (n) {

View File

@@ -10,6 +10,9 @@
:chart-info="chartInfo" :chart-info="chartInfo"
:chart-option="chartOption" :chart-option="chartOption"
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
:minusTime="minusTime"
:multipleTime="multipleTime"
:showAllData="showAllData"
@chartIsNoData="chartIsNoData" @chartIsNoData="chartIsNoData"
></chart-time-series> ></chart-time-series>
<chart-pie <chart-pie
@@ -222,7 +225,13 @@ export default {
panelLock: Boolean, panelLock: Boolean,
from: String, from: String,
isError: Boolean, isError: Boolean,
filter: {} filter: {},
multipleTime: {},
minusTime: {},
showAllData: {
type: Boolean,
default: false
}
}, },
data () { data () {
return { return {

View File

@@ -33,6 +33,10 @@ export default {
components: { components: {
chartLegend: legend chartLegend: legend
}, },
props: {
multipleTime: {},
minusTime: {}
},
mixins: [chartMixin], mixins: [chartMixin],
data () { data () {
return { return {
@@ -145,7 +149,9 @@ export default {
return function (params) { return function (params) {
let str = '<div class="nz-chart__tooltip">' let str = '<div class="nz-chart__tooltip">'
let sum = 0 let sum = 0
let flag = true
params.forEach((item, i) => { params.forEach((item, i) => {
const seriesName = item.seriesName.split('-')[0]
if (i === 0) { if (i === 0) {
const value = bus.computeTimezone(item.data[0] * 1000) const value = bus.computeTimezone(item.data[0] * 1000)
const tData = new Date(value) const tData = new Date(value)
@@ -153,6 +159,15 @@ export default {
str += bus.timeFormate(tData) str += bus.timeFormate(tData)
str += '</div>' str += '</div>'
} }
if (flag && item.seriesName.indexOf('Previous') !== -1) {
flag = false
const value = bus.computeTimezone(item.data[0] * 1000 - self.minusTime)
const tData = new Date(value)
str += '<div style="border: 1px solid #EEEEEE"></div>'
str += '<div style="margin-top: 5px;margin-bottom: 5px">'
str += bus.timeFormate(tData)
str += '</div>'
}
const color = self.colorList[item.seriesIndex] const color = self.colorList[item.seriesIndex]
const previousItem = params.find((series) => ('Previous ' + item.seriesName) === series.seriesName) const previousItem = params.find((series) => ('Previous ' + item.seriesName) === series.seriesName)
let paramsDot = bus.countDecimals(item.data[1]) let paramsDot = bus.countDecimals(item.data[1])
@@ -166,7 +181,8 @@ export default {
let previousDom = '' let previousDom = ''
if (previousItem) { if (previousItem) {
const previousVal = formatScientificNotation(item.data[1], paramsDot) const previousVal = formatScientificNotation(previousItem.data[1], paramsDot)
// console.log(previousVal, item.data[1])
let minusVal = 0 let minusVal = 0
let operator let operator
if (previousVal <= val) { if (previousVal <= val) {
@@ -184,7 +200,7 @@ export default {
<div class="tooltip__row"> <div class="tooltip__row">
<div class="row__label"> <div class="row__label">
<span class="row__color-block" style="background-color: ${color}"></span> <span class="row__color-block" style="background-color: ${color}"></span>
<span>${item.seriesName}</span> <span>${seriesName}</span>
</div> </div>
<div class="row__value"> <div class="row__value">
<span>${chartDataFormat.getUnit(self.chartInfo.unit ? self.chartInfo.unit : 2).compute(val, null, -1, paramsDot)}</span> <span>${chartDataFormat.getUnit(self.chartInfo.unit ? self.chartInfo.unit : 2).compute(val, null, -1, paramsDot)}</span>

View File

@@ -13,6 +13,19 @@
</span> </span>
</el-popover> </el-popover>
</span> </span>
<span v-if="!isError&&!showAllData&&allDataLength>20" class="chart-header-error moreTitle">
<el-popover
placement="top-start"
:close-delay=10
trigger="hover"
popper-class="chart-warring-popper">
<div class="moreTitle">{{$t('dashboard.panel.moreTitle')}}{{$t('dashboard.panel.showAll')}}{{allDataLength}}</div>
<span slot="reference" class="panel-info-corner panel-info-corner--error" @click="loadMore">
<i class="nz-icon nz-icon-warning fa"></i>
<span class="panel-info-corner-inner"></span>
</span>
</el-popover>
</span>
<div class="chart-header__title" v-if="!isGroup">{{chartInfo.name}}</div> <div class="chart-header__title" v-if="!isGroup">{{chartInfo.name}}</div>
<div class="chart-header__title" v-else > <div class="chart-header__title" v-else >
<span @click="groupShow"> <i class="nz-icon" :class="chartInfo.param.collapse ? 'nz-icon-arrow-down': 'nz-icon-arrow-right'"></i></span> <span @click="groupShow"> <i class="nz-icon" :class="chartInfo.param.collapse ? 'nz-icon-arrow-down': 'nz-icon-arrow-right'"></i></span>
@@ -63,73 +76,9 @@
</template> </template>
<script> <script>
import chartHeaderMixin from '@/components/chart/chartHeaderMixin'
export default { export default {
name: 'chartHeader', name: 'chartHeader',
props: { mixins: [chartHeaderMixin],
chartInfo: Object,
from: String,
isGroup: {
type: Boolean,
default: false
},
error: {
type: String,
default: ''
},
isError: {
type: Boolean,
default: false
},
chartData: {}
},
data () {
return {
dropdownMenuShow: false,
errorText: ''
}
},
methods: {
showFullscreen () {
this.$emit('showFullscreen', true)
},
refreshChart () {
this.$emit('refresh')
},
editChart () {
// this.$emit('edit-chart', this.chartInfo)
this.$store.dispatch('dispatchEditChart', {
chart: this.chartInfo,
type: 'edit'
})
},
removeChart () {
this.$store.dispatch('dispatchDelChart', {
chart: this.chartInfo,
type: 'delete'
})
},
duplicate () {
this.$store.dispatch('dispatchEditChart', {
chart: this.chartInfo,
type: 'duplicate'
})
},
clickos () {
this.dropdownMenuShow = false
},
groupShow () {
this.$emit('groupShow', !this.chartInfo.param.collapse)
}
},
watch: {
isError: {
immediate: true,
handler (n) {
if (n) {
this.errorText = this.chartData.filter(item => item.error).map(item => item.error).join('\n')
}
}
}
}
} }
</script> </script>

View File

@@ -0,0 +1,79 @@
export default {
props: {
chartInfo: Object,
from: String,
isGroup: {
type: Boolean,
default: false
},
error: {
type: String,
default: ''
},
isError: {
type: Boolean,
default: false
},
chartData: {},
showAllData: {
type: Boolean,
default: false
},
allDataLength: {
type: Number,
default: 0
}
},
data () {
return {
dropdownMenuShow: false,
errorText: ''
}
},
methods: {
showFullscreen () {
this.$emit('showFullscreen', true)
},
refreshChart () {
this.$emit('refresh')
},
editChart () {
// this.$emit('edit-chart', this.chartInfo)
this.$store.dispatch('dispatchEditChart', {
chart: this.chartInfo,
type: 'edit'
})
},
removeChart () {
this.$store.dispatch('dispatchDelChart', {
chart: this.chartInfo,
type: 'delete'
})
},
duplicate () {
this.$store.dispatch('dispatchEditChart', {
chart: this.chartInfo,
type: 'duplicate'
})
},
clickos () {
this.dropdownMenuShow = false
},
groupShow () {
this.$emit('groupShow', !this.chartInfo.param.collapse)
},
loadMore () {
this.$emit('loadMore')
}
},
watch: {
isError: {
immediate: true,
handler (n) {
if (n) {
this.errorText = this.chartData.filter(item => item.error).map(item => item.error).join('\n')
}
}
}
}
}

View File

@@ -155,7 +155,6 @@ export default {
} }
if (dom) { if (dom) {
this.stepWidth = Math.floor(dom.offsetWidth / 12) this.stepWidth = Math.floor(dom.offsetWidth / 12)
console.log(this.stepWidth)
if (!this.isGroup) { if (!this.isGroup) {
const headerH = 50 / this.stepWidth const headerH = 50 / this.stepWidth
const headerHPadding = 50 / this.stepWidth const headerHPadding = 50 / this.stepWidth
@@ -217,7 +216,6 @@ export default {
}, },
changeGroupHeight (copyList, group, flag) { changeGroupHeight (copyList, group, flag) {
const height = getGroupHeight(copyList) const height = getGroupHeight(copyList)
console.log(height,copyList[0].h, group, flag)
// console.log(this.$refs.layout) // console.log(this.$refs.layout)
const groupFind = this.copyDataList.find(item => item.id == group.id) const groupFind = this.copyDataList.find(item => item.id == group.id)
if (group && groupFind) { if (group && groupFind) {
@@ -300,7 +298,6 @@ export default {
let top = dom.style.transform.split(',')[1] let top = dom.style.transform.split(',')[1]
top = top.substring(0, top.length - 2) top = top.substring(0, top.length - 2)
const mainOffsetTop = top - this.stepWidth + 14// transform: grid组件 通过 tranfrom 控制位置 中间的为y的值 通过截取获得 - 父元素 marginTop的 值。 const mainOffsetTop = top - this.stepWidth + 14// transform: grid组件 通过 tranfrom 控制位置 中间的为y的值 通过截取获得 - 父元素 marginTop的 值。
console.log(mainOffsetTop)
// 2.元素的高度 // 2.元素的高度
const mainHeight = itemHeight // ele.offsetHeight;//itemHeight; const mainHeight = itemHeight // ele.offsetHeight;//itemHeight;
// 3.页面滚动的距离 // 3.页面滚动的距离

View File

@@ -1,6 +1,7 @@
import lodash from 'lodash' import lodash from 'lodash'
import { getMetricTypeValue } from '@/components/common/js/tools' import { getMetricTypeValue } from '@/components/common/js/tools'
import { getChart, getMousePoint, setChart } from '@/components/common/js/common' import { getChart, getMousePoint, setChart } from '@/components/common/js/common'
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
export default { export default {
data () { data () {
return { return {
@@ -14,14 +15,17 @@ export default {
}, },
chartId: '', chartId: '',
isNoData: true, isNoData: true,
showAllData: false
} }
}, },
props: { props: {
chartInfo: Object, chartInfo: Object,
chartData: Array, chartData: Array,
chartOption: Object, chartOption: Object,
isFullscreen: Boolean isFullscreen: Boolean,
showAllData: {
type: Boolean,
default: false
}
}, },
computed: { computed: {
filterTime () { filterTime () {
@@ -77,8 +81,15 @@ export default {
return series return series
}, },
// 单个legend // 单个legend
handleLegend (chartInfo, data, expressionIndex, dataIndex, colorIndex) { handleLegend (chartInfo, data, expressionIndexs, dataIndex, colorIndex) {
let expressionIndex = expressionIndexs
let legend = '' // up let legend = '' // up
let alias = ''
if (expressionIndex >= chartInfo.elements.length) {
expressionIndex -= chartInfo.elements.length
legend += 'Previous '
alias += 'Previous '
}
if (data.metric.__name__) { if (data.metric.__name__) {
legend += `${data.metric.__name__}{` legend += `${data.metric.__name__}{`
} }
@@ -98,10 +109,13 @@ export default {
legend = chartInfo.elements[expressionIndex].expression legend = chartInfo.elements[expressionIndex].expression
} }
// 处理legend别名 // 处理legend别名
let alias = chartInfo.datasource === 'system' ? '' : this.handleLegendAlias(legend, chartInfo.elements[expressionIndex].legend) alias = chartInfo.datasource === 'system' ? '' : (alias + this.handleLegendAlias(legend, chartInfo.elements[expressionIndex].legend))
if (!alias) { if (!alias) {
alias = legend alias = legend
} }
if (alias == 'Previous ') {
alias += legend
}
// proj_status_ // proj_status_
const name = alias + '-' + dataIndex const name = alias + '-' + dataIndex
@@ -113,6 +127,12 @@ export default {
return { type, value: getMetricTypeValue(data.values, type) } return { type, value: getMetricTypeValue(data.values, type) }
}) })
} }
if (colorIndex > 20) {
const colorRandom = randomcolor()
this.colorList.push(colorRandom)
this.chartOption.color.push(colorRandom)
}
// console.log(name, alias, statistics)
this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] }) this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] })
return { return {
name, name,
@@ -133,6 +153,9 @@ export default {
}) })
return labelValue return labelValue
} else { } else {
if (!aliasExpression) {
return ''
}
return aliasExpression return aliasExpression
} }
}, },

View File

@@ -0,0 +1,111 @@
const data = {
id: 'metrics',
loaded: true,
showHeader: true,
name: '',
panelId: 1244,
groupId: 0,
span: 4,
height: 4,
updateBy: 381,
updateAt: '2021-12-23 03:49:51',
type: 'line',
unit: 2,
weight: 0,
param: {
stack: 0,
showHeader: true,
thresholds: [
{
color: '#751bd6'
}
],
thresholdShow: false,
legend: {
values: [
],
show: true,
placement: 'bottom'
},
enable: {
thresholds: false,
legend: true,
valueMapping: false
},
nullType: 'null'
},
pid: null,
buildIn: 0,
remark: '',
seq: null,
x: 0,
y: 12,
elements: [
{
id: 85583,
chartId: 697389,
expression: '',
type: 'expert',
legend: '',
buildIn: 0,
seq: null,
name: 'A',
state: 1
}
],
sync: null,
panel: {
id: 1244,
name: 'testnodata',
createBy: null,
type: null,
link: null,
pid: null,
weight: null,
buildIn: null,
seq: null,
children: null,
parent: null,
chartNum: null
},
group: {
id: 0,
name: null,
panelId: null,
groupId: null,
span: null,
height: null,
updateBy: null,
updateAt: null,
type: null,
unit: null,
weight: null,
param: null,
pid: null,
buildIn: null,
remark: null,
seq: null,
x: null,
y: null,
elements: null,
sync: null,
panel: null,
group: null,
children: null,
chartNums: null,
asset: null,
varType: null,
varId: null,
varName: null,
datasource: null
},
children: null,
chartNums: null,
asset: null,
varType: null,
varId: null,
varName: null,
datasource: 'metrics'
}
export default data

View File

@@ -0,0 +1,110 @@
const data = {
id: 'logs',
loaded: true,
showHeader: true,
name: '',
panelId: 1244,
groupId: 0,
span: 4,
height: 4,
updateBy: 381,
updateAt: '2021-12-23 03:49:51',
type: 'line',
unit: 2,
weight: 0,
param: {
stack: 0,
showHeader: true,
thresholds: [
{
color: '#ea2556'
}
],
thresholdShow: false,
legend: {
values: [
],
show: true,
placement: 'bottom'
},
enable: {
thresholds: false,
legend: true,
valueMapping: false
}
},
pid: null,
buildIn: 0,
remark: '',
seq: null,
x: 0,
y: 12,
elements: [
{
id: 85584,
chartId: 697389,
expression: '',
type: 'expert',
legend: '',
buildIn: 0,
seq: null,
name: 'A',
state: 1
}
],
sync: null,
panel: {
id: 1244,
name: 'testnodata',
createBy: null,
type: null,
link: null,
pid: null,
weight: null,
buildIn: null,
seq: null,
children: null,
parent: null,
chartNum: null
},
group: {
id: 0,
name: null,
panelId: null,
groupId: null,
span: null,
height: null,
updateBy: null,
updateAt: null,
type: null,
unit: null,
weight: null,
param: null,
pid: null,
buildIn: null,
remark: null,
seq: null,
x: null,
y: null,
elements: null,
sync: null,
panel: null,
group: null,
children: null,
chartNums: null,
asset: null,
varType: null,
varId: null,
varName: null,
datasource: null
},
children: null,
chartNums: null,
asset: null,
varType: null,
varId: null,
varName: null,
datasource: 'logs'
}
export default data

View File

@@ -8,6 +8,9 @@
:isError="isError" :isError="isError"
:chartData="chartData" :chartData="chartData"
:chart-info="chartInfo" :chart-info="chartInfo"
:showAllData.sync="showAllData"
:allDataLength="allDataLength"
@loadMore="loadMore"
@edit-chart="$emit('edit-chart', chartInfo)" @edit-chart="$emit('edit-chart', chartInfo)"
@refresh="refresh" @refresh="refresh"
@groupShow="groupShow" @groupShow="groupShow"
@@ -20,6 +23,9 @@
:isError="isError" :isError="isError"
:chartData="chartData" :chartData="chartData"
:chart-info="chartInfo" :chart-info="chartInfo"
:showAllData.sync="showAllData"
:allDataLength="allDataLength"
@loadMore="loadMore"
@refresh="refresh" @refresh="refresh"
@dateChange="dateChange" @dateChange="dateChange"
@close="showFullscreen" @close="showFullscreen"
@@ -35,7 +41,10 @@
:from="from" :from="from"
:isError="isError" :isError="isError"
:loading="loading" :loading="loading"
:minusTime="minusTime"
:multipleTime="multipleTime"
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
:showAllData="showAllData"
v-if="!isGroup(chartInfo.type) || !chartInfo.param.collapse" v-if="!isGroup(chartInfo.type) || !chartInfo.param.collapse"
></chart> ></chart>
</div> </div>
@@ -74,7 +83,10 @@ export default {
chartData: [], chartData: [],
loading: true, loading: true,
isError: false, isError: false,
MultipleTime: false multipleTime: false,
minusTime: '',
showAllData: false,
allDataLength: 0
} }
}, },
computed: { computed: {
@@ -87,8 +99,7 @@ export default {
}, },
methods: { methods: {
isGroup, isGroup,
dateChange (filter, MultipleTime) { dateChange (filter, multipleTime) {
console.log(filter, MultipleTime)
this.loading = true this.loading = true
// TODO assetInfo、endpointInfo、echarts等进行不同的处理 // TODO assetInfo、endpointInfo、echarts等进行不同的处理
let startTime = filter.start_time let startTime = filter.start_time
@@ -97,6 +108,14 @@ export default {
startTime = this.$stringTimeParseToUnix(startTime) startTime = this.$stringTimeParseToUnix(startTime)
endTime = this.$stringTimeParseToUnix(endTime) endTime = this.$stringTimeParseToUnix(endTime)
const elements = this.chartInfo.elements || [] const elements = this.chartInfo.elements || []
if (multipleTime.length) {
const minusTime = (new Date(filter.start_time).getTime() - new Date(multipleTime[0]).getTime())
this.minusTime = minusTime
this.multipleTime = true
} else {
this.minusTime = ''
this.multipleTime = false
}
this.chartInfo.loaded && this.query(elements, startTime, endTime, step) this.chartInfo.loaded && this.query(elements, startTime, endTime, step)
}, },
// 参数 isRefresh 标识是否是刷新操作 // 参数 isRefresh 标识是否是刷新操作
@@ -128,6 +147,7 @@ export default {
}, },
query (elements, startTime, endTime, step) { query (elements, startTime, endTime, step) {
this.isError = false this.isError = false
this.allDataLength = 0
try { try {
switch (this.chartInfo.datasource) { switch (this.chartInfo.datasource) {
case 'metrics': case 'metrics':
@@ -138,7 +158,7 @@ export default {
} else if (this.chartInfo.datasource === 'logs') { } else if (this.chartInfo.datasource === 'logs') {
urlPre += '/logs/loki' urlPre += '/logs/loki'
} }
const requests = elements.map((element) => { let requests = elements.map((element) => {
if (this.from === fromRoute.chartTemp) { if (this.from === fromRoute.chartTemp) {
return chartTempData return chartTempData
} }
@@ -146,21 +166,61 @@ export default {
if (isTimeSeries(this.chartInfo.type)) { if (isTimeSeries(this.chartInfo.type)) {
query += `&nullType=${this.chartInfo.param.nullType || 'null'}` query += `&nullType=${this.chartInfo.param.nullType || 'null'}`
} }
if (element.filter) {
query += `&filter=${element.filter}`
}
// if (isChartPie(this.chartInfo.type)) { // if (isChartPie(this.chartInfo.type)) {
// query += `&statistics=${this.chartInfo.param.statistics || 'last'}` // query += `&statistics=${this.chartInfo.param.statistics || 'last'}`
// } // }
query += `&query=${element.expression}` query += `&query=${element.expression}`
return this.$get(query) return this.$get(query)
}) })
if (this.multipleTime) {
const multipleRequests = elements.map((element) => {
if (this.from === fromRoute.chartTemp) {
return chartTempData
}
let query = `${urlPre}/api/v1/query_range?start=${startTime - this.minusTime / 1000}&end=${endTime - this.minusTime / 1000}&step=${step}`
if (isTimeSeries(this.chartInfo.type)) {
query += `&nullType=${this.chartInfo.param.nullType || 'null'}`
}
if (element.filter) {
query += `&filter=${element.filter}`
}
// if (isChartPie(this.chartInfo.type)) {
// query += `&statistics=${this.chartInfo.param.statistics || 'last'}`
// }
query += `&query=${element.expression}`
return this.$get(query)
})
requests = requests.concat(multipleRequests)
}
const chartData = [] const chartData = []
axios.all(requests).then(res => { axios.all(requests).then((res) => {
res.forEach(r => { res.forEach((r, rIndex) => {
if (r.status === 'success') { if (rIndex < elements.length) {
chartData.push(r.data.result) if (r.status === 'success') {
r.data.result.forEach(item => {
this.allDataLength++
})
chartData.push(r.data.result)
} else {
chartData.push({ error: r.msg || r.error || r })
this.isError = true
}
} else { } else {
chartData.push({ error: r.msg || r.error || r }) if (r.status === 'success') {
this.isError = true r.data.result.forEach(item => {
this.allDataLength++
item.values.forEach(values => {
values[0] = values[0] + this.minusTime / 1000
})
})
chartData.push(r.data.result)
} else {
chartData.push({ error: r.msg || r.error || r })
this.isError = true
}
} }
}) })
this.chartData = chartData this.chartData = chartData
@@ -316,6 +376,21 @@ export default {
this.groupInit() this.groupInit()
bus.$emit('groupMove', '', '', true) bus.$emit('groupMove', '', '', true)
this.$emit('groupShow', this.chartInfo) this.$emit('groupShow', this.chartInfo)
},
showMultiple (type) {
switch (type) {
case 'line' :
case 'area' :
case 'point' :
return true
default: return false
}
},
loadMore () {
this.showAllData = true
this.$nextTick(() => {
this.$refs.chart && this.$refs.chart.$refs['chart' + this.chartInfo.id].initChart()
})
} }
}, },
watch: { watch: {
@@ -334,6 +409,7 @@ export default {
}, },
mounted () { mounted () {
this.chartInfo.loaded && this.getChartData() this.chartInfo.loaded && this.getChartData()
this.showAllData = !this.showMultiple(this.chartInfo.type)
} }
} }
</script> </script>

View File

@@ -47,36 +47,56 @@
<Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination>
</template> </template>
</nz-bottom-data-list> </nz-bottom-data-list>
<el-dialog id="viewGraphDialog" <!-- <el-dialog id="viewGraphDialog"-->
:modal-append-to-body='false' <!-- :modal-append-to-body='false'-->
destroy-on-close <!-- destroy-on-close-->
:title="$t('overall.detail')" <!-- :title="$t('overall.detail')"-->
:visible.sync="graphShow" <!-- :visible.sync="graphShow"-->
class="line-chart-block-modal nz-dialog endpoint-dialog" <!-- class="line-chart-block-modal nz-dialog endpoint-dialog"-->
width="90%" <!-- width="90%"-->
@close="dialogClose"> <!-- @close="dialogClose">-->
<el-popover <!-- <el-popover-->
v-if="isError" <!-- v-if="isError"-->
placement="top-start" <!-- placement="top-start"-->
:close-delay=10 <!-- :close-delay=10-->
trigger="hover" <!-- trigger="hover"-->
popper-class="chart-error-popper"> <!-- popper-class="chart-error-popper">-->
<div >{{errorContent}}</div> <!-- <div >{{errorContent}}</div>-->
<span slot="reference" class="panel-info-corner panel-info-corner--error"> <!-- <span slot="reference" class="panel-info-corner panel-info-corner&#45;&#45;error">-->
<i class="nz-icon nz-icon-warning fa-model" ></i> <!-- <i class="nz-icon nz-icon-warning fa-model" ></i>-->
<span class="panel-info-corner-inner"></span> <!-- <span class="panel-info-corner-inner"></span>-->
</span> <!-- </span>-->
</el-popover> <!-- </el-popover>-->
<div slot="title"> <!-- <div slot="title">-->
{{$t("project.endpoint.dialogTitle")}} <!-- {{$t("project.endpoint.dialogTitle")}}-->
<div class="float-right panel-calendar dialog-tool" style="display: flex"> <!-- <div class="float-right panel-calendar dialog-tool" style="display: flex">-->
<pick-time v-model="searchTime" :refresh-data-func="queryDate" :use-chart-unit="false" :use-refresh="false" style="height: 28px;"></pick-time> <!-- <pick-time v-model="searchTime" :refresh-data-func="queryDate" :use-chart-unit="false" :use-refresh="false" style="height: 28px;"></pick-time>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div style="width: 100%;height: 100%" v-loading="chartLoading"> <!-- <div style="width: 100%;height: 100%" v-loading="chartLoading">-->
<chart v-if="resultType === 'matrix'" ref="messageChart" :unit="chartUnit" name="alertMessageChart"></chart> <!-- <chart v-if="resultType === 'matrix'" ref="messageChart" :unit="chartUnit" name="alertMessageChart"></chart>-->
<log-tab v-if="resultType === 'streamsFormat'" ref="logDetailScreen" :log-data="logData" :showSwitch="false" :tab-index="tabIndex" @exportLog="exportLog" @limitChange="queryLogData"></log-tab> <!-- <log-tab v-if="resultType === 'streamsFormat'" ref="logDetailScreen" :log-data="logData" :showSwitch="false" :tab-index="tabIndex" @exportLog="exportLog" @limitChange="queryLogData"></log-tab>-->
</div> <!-- </div>-->
<!-- </el-dialog>-->
<el-dialog
id="viewGraphDialog"
v-if="graphShow"
:visible.sync="graphShow"
:show-close="false"
class="nz-dialog chart-fullscreen"
destroy-on-close
fullscreen
:modal-append-to-body="false"
>
<panel-chart
:ref="'chart-fullscreen' + chartInfo.id"
:chart-info="chartInfo"
:from="fromRoute.alertMessage"
:filter="{}"
:is-fullscreen="true"
:time-range="searchTime"
@showFullscreen="showFullscreen"
></panel-chart>
</el-dialog> </el-dialog>
<el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')" <el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')"
:visible.sync="dialogShowText" :visible.sync="dialogShowText"
@@ -109,6 +129,10 @@ import chart from '@/components/page/dashboard/overview/chart'
import { alertMessage as alertMessageConstant, fromRoute } from '@/components/common/js/constants' import { alertMessage as alertMessageConstant, fromRoute } from '@/components/common/js/constants'
import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox' import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox'
import detailViewRightMixin from '@/components/common/mixin/detailViewRightMixin' import detailViewRightMixin from '@/components/common/mixin/detailViewRightMixin'
import panelChart from '@/components/chart/panelChart'
import lodash from 'lodash'
import lineData from '@/components/chart/defaultLineData'
import logData from '@/components/chart/defaultLogData'
export default { export default {
name: 'alertMessageTab', name: 'alertMessageTab',
@@ -117,7 +141,8 @@ export default {
nzBottomDataList, nzBottomDataList,
alertMessageTable, alertMessageTable,
alertSilenceBox, alertSilenceBox,
chart chart,
panelChart
}, },
props: { props: {
from: String from: String
@@ -218,7 +243,8 @@ export default {
dialogShowText: false, dialogShowText: false,
dialogText: '', dialogText: '',
isError: false, isError: false,
errorContent: '' errorContent: '',
chartInfo: {}
} }
}, },
methods: { methods: {
@@ -493,7 +519,6 @@ export default {
} }
this.$get('/alert/rule/' + row.alertRule.id).then(res => { this.$get('/alert/rule/' + row.alertRule.id).then(res => {
this.currentMsg = { ...row, alertRule: { ...res.data } } this.currentMsg = { ...row, alertRule: { ...res.data } }
this.graphShow = true
this.$nextTick(() => { this.$nextTick(() => {
this.searchTime = [bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000), bus.computeTimezoneTime(new Date().getTime())] this.searchTime = [bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000), bus.computeTimezoneTime(new Date().getTime())]
this.queryDate() this.queryDate()
@@ -683,12 +708,15 @@ export default {
queryDate () { queryDate () {
this.chartLoading = true this.chartLoading = true
if (this.currentMsg.alertRule.type === 1) { if (this.currentMsg.alertRule.type === 1) {
this.resultType = 'matrix' const chartInfo = lodash.cloneDeep(lineData)
this.$nextTick(() => { chartInfo.elements[0].expression = encodeURIComponent(this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
this.queryChartDate() chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
}) this.showFullscreen(true, chartInfo)
} else if (this.currentMsg.alertRule.type === 2) { } else if (this.currentMsg.alertRule.type === 2) {
this.queryLogData(1000) const chartInfo = lodash.cloneDeep(logData)
chartInfo.elements[0].expression = encodeURIComponent(this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
this.showFullscreen(true, chartInfo)
} }
}, },
exportLog ({ limit, descending }) { exportLog ({ limit, descending }) {
@@ -841,6 +869,10 @@ export default {
showText (row) { showText (row) {
this.dialogShowText = true this.dialogShowText = true
this.dialogText = row.alertRule.trbShot this.dialogText = row.alertRule.trbShot
},
showFullscreen (show, chartInfo) {
this.chartInfo = chartInfo
this.graphShow = show
} }
} }
} }

View File

@@ -101,36 +101,24 @@
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
<el-dialog id="viewGraphDialog" <el-dialog
:modal-append-to-body='false' v-if="graphShow"
destroy-on-close :visible.sync="graphShow"
:title="$t('overall.detail')" :show-close="false"
:visible.sync="graphShow" class="nz-dialog chart-fullscreen"
class="line-chart-block-modal nz-dialog endpoint-dialog" destroy-on-close
width="90%" fullscreen
@close="dialogClose"> :modal-append-to-body="false"
<el-popover >
v-if="isError" <panel-chart
placement="top-start" :ref="'chart-fullscreen' + chartInfo.id"
:close-delay=10 :chart-info="chartInfo"
trigger="hover" :from="fromRoute.alertMessage"
popper-class="chart-error-popper"> :filter="{}"
<div >{{errorContent}}</div> :is-fullscreen="true"
<span slot="reference" class="panel-info-corner panel-info-corner--error"> :time-range="searchTimeDialog"
<i class="nz-icon nz-icon-warning fa-model" ></i> @showFullscreen="showFullscreen"
<span class="panel-info-corner-inner"></span> ></panel-chart>
</span>
</el-popover>
<div slot="title">
{{$t("project.endpoint.dialogTitle")}}
<div class="float-right panel-calendar dialog-tool" style="display: flex">
<pick-time v-model="searchTimeDialog" :refresh-data-func="queryDate" :use-chart-unit="false" :use-refresh="false" style="height: 28px;"></pick-time>
</div>
</div>
<div style="width: 100%;height: 100%" v-loading="chartLoading">
<chart v-if="resultType === 'matrix'" ref="messageChart" :unit="chartUnit" name="alertMessageChart"></chart>
<log-tab v-if="resultType === 'streamsFormat'" ref="logDetailScreen" :log-data="logData" :showSwitch="false" :tab-index="tabIndex" @exportLog="exportLog" @limitChange="queryLogData"></log-tab>
</div>
</el-dialog> </el-dialog>
<!--全屏--> <!--全屏-->
<el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')" <el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')"
@@ -166,6 +154,10 @@ import { alertMessage as alertMessageConstant, fromRoute } from '@/components/co
import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox' import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox'
import clickSearch from '@/components/common/labelFilter/clickSearch' import clickSearch from '@/components/common/labelFilter/clickSearch'
import routerPathParams from '@/components/common/mixin/routerPathParams' import routerPathParams from '@/components/common/mixin/routerPathParams'
import panelChart from '@/components/chart/panelChart'
import lineData from '@/components/chart/defaultLineData'
import logData from '@/components/chart/defaultLogData'
import lodash from 'lodash'
export default { export default {
name: 'alertMessage', name: 'alertMessage',
@@ -176,12 +168,14 @@ export default {
nzDataList, nzDataList,
deleteButton, deleteButton,
alertSilenceBox, alertSilenceBox,
clickSearch clickSearch,
panelChart
}, },
mixins: [dataListMixin, routerPathParams], mixins: [dataListMixin, routerPathParams],
data () { data () {
return { return {
chartLoading: false, chartLoading: false,
chartInfo: {},
stateOptions: alertMessageConstant.states, stateOptions: alertMessageConstant.states,
dataListLayout: localStorage.getItem('dataList-layout' + 'alertMessageTable') ? JSON.parse(localStorage.getItem('dataList-layout' + 'alertMessageTable')) : ['searchInput', 'elementSet', 'clickSearch', 'pagination'], dataListLayout: localStorage.getItem('dataList-layout' + 'alertMessageTable') ? JSON.parse(localStorage.getItem('dataList-layout' + 'alertMessageTable')) : ['searchInput', 'elementSet', 'clickSearch', 'pagination'],
state: '1', state: '1',
@@ -562,7 +556,7 @@ export default {
} }
this.$get('/alert/rule/' + row.alertRule.id).then(res => { this.$get('/alert/rule/' + row.alertRule.id).then(res => {
this.currentMsg = { ...row, alertRule: { ...res.data } } this.currentMsg = { ...row, alertRule: { ...res.data } }
this.graphShow = true console.log(this.currentMsg )
this.$nextTick(() => { this.$nextTick(() => {
this.searchTimeDialog = [bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000), bus.computeTimezoneTime(new Date().getTime())] this.searchTimeDialog = [bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000), bus.computeTimezoneTime(new Date().getTime())]
this.queryDate() this.queryDate()
@@ -578,132 +572,15 @@ export default {
queryDate () { queryDate () {
this.chartLoading = true this.chartLoading = true
if (this.currentMsg.alertRule.type === 1) { if (this.currentMsg.alertRule.type === 1) {
this.resultType = 'matrix' const chartInfo = lodash.cloneDeep(lineData)
this.$nextTick(() => { chartInfo.elements[0].expression = encodeURIComponent(this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
this.queryChartDate() chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
}) this.showFullscreen(true, chartInfo)
} else if (this.currentMsg.alertRule.type === 2) { } else if (this.currentMsg.alertRule.type === 2) {
this.queryLogData(100) const chartInfo = lodash.cloneDeep(logData)
} chartInfo.elements[0].expression = encodeURIComponent(this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
}, chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
queryChartDate () { this.showFullscreen(true, chartInfo)
const $temp = this
const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
this.searchTimeDialog = [start, end]
const timeDiff = (new Date(end).getTime() - new Date(start).getTime()) / 1000 / (24 * 60 * 60)
let step = '15s'
if (timeDiff < 1) {
step = '15s'
} else if (timeDiff < 7) {
step = '5m'
} else if (timeDiff < 30) {
step = '10m'
} else {
step = '30m'
}
if (this.$refs.messageChart) {
this.$refs.messageChart.startLoading()
const axiosArr = []
axiosArr.push(axios.get('/prom/api/v1/query_range?query=' + encodeURIComponent(this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, '')) + '&start=' + this.$stringTimeParseToUnix(start) + '&end=' + this.$stringTimeParseToUnix(end) + '&step=' + step + '&filter=' + encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))))
this.legend = []
this.chartDatas = []
axios.all(axiosArr).then(res => {
this.chartLoading = false
try {
res.forEach((response, promIndex) => {
if (response.status === 200) {
if (response.data.status === 'success') {
const queryData = response.data.data.result[0]
if (queryData) {
const chartData = {
type: 'line',
symbol: 'none', // 去掉点
smooth: 0.2, // 曲线变平滑
name: '',
lineStyle: {
width: 1,
opacity: 0.9
},
markLine: {
silent: true,
symbol: ['circle', 'circle'],
label: {
distance: this.computeDistance(chartDataFormat.getUnit(this.currentMsg.alertRule.unit ? this.currentMsg.alertRule.unit : 2).compute(this.currentMsg.alertRule.threshold)),
formatter (params) {
return chartDataFormat.getUnit($temp.currentMsg.alertRule.unit ? $temp.currentMsg.alertRule.unit : 2).compute(params.value)
}
},
lineStyle: {
color: '#d64f40',
width: 2,
type: 'dotted'
},
data: [{
yAxis: Number(this.currentMsg.alertRule.threshold)
}]
},
markArea: {
itemStyle: {
color: '#d64f40',
opacity: 0.1
},
data: [this.returnMarkArea()]
}
}
if (this.currentMsg.alertRule.operator == '==' || this.currentMsg.alertRule.operator == '!=') {
delete chartData.markArea
}
let alias = chartData.name
chartData.name += '{'
alias += '{'
Object.keys(queryData.metric).forEach((item, index) => {
const label = item
const value = queryData.metric[label]
chartData.name += label + "='" + value + "',"
})
chartData.name = chartData.name.charAt(chartData.name.length - 1) == ',' ? chartData.name.substr(0, chartData.name.length - 1) : chartData.name
chartData.name += '}'
const legend = {
name: chartData.name,
alias: chartData.name,
isGray: false
}
this.legend.push(legend)
chartData.data = queryData.values.map((dpsItem, dpsIndex) => {
return [dpsItem[0] * 1000, parseFloat(dpsItem[1]).toFixed(2)]
})
this.chartDatas.push(chartData)
}
} else {
this.$message.error(response.data.error)
}
} else {
this.$refs.messageChart.endLoading()
this.chartLoading = false
this.isError = true
if (response.msg) {
this.errorContent = response.msg
} else if (response.error) {
this.errorContent = response.error
} else {
this.errorContent = response
}
}
})
this.$nextTick(() => {
this.$refs.messageChart.setRandomColors(this.chartDatas.length)
this.$refs.messageChart.setLegend(this.legend)
this.$refs.messageChart.setSeries(this.chartDatas)
this.$refs.messageChart.endLoading()
this.$refs.messageChart.resize()
})
} catch (err) {
// this.$message.error(err)
this.$refs.messageChart.endLoading()
this.chartLoading = false
}
})
} }
}, },
exportLog ({ limit, descending }) { exportLog ({ limit, descending }) {
@@ -746,33 +623,6 @@ export default {
reader.readAsText(error.response.data) reader.readAsText(error.response.data)
}) })
}, },
queryLogData (limit) { // log的chart和table是一个请求
if (!limit) {
limit = 100
}
const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
this.expressions = [this.currentMsg.alertRule.expr]
this.$get('/logs/loki/api/v1/query_range?format=1&query=' + encodeURIComponent(this.currentMsg.alertRule.expr) + '&start=' + this.$stringTimeParseToUnix(start) + '&end=' + this.$stringTimeParseToUnix(end) + '&limit=' + limit + '&filter=' + encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))).then(res => {
this.chartLoading = false
const logData = [res.data]
this.resultType = res.data.resultType
this.$nextTick(() => {
if (this.$refs.logDetail) {
this.$refs.logDetail.time = this.chartData.param.time
this.$refs.logDetail.wrapLines = this.chartData.param.wrapLines
this.$refs.logDetail.operations.descending = this.chartData.param.descending
}
// logData.forEach((item, index) => {
// item.result.forEach(result => {
// result.elements = this.expressions[index]
// })
// })
this.logData = logData
this.resultType === 'matrix' && this.loadLogGraph()
})
})
},
loadLogGraph () { loadLogGraph () {
const graphData = this.logData.filter(l => l.resultType === 'matrix') const graphData = this.logData.filter(l => l.resultType === 'matrix')
if (graphData && graphData.length > 0) { if (graphData && graphData.length > 0) {
@@ -1251,6 +1101,10 @@ export default {
params.ids = this.batchDeleteObjs.map(item => item.id).join(',') params.ids = this.batchDeleteObjs.map(item => item.id).join(',')
this.exportExcel(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.xlsx') this.exportExcel(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.xlsx')
this.closeDialog() this.closeDialog()
},
showFullscreen (show, chartInfo) {
this.chartInfo = chartInfo
this.graphShow = show
} }
}, },
destroyed () { destroyed () {

View File

@@ -34,11 +34,11 @@
</select-panel> </select-panel>
</div> </div>
<div class="top-tool-right"> <div class="top-tool-right">
<div class="top-tool-search margin-r-20"> <!-- <div class="top-tool-search margin-r-20">-->
<el-input id="queryPanel" ref="queryPanel" v-model="filter.searchName" class="query-input-inactive" clearable size="small" @blur="blurInput" @clear="clearInput" @focus="focusInput"> <!-- <el-input id="queryPanel" ref="queryPanel" v-model="filter.searchName" class="query-input-inactive" clearable size="small" @blur="blurInput" @clear="clearInput" @focus="focusInput">-->
<i slot="suffix" class="el-input__icon nz-icon nz-icon-search" style="float: right" @click="focusInput"></i> <!-- <i slot="suffix" class="el-input__icon nz-icon nz-icon-search" style="float: right" @click="focusInput"></i>-->
</el-input> <!-- </el-input>-->
</div> <!-- </div>-->
<pick-time id="panel" ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :use-chart-unit="false" class="margin-r-10"></pick-time> <pick-time id="panel" ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :use-chart-unit="false" class="margin-r-10"></pick-time>