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

This commit is contained in:
zyh
2022-04-06 10:46:08 +08:00
62 changed files with 1599 additions and 300 deletions

View File

@@ -12,10 +12,14 @@ npm install
npm run dev
# build for production with minification
npm run build
npm run build -- dev
# build for production and view the bundle analyzer report
npm run build --report
```
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
使用
需要配置 config.json 为 {"baseUrl":"http://192.168.40.42:8080/", "version": "21.04"}

View File

@@ -63,6 +63,12 @@
position: absolute;
}
}
.no-position-alert-label {
.alert-label.alert-label__border{
border: none !important;
position: unset;
}
}
//.alert-label::after, .alert-labelUp::after {
// content: '';
// display: block;

View File

@@ -0,0 +1,185 @@
.chart-fullscreen.nz-dialog .panel-chart--fullscreen{
.alert-message-info-header{
border-bottom: 1px solid rgba(0,0,0,0.09);;
padding-bottom: 20px;
}
.alert-message-info-box{
box-sizing: border-box;
padding: 20px;
display: flex;
width: 100%;
height: 100%;
overflow-y: auto;
.info-box-left{
width: 66%;
min-width: 500px;
min-height: 600px;
margin-right: 20px;
display: flex;
flex-direction: column;
.nz-chart {
height: 36%;
margin-bottom: 20px;
border: 1px solid $--border-color-light;
flex: none;
}
.alert-message-info-tab{
height: 63%;
flex: 1;
.el-tabs.el-tabs--card {
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__header{
margin: 0;
.el-tabs__item{
border: 1px solid $--border-color-light;
border-radius: 2px;
//border-bottom: none;
margin-right: 6px;
background: $--background-color-base;
color: $--color-text-regular;
}
.el-tabs__item:hover{
color: $--color-warning;
background: $--background-color-empty;
border-bottom-color: $--background-color-empty;
}
.el-tabs__item.is-active{
color: $--color-warning;
background: $--background-color-empty;
border-bottom-color: $--background-color-empty;
}
}
.el-tabs__content{
padding: 20px;
flex: 1;
border: 1px solid $--border-color-light;
border-top: none;
overflow-y: auto;
}
}
}
}
.info-box-right{
flex: 1;
height: 100%;
border: 1px solid #E7EAED;
border-radius: 2px;
box-sizing: border-box;
padding: 0px 20px 20px 0;
.table-no-data {
height: calc(100% - 80px);
}
.time-line-header{
padding: 20px;
font-size: 16px;
color: $--color-text-primary;
font-weight: 600;
display: flex;
justify-content: space-between;
.scope-icon-box {
display: flex;
flex: 1;
justify-content: right;
}
.scope-box {
cursor: pointer;
color: $--background-color-disabled;
.nz-icon {
margin-right: 5px;
color: $--background-color-disabled ;
font-weight: 400;
}
}
.scope-box.is-select{
color: $--color-monitor;
.nz-icon {
color: $--color-monitor;
}
}
#time-line-scope{
//float: right;
}
}
.el-timeline{
height: calc(100% - 80px);
overflow-y: auto;
padding-top: 14px;
padding-left: 40px;
box-sizing: border-box;
.el-timeline-item{
padding-bottom: 24px;
}
.has-time{
padding-top: 36px;
.el-timeline-item__tail{
height: calc(100% + 14px);
top: -14px;
}
}
.el-timeline-item.last .el-timeline-item__tail{
display: block;
top: -100%;
}
.el-timeline-item:last-child .el-timeline-item__tail.only{
display: block;
top: -100%;
}
.el-timeline-item__timestamp.is-top{
position: absolute;
top: -40px;
left: -20px;
font-size: 14px;
color: $--color-text-regular;
font-weight: 600;
background: $--background-color-empty;
margin: 0;
padding: 10px 0;
}
.el-timeline-item__node {
z-index: 1;
}
.time-line-item-header{
font-size: 14px;
color: #333333;
font-weight: 400;
}
}
.load-more-box{
display: flex;
justify-content: center;
align-items: center;
}
}
.table-no-data {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.el-tabs__nav{
border: none;
}
.info-box-header{
height: 100%;
overflow-y: auto;
}
.info-box-title{
font-size: 16px;
color: $--color-text-primary;
font-weight: 600;
margin-bottom: 12px;
}
.info-box-content{
font-size: 14px;
color: #666666;
font-weight: 400;
width: 100%;
margin-bottom: 40px;
}
}
}

View File

@@ -104,5 +104,5 @@
.alert-message-state{
padding: 3px 5px;
border-radius: 4px;
color: $--color-text-primary;
color: $--color-text-label;
}

View File

@@ -5,6 +5,7 @@
@import './common/alert/alertLabel.scss';
@import './common/alert/alertRuleInfo.scss';
@import './common/alert/selectAlertSilence.scss';
@import './common/alert/alertMessageInfo.scss';
@import './common/alert/alertDaysInfo.scss';
@import './common/bottomBox/bottomBox.scss';
@import './common/bottomBox/panelTabNew.scss';

View File

@@ -41,6 +41,8 @@ $--color-text-secondary: #999998;
$--color-text-link: #3C92F1;
// 禁用字色
$--color-text-disabled: #505050;
// 标签内白色
$--color-text-label: #505050;
/* 4.边框色 */
// 普通边框色

View File

@@ -41,6 +41,8 @@ $--color-text-secondary: #999998;
$--color-text-link: #3C92F1;
// 禁用字色
$--color-text-disabled: #FFFFFF;
// 标签内白色
$--color-text-label: #FFFFFF;
/* 4.边框色 */
// 普通边框色(覆盖element-ui内置变量)

View File

@@ -26,7 +26,10 @@
</span>
</el-popover>
</span>
<div class="chart-header__title" :title="chartInfo.name">{{chartInfo.name}}</div>
<div class="chart-header__title" :title="chartInfo.name">
<slot name="title-icon"></slot>
{{chartInfo.name}}
</div>
<div class="chart-header__tools">
<span v-if="chartInfo.remark" class="chart-header__tool top-tool-btn-group">
<el-tooltip :content="chartInfo.remark" effect="light" placement="top">

View File

@@ -1,7 +1,7 @@
<template>
<div :style="showHeader&&chartInfo.param.showHeader ? '' : 'padding-top: 15px;'" class="nz-chart" :class="showHeader&&chartInfo.param.showHeader ? '' : 'no-header'" >
<loading :loading="loading"></loading>
<chart-no-data v-if="isNoData || isError || chartChildrenData"></chart-no-data>
<chart-no-data v-if="isNoData || isError || chartChildrenData"></chart-no-data>
<template v-else>
<chart-time-series
v-if="isTimeSeries(chartInfo.type)"

View File

@@ -16,6 +16,11 @@ export default {
data () {
return {
}
},
methods: {
resize () {
}
}
}

View File

@@ -16,6 +16,11 @@ export default {
data () {
return {
}
},
methods: {
resize () {
}
}
}

View File

@@ -214,9 +214,11 @@ export default {
})
},
resize () {
this.getLayout().then(layout => {
this.renderGauge(layout).then(() => {
this.gaugeChartResize()
setTimeout(() => {
this.getLayout().then(layout => {
this.renderGauge(layout).then(() => {
this.gaugeChartResize()
})
})
})
},

View File

@@ -54,9 +54,8 @@ export default {
setTimeout(() => {
this.dataList = this.dataList.map(item => {
return {
...item,
...item
// hide: item.name.indexOf(this.filter.searchName) === -1, // 搜索条件
loaded: false
}
})
}, 100)
@@ -70,9 +69,9 @@ export default {
const arr = JSON.parse(JSON.stringify(n))
this.dataList = arr.map(item => {
return {
...item,
...item
// hide: item.name.indexOf(this.filter.searchName) === -1, // 搜索条件
loaded: false
// loaded: false
}
})
})

View File

@@ -6,6 +6,11 @@
<script>
export default {
name: 'chartNoData'
name: 'chartNoData',
methods: {
resize () {
}
}
}
</script>

View File

@@ -21,6 +21,9 @@ export default {
}
},
methods: {
resize () {
}
},
watch: {
chartInfo: {

View File

@@ -72,6 +72,15 @@ export default {
methods: {
initChart (chartOptions = this.chartOption) {
const chartOption = lodash.cloneDeep(chartOptions)
if (this.chartInfo.isAlertMessage) {
chartOption.title = {
show: true,
text: this.$t('project.endpoint.dialogTitle'),
top: 20
}
chartOption.grid.top = 70
chartOption.toolbox.top = 20
}
this.legends = []
this.series = chartOption.series = this.handleTimeSeries(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends
if (!this.series.length) {
@@ -89,6 +98,9 @@ export default {
chartOption.yAxis.axisLabel.formatter = this.yAxisLabelFormatter(minValue, maxValue, copies, unit, decimals)
chartOption.yAxis.minInterval = chartDataFormat.Interval(maxValue, copies, unit.type, 'min')
chartOption.yAxis.maxInterval = chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(chartOption.series.length / 5)
if (this.chartInfo.param.stack) {
chartOption.yAxis.maxInterval = chartOption.yAxis.maxInterval * (Math.ceil(chartOption.series.length / 5) + 1)
}
if (unit.type === 'Time') {
delete chartOption.yAxis.minInterval
delete chartOption.yAxis.maxInterval
@@ -127,10 +139,12 @@ export default {
})
})
const timeSorted = datas.sort((a, b) => {
return a[0] - b[0]
return Number(a[0]) - Number(b[0])
})
const valueSorted = datas.sort((a, b) => {
return a[1] - b[1]
const a1 = isNaN(a[1]) && !a[1] ? 0 : Number(a[1])
const b1 = isNaN(b[1]) && !b[1] ? 0 : Number(b[1])
return a1 - b1
})
minTime = timeSorted.length ? timeSorted[0][0] : ''
maxTime = timeSorted.length ? timeSorted[timeSorted.length - 1][0] : ''
@@ -160,7 +174,6 @@ export default {
maxValue = Math.floor(oldValue) / Math.pow(10, dot)
dot++
}
console.log(oldValue)
const copies = chartDataFormat.copies(Number(oldValue), unit.type)
return { minTime, maxTime, minValue, maxValue, copies, unit, dot }
},
@@ -201,7 +214,11 @@ export default {
let sum = 0
let flag = true
params.forEach((item, i) => {
const seriesName = item.seriesName.split('-')[0]
const nameArr = item.seriesName.split('-')
if (nameArr.length > 1) {
nameArr.splice(nameArr.length - 1, 1)
}
const seriesName = nameArr.join('-')
if (i === 0 && item.seriesName.indexOf('Previous') === -1) {
const value = bus.computeTimezone(item.data[0] * 1000)
const tData = new Date(value)
@@ -283,7 +300,7 @@ export default {
yAxisLabelFormatter (minValue, maxValue, copies, unit, dot) {
const self = this
return function (val, index) {
const value = formatScientificNotation(val, 2)
const value = formatScientificNotation(val, 6)
// let chartUnit = self.chartInfo.unit
// chartUnit = chartUnit || 2
// const unit = chartDataFormat.getUnit(chartUnit)
@@ -317,11 +334,18 @@ export default {
self.isStack = !self.isStack
// 改变tooltip
option.tooltip[0].formatter = self.tooltipFormatter(self.isStack)
if (!self.chartInfo.param.stack) {
option.yAxis.maxInterval = option.yAxis.maxInterval / (Math.ceil(option.series.length / 5) + 1)
} else {
option.yAxis.maxInterval = option.yAxis.maxInterval * (Math.ceil(option.series.length / 5) + 1)
}
myChart.setOption(option)
}
},
resize () {
getChart(this.chartId).resize()
setTimeout(() => {
getChart(this.chartId) && getChart(this.chartId).resize()
}, 100)
}
},
mounted () {

View File

@@ -5,7 +5,10 @@
<div class="legend--table">
<div class="legend--table-row table-header">
<div class="legend--table-cell"></div>
<div v-for="statistics in chartInfo.param.legend.values" :key="statistics" class="legend--table-cell">{{statistics}}</div>
<div v-for="statistics in chartInfo.param.legend.values" :key="statistics" class="legend--table-cell">
<span v-if="statisticsList.find(key=>key.value === statistics)">{{$t(statisticsList.find(key=>key.value === statistics).label)}}</span>
<span v-else>--</span>
</div>
</div>
<div v-for="(item, index) in legends"
:key="index"
@@ -40,6 +43,7 @@
import lodash from 'lodash'
import { getChart } from '@/components/common/js/common'
import chartDataFormat from '@/components/charts/chartDataFormat'
import { statisticsList } from '@/components/common/js/constants'
export default {
name: 'chartLegend',
props: {
@@ -51,6 +55,7 @@ export default {
},
data () {
return {
statisticsList,
isGrey: [],
legendDefaultCount: 20, // 初始显示的legend条数
showLegends: [], // 要显示的legend若legend数量过多初始时这个数据里只有前20条legend
@@ -200,16 +205,6 @@ export default {
if (isNaN(result)) {
return '--'
}
// result = Math.round(num * 100) / 100
// let decimal = result.toString()
// let posDecimal = decimal.indexOf('.')
// if (posDecimal < 0) {
// posDecimal = decimal.length
// decimal += '.'
// }
// while (decimal.length <= posDecimal + 2) {
// decimal += '0'
// }
result = chartDataFormat.getUnit(this.chartInfo.unit ? this.chartInfo.unit : 2).compute(result, null, -1, 2)
return result
},

View File

@@ -68,7 +68,7 @@
<div class="basic-info-table-value" v-if="chartDetail">
<i :class="chartDetail.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{chartDetail.alertNum}}</div>
@@ -118,7 +118,7 @@
<div class="basic-info-table-value" v-if="chartDetail">
<i :class="chartDetail.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{chartDetail.alertNum}}</div>

View File

@@ -47,6 +47,7 @@
:chart-info="item"
:from="from"
:time-range="timeRange"
@groupShow="groupShow"
:chart-detail-info="chartDetailInfo"
@refreshPanel="refreshPanel"
@showFullscreen="showFullscreen"
@@ -209,6 +210,8 @@ export default {
if (!this.isGroup) {
this.moveChart()
this.onScroll(this.scrollTop)
} else {
bus.$emit('groupChildMove')
}
},
containerResizedEvent (i, newH, newW, newHPx, newWPx) {
@@ -232,7 +235,7 @@ export default {
this.copyDataList = [...this.copyDataList]
// this.$refs.layout.layoutUpdate()
}
this.moveChart()
this.onScroll(this.scrollTop)
},
cleanData () {
@@ -243,51 +246,46 @@ export default {
this.onScroll(this.scrollTop)
},
moveChart () {
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
const arr = this.copyDataList.filter(item => !item.staic)
const charts = []
let weight = 0
arr.forEach(item => {
charts.push({
id: item.id,
x: item.x,
y: item.y,
span: item.span,
height: item.height,
groupId: item.groupId,
weight: weight
})
weight++
if (item.type === 'group') {
item.children && item.children.forEach(children => {
charts.push({
id: children.id,
x: children.x,
y: children.y,
span: children.span,
height: children.height,
groupId: children.groupId,
weight: weight
})
weight++
})
}
this.onScroll(this.scrollTop)
const arr = this.copyDataList.filter(item => !item.staic)
const charts = []
let weight = 0
arr.forEach(item => {
charts.push({
id: item.id,
x: item.x,
y: item.y,
span: item.span,
height: item.height,
groupId: item.groupId,
weight: weight
})
const params = {
panelId: this.panelId,
charts: charts
}
if (charts && charts.length) {
this.$put('/visual/panel/chart/weights', params).then(() => {
const position = getLayoutPosition(this.copyDataList)
this.$store.commit('setChartLastPosition', position)
weight++
if (item.type === 'group') {
item.children && item.children.forEach(children => {
charts.push({
id: children.id,
x: children.x,
y: children.y,
span: children.span,
height: children.height,
groupId: children.groupId,
weight: weight
})
weight++
})
}
}, 1000)
})
const params = {
panelId: this.panelId,
charts: charts
}
if (charts && charts.length) {
this.$put('/visual/panel/chart/weights', params).then(() => {
const position = getLayoutPosition(this.copyDataList)
this.$store.commit('setChartLastPosition', position)
})
}
},
onScroll (scrollTop = 0, groupTop = 0) {
const self = this
@@ -304,8 +302,13 @@ export default {
if (dom) {
let top = dom.style.top
top = Number(top.substring(0, top.length - 2)) + groupTop
if (item.type === 'group') {
if (item.type === 'group' && item.loaded) {
this.$refs['chart' + item.id][0] && this.$refs['chart' + item.id][0].$refs.chart && this.$refs['chart' + item.id][0].$refs.chart.$refs['chart' + item.id] && this.$refs['chart' + item.id][0].$refs.chart.$refs['chart' + item.id].$refs.chartList.onScroll(scrollTop, top)
return
}
if (item.type === 'group' && !item.loaded) {
item.loaded = true
this.$refs['chart' + item.id][0].getChartData()
}
if (item.loaded) {
return
@@ -333,8 +336,77 @@ export default {
})
}, 200)
},
resize () {
this.init()
this.copyDataList.forEach(item => {
if (item.type === 'group') {
this.$refs['chart' + item.id][0] && this.$refs['chart' + item.id][0].groupShow(item.param.collapse)
this.$refs['chart' + item.id][0] && this.$refs['chart' + item.id][0].$refs.chart && this.$refs['chart' + item.id][0].$refs.chart.$refs['chart' + item.id] && this.$refs['chart' + item.id][0].$refs.chart.$refs['chart' + item.id].$refs.chartList.resize()
}
this.$refs['chart' + item.id][0] && this.$refs['chart' + item.id][0].resize()
})
},
refreshPanel () {
bus.$emit('refreshPanel')
},
createChartSuccess (params) {
const arr = this.copyDataList.filter(item => !item.staic)
const charts = []
let weight = 0
arr.forEach(item => {
const chart = {
id: item.id,
x: item.x,
y: item.y,
span: item.span,
height: item.height,
groupId: item.groupId,
weight: weight
}
if (!params.groupId && chart.y >= params.y) {
chart.y = chart.y + 1
}
if (params.id == item.id) {
chart.y = params.y
chart.x = params.x
}
charts.push(chart)
weight++
if (item.type === 'group') {
item.children && item.children.forEach(children => {
const childrenChart = {
id: children.id,
x: children.x,
y: children.y,
span: children.span,
height: children.height,
groupId: children.groupId,
weight: weight
}
if (item.id === params.groupId && children.y >= params.y) {
childrenChart.y = childrenChart.y + 1
}
if (params.id == childrenChart.id) {
childrenChart.y = params.y
childrenChart.x = params.x
}
charts.push(childrenChart)
weight++
})
}
})
const chartParams = {
panelId: this.panelId,
charts: charts
}
if (charts && charts.length) {
this.$put('/visual/panel/chart/weights', chartParams).then(() => {
if (params.cb) {
params.cb()
}
})
}
}
},
created () {
@@ -344,9 +416,15 @@ export default {
this.init()
if (!this.isGroup) {
bus.$on('groupMove', this.changeGroupHeight)
bus.$on('creat-chart-success', this.createChartSuccess)
bus.$on('groupChildMove', this.moveChart)
this.$store.commit('setChartListId', `chartList${this.timestamp}`)
window.addEventListener('resize', this.resize)
}
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
},
watch: {
dataList: {
deep: true,
@@ -371,6 +449,19 @@ export default {
// }
height = (item.type === 'group' && item.param.collapse) ? this.headerH : item.height
param.showHeader = true
if (param.valueMapping) {
param.valueMapping.forEach(valueMapping => {
if (!valueMapping.show) {
valueMapping.show = false
}
if (valueMapping.text && !valueMapping.display) {
valueMapping.display = valueMapping.text
}
if (valueMapping.columns && !valueMapping.column) {
valueMapping.column = valueMapping.columns
}
})
}
}
return {
...item,
@@ -397,7 +488,9 @@ export default {
this.copyDataList = JSON.parse(JSON.stringify(tempList))
setTimeout(() => {
this.gridLayoutShow = true
this.onScroll()
if (!this.isGroup) {
this.onScroll()
}
})
setTimeout(() => {
this.firstInit = false

View File

@@ -110,16 +110,17 @@ export default {
if (data.metric.__name__) {
legend += '}'
}
if (!legend && chartInfo.elements) {
legend = chartInfo.elements[expressionIndex].expression
}
// if (!legend && chartInfo.elements) {
// // legend = chartInfo.elements[expressionIndex].expression
// legend = ''
// }
// 处理legend别名
alias = alias + this.handleLegendAlias(legend, chartInfo.elements[expressionIndex].legend)
if (!alias) {
alias = legend
alias = chartInfo.elements[expressionIndex].expression
}
if (alias == 'Previous ') {
alias += legend
alias += chartInfo.elements[expressionIndex].expression
}
// proj_status_
const name = alias + '-' + dataIndex
@@ -146,6 +147,9 @@ export default {
if (/\{\{.+\}\}/.test(aliasExpression)) {
const labelValue = aliasExpression.replace(/(\{\{.+?\}\})/g, function (i) {
const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2)
if (!legend) {
return label
}
const reg = new RegExp(label + '=".+?"')
let value = null
if (reg.test(legend)) {
@@ -257,7 +261,9 @@ export default {
}
},
resize () {
getChart(this.chartId) && getChart(this.chartId).resize()
setTimeout(() => {
getChart(this.chartId) && getChart(this.chartId).resize()
}, 100)
}
},
watch: {

View File

@@ -420,7 +420,7 @@ export default {
})
},
resize () {
this.$refs.chart.resize()
this.$refs.chart && this.$refs.chart.resize()
},
refresh () {
this.getChartData(true)
@@ -532,7 +532,7 @@ export default {
timeRange: {
deep: true,
handler (n) {
this.refresh()
// this.refresh()
}
},
loading: {

View File

@@ -495,7 +495,7 @@ export default {
})
break
}
case 'average': {
case 'avg': {
result = classifies.map(group => {
const groupData = group.map(t => parseFloat(t.data[1]))
const sum = eval(groupData.join('+'))

View File

@@ -34,7 +34,7 @@ function percent02 (value, index) {
if (!numberWithEConvent(scientificNotationValue)) {
return `${scientificNotationValue} %`
}
value = parseFloat((Number(value) * 100))
value = parseFloat((Number(value) * 100).toFixed(2))
return `${value} %`
}
function localFormat (value, index) {
@@ -397,6 +397,9 @@ function asciiCompute2 (num, ascii, units, dot = 2, unitIndex = 0) {
* unit:设置的单位
* */
function timeCompute (value, unit, dot = 0) {
if (isNaN(value)) {
return `0 ${unit}`
}
if (unit == 'year') {
return `${value.toFixed(dot)} ${unit}`
}
@@ -725,7 +728,7 @@ export default {
pow++
value = value * 10
}
return Math.ceil(value + 1) / Math.pow(10, pow)
return Math.floor(value + 1) / Math.pow(10, pow)
}
if (type === 'Time') {
return value

View File

@@ -1449,7 +1449,7 @@ export default {
})
break
}
case 'average': {
case 'avg': {
result = classifies.map(group => {
const groupData = group.map(t => parseFloat(t.data[1]))
const sum = eval(groupData.join('+'))

View File

@@ -99,23 +99,23 @@
</span>
<span class="float-right">
<button @click="previewTopology" v-if="!isPreview" class="nz-btn nz-btn-size-normal nz-btn-style-light"
<button type="button" @click="previewTopology" v-if="!isPreview" class="nz-btn nz-btn-size-normal nz-btn-style-light"
style="margin-right: 20px"
>
{{$t('project.topology.preview')}}
</button>
<button v-if="isPreview" class="nz-btn nz-btn-size-normal nz-btn-style-light" @click="previewExit"
<button type="button" v-if="isPreview" class="nz-btn nz-btn-size-normal nz-btn-style-light" @click="previewExit"
style="margin-right: 20px"
>
{{$t('project.topology.previewExit')}}
</button>
<button class="nz-btn nz-btn-size-normal nz-btn-style-normal" @click="saveTopology"
<button type="button" class="nz-btn nz-btn-size-normal nz-btn-style-normal" @click="saveTopology"
:disabled="prevent_opt.save"
:class="{'nz-btn-disabled':prevent_opt.save}"
style="margin-right: 20px">
{{$t('project.topology.save')}}
</button>
<button class="nz-btn nz-btn-size-normal nz-btn-style-normal" style="margin-right: 20px" @click="cancelTopology">
<button type="button" class="nz-btn nz-btn-size-normal nz-btn-style-normal" style="margin-right: 20px" @click="cancelTopology">
{{$t('project.topology.exit')}}
</button>
</span>
@@ -294,11 +294,11 @@
</el-row>
<div class="upload-pic-row" style="text-align: center">
<span>
<button class="nz-btn nz-btn-size-normal nz-btn-style-light" style="margin-right: 20px" @click="uploadPicShow=false">
<button type="button" class="nz-btn nz-btn-size-normal nz-btn-style-light" style="margin-right: 20px" @click="uploadPicShow=false">
{{$t('project.topology.exit')}}
</button>
<button class="nz-btn nz-btn-size-normal nz-btn-style-normal" @click="imgUpload"
<button type="button" class="nz-btn nz-btn-size-normal nz-btn-style-normal" @click="imgUpload"
v-has="'topo_icon_save'" :disabled="prevent_opt.save"
:class="{'nz-btn-disabled':prevent_opt.save}"
style="margin-right: 20px">

View File

@@ -25,7 +25,7 @@ export default {
daysData: [],
severityData: this.$store.getters.severityData,
severityDataWeight: this.$store.getters.severityDataWeight,
dateFormatStr: localStorage.getItem('nz-default-dateFormat') ? localStorage.getItem('nz-default-dateFormat') : 'YYYY-MM-DD'
dateFormatStr: localStorage.getItem('nz-default-dateFormat') ? localStorage.getItem('nz-default-dateFormat') : 'YYYY-MM-DD HH:ss:mm'
}
},
// watch: {

View File

@@ -49,7 +49,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -62,7 +62,7 @@
</div>
</div>
<div class="alert-label-box">
<div class="alert-label-title">Endpoint</div>
<div class="alert-label-title">{{$t('asset.endpoint')}}</div>
<div class="alert-label-value">
<i class="nz-icon nz-icon-overview-endpoint monitorColor"></i>&nbsp;
<span>{{alertLabelData && alertLabelData.endpointNum ? alertLabelData.endpointNum : 0}}</span></div>
@@ -83,7 +83,7 @@
<div class="alert-label-value">{{alertLabelData && alertLabelData.project && alertLabelData.project.name ?alertLabelData.project.name : '--'}}</div>
</div>
<div class="alert-label-box">
<div class="alert-label-title">Endpoint</div>
<div class="alert-label-title">{{$t('asset.endpoint')}}</div>
<div class="alert-label-value">
<i class="nz-icon nz-icon-overview-endpoint monitorColor"></i>&nbsp;
<span>{{alertLabelData && alertLabelData.endpointNum ? alertLabelData.endpointNum : 0}}</span></div>
@@ -100,7 +100,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -152,7 +152,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -202,7 +202,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -276,7 +276,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -318,7 +318,8 @@ export default {
return {
alertLabelData: null,
loading: true,
heightList: 0
heightList: 0,
boxWidth: 0
}
},
watch: {
@@ -347,29 +348,45 @@ export default {
calcPosition () {
return function (position) {
const clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight
const leftOffSetView = this.detailList ? -80 : 10
const leftOffSet = this.detailList ? -80 : 10
const topOffSet = this.detailList ? 60 : 22
if (position.top > clientHeight / 2) {
return {
left: `${position.left + position.width + leftOffSet}px`,
top: `${position.top - this.heightList + topOffSet}px`
const clientWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth
let leftOffSetView = 0
let leftOffSet = this.detailList ? -80 : 10
let topOffSet = this.detailList ? 60 : 22
let topOffSetView = 0
let labelPosition = {
top: 0,
left: 0,
right: 0
}
if (this.alertTableDialog) {
let dialog = document.querySelector('#dialog-alert-massage .el-dialog')
if (!dialog) {
dialog = document.querySelector('#viewGraphDialog .el-dialog')
}
} else if (this.alertTableDialog) {
const dialog = document.querySelector('#dialog-alert-massage .el-dialog')
const dialogHeight = dialog.getBoundingClientRect()
if (dialogHeight) {
return {
left: `${position.left + position.width + 10 - dialogHeight.x}px`,
top: `${position.top - dialogHeight.y}px`
}
console.log(dialogHeight, 'dialogHeight')
leftOffSet = leftOffSet - dialogHeight.x
leftOffSetView = dialogHeight.x
topOffSet = topOffSet - dialogHeight.y
topOffSetView = topOffSet
}
if (position.top > clientHeight / 2) {
labelPosition = {
left: `${position.left + position.width + leftOffSet}px`,
top: `${position.top - this.heightList - topOffSetView}px`
}
} else {
return {
left: `${position.left + position.width + leftOffSetView}px`,
top: `${position.top}px`
labelPosition = {
left: `${position.left + position.width + leftOffSet}px`,
top: `${position.top + topOffSet}px`
}
}
if (position.left > clientWidth / 2) {
delete labelPosition.left
labelPosition.right = (clientWidth - position.left - leftOffSetView) + 'px'
}
return labelPosition
}
},
calcHeight () {
@@ -486,8 +503,10 @@ export default {
mounted () {
if (this.$refs.alertLabels) {
this.heightList = this.$refs.alertLabels.getBoundingClientRect().height
this.boxWidth = this.$refs.alertLabels.getBoundingClientRect().width
} else {
this.heightList = ''
this.heightList = 0
this.boxWidth = 0
}
},
beforeDestroy () {

View File

@@ -56,7 +56,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -107,7 +107,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -158,7 +158,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -208,7 +208,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>
@@ -282,7 +282,7 @@
<div class="alert-label-value" v-if="alertLabelData">
<i :class="alertLabelData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertLabelData.alertNum}}</div>

View File

@@ -0,0 +1,353 @@
<template>
<!-- chart外层箱子 -->
<div :class="{'panel-chart--fullscreen': isFullscreen}" class="panel-chart" :id="isFullscreen ? ('chart-screen-' + chartInfo.id ) : ('chart-local-' + chartInfo.id)">
<!-- 全屏的header-->
<chart-screen-header
v-if="isFullscreen"
:is-group="isGroup(chartInfo.type)"
:isError="isError"
:from="from"
:chartData="chartData"
:chart-info="chartInfo"
:showAllData.sync="showAllData"
:allDataLength="allDataLength"
@loadMore="loadMore"
@refresh="refresh"
@dateChange="dateChange"
@close="showFullscreen"
class="alert-message-info-header"
>
<span slot="title-icon" v-if="infoData['state']" style="margin-left: 5px" class="alert-message-state" :class="{'gray-bg': infoData['state'] == 3, 'red-bg': infoData['state'] == 1,'yellow-bg': infoData['state'] == 2}">{{$t(stateOptions.find(state=>state.value == infoData['state']).label)}}</span>
</chart-screen-header>
<!-- chart -->
<!-- 数据查询后传入chart组件chart组件内不查询只根据接传递的数据来渲染 -->
<div class="alert-message-info-box">
<div class="info-box-left">
<chart
ref="chart"
v-if="chartInfo.alertRule && chartInfo.alertRule.type !== 3"
:chart-data="chartData"
:chart-info="chartInfo"
:panelLock="panelLock"
:filter="filter"
:from="from"
@refreshLogs="refreshLogs"
:show-header="showHeader"
:isError="isError"
:loading="loading"
:minusTime="minusTime"
:multipleTime="multipleTime"
:isFullscreen="isFullscreen"
:showAllData="showAllData"
></chart>
<alertMessageInfoTab
class="alert-message-info-tab"
:noData="tabNoData"
:infoData="infoData" />
</div>
<div class="info-box-right">
<alertMessageInfoTimeLine :info-data="chartInfo" :time="time"/>
</div>
</div>
</div>
</template>
<script>
import ChartScreenHeader from '@/components/chart/ChartScreenHeader'
import chart from '@/components/chart/chart'
import { isChartPie, isTimeSeries, getGroupHeight, isGroup } from '@/components/chart/chart/tools'
import {alertMessage as alertMessageConstant, chartType, fromRoute} from '@/components/common/js/constants'
import bus from '@/libs/bus'
import axios from 'axios'
import chartTempData from '@/components/charts/chartTempData'
import logsData from '@/components/chart/logsData'
import lodash from 'lodash'
import alertMessageInfoTab from '@/components/common/alert/alertMessageInfoTab'
import alertMessageInfoTimeLine from '@/components/common/alert/alertMessageInfoTimeLine'
export default {
name: 'panelChart',
components: {
alertMessageInfoTab,
chart,
ChartScreenHeader,
alertMessageInfoTimeLine
},
props: {
chartInfo: Object, // 其中的param json串已转化为对象
timeRange: Array, // 时间范围
isFullscreen: Boolean,
panelLock: Boolean,
chartDetailInfo: Object,
from: String,
filter: {},
showHeader: {
type: Boolean,
default: true
}
},
data () {
return {
chartData: [],
loading: true,
isError: false,
multipleTime: false,
minusTime: '',
showAllData: false,
allDataLength: 0,
severityData: this.$store.getters.severityData,
severityDataWeight: this.$store.getters.severityDataWeight,
infoData: {},
timeLineData: [],
tabNoData: false,
timeLineNoData: false,
time: [],
stateOptions: alertMessageConstant.states
}
},
computed: {
headerH () {
return this.$store.getters.getHeaderH
},
headerHPadding () {
return this.$store.getters.getHeaderHPadding
}
},
methods: {
isGroup,
dateChange (filter, multipleTime) {
this.loading = true
// TODO assetInfo、endpointInfo、echarts等进行不同的处理
let startTime = bus.formateTimeToTime(filter.start_time)
let endTime = bus.formateTimeToTime(filter.end_time)
const step = bus.getStep(startTime, endTime)
startTime = this.$stringTimeParseToUnix(startTime)
endTime = this.$stringTimeParseToUnix(endTime)
const elements = this.chartInfo.elements || []
if (multipleTime.length) {
const minusTime = (new Date(bus.formateTimeToTime(filter.start_time)).getTime() - new Date(bus.formateTimeToTime(multipleTime[0])).getTime())
this.minusTime = minusTime
this.multipleTime = true
} else {
this.minusTime = ''
this.multipleTime = false
}
this.time = [startTime, endTime]
this.chartInfo.loaded && this.chartInfo.alertRule && this.chartInfo.alertRule.type !== 3 && this.query(elements, startTime, endTime, step)
},
// 参数 isRefresh 标识是否是刷新操作
getChartData (isRefresh, params) {
this.loading = true
// TODO assetInfo、endpointInfo、echarts等进行不同的处理
let startTime = ''
let endTime = ''
if (isRefresh) { // 刷新则视情况更新时间范围
const now = new Date(bus.computeTimezone(new Date().getTime()))
const origin = new Date(this.timeRange[1])
const numInterval = now.getTime() - origin.getTime()
if (numInterval >= 60000) { // 大于1分钟则start、end均往后移numInterval否则时间不变
startTime = bus.getNewTime(bus.formateTimeToTime(this.timeRange[0]), numInterval)
endTime = bus.timeFormate(now, 'YYYY-MM-DD HH:mm:ss')
} else {
startTime = bus.formateTimeToTime(this.timeRange[0])
endTime = bus.formateTimeToTime(this.timeRange[1])
}
} else {
startTime = bus.formateTimeToTime(this.timeRange[0])
endTime = bus.formateTimeToTime(this.timeRange[1])
}
const step = bus.getStep(startTime, endTime)
startTime = this.$stringTimeParseToUnix(startTime)
endTime = this.$stringTimeParseToUnix(endTime)
this.time = [startTime, endTime]
const elements = this.chartInfo.elements || []
this.chartInfo.loaded && this.query(elements, startTime, endTime, step, params)
},
query (elements, startTime, endTime, step, params) {
this.isError = false
this.allDataLength = 0
try {
switch (this.chartInfo.datasource) {
case 'metrics':
case 'logs': {
if (this.from === fromRoute.chartTemp) {
setTimeout(() => {
this.chartData = [chartTempData.data.result]
this.chartData.forEach(item => {
item.forEach(children => {
children.elements = elements[0]
})
})
this.loading = false
}, 100)
return
}
let urlPre = ''
if (this.chartInfo.datasource === 'metrics') {
urlPre += '/prom'
} else if (this.chartInfo.datasource === 'logs') {
urlPre += '/logs/loki'
}
let requests = elements.map((element) => {
if (this.from === fromRoute.chartTemp) {
return chartTempData
}
let query = `${urlPre}/api/v1/query_range?start=${startTime}&end=${endTime}&step=${step}`
if (isTimeSeries(this.chartInfo.type)) {
query += `&nullType=${this.chartInfo.param.nullType || 'null'}`
}
if (element.filter) {
query += `&filter=${element.filter}`
}
if (this.chartInfo.datasource === 'logs') {
query += '&format=1'
if (!params || params.descending) {
this.chartInfo.descending = true
query += '&direction=backward'
} else {
this.chartInfo.descending = false
query += '&direction=forward'
}
}
// if (isChartPie(this.chartInfo.type)) {
// query += `&statistics=${this.chartInfo.param.statistics || 'last'}`
// }
query += `&query=${encodeURIComponent(element.expression)}`
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 (this.chartInfo.datasource === 'logs') {
query += '&format=1'
}
// if (isChartPie(this.chartInfo.type)) {
// query += `&statistics=${this.chartInfo.param.statistics || 'last'}`
// }
query += `&query=${encodeURIComponent(element.expression)}`
return this.$get(query)
})
requests = requests.concat(multipleRequests)
}
const chartData = []
axios.all(requests).then((res) => {
res.forEach((r, rIndex) => {
if (rIndex < elements.length) {
if (r.status === 'success') {
r.data.result.forEach(item => {
item.elements = elements[rIndex]
this.allDataLength++
})
chartData.push(r.data.result)
} else {
chartData.push({ error: r.msg || r.error || r })
this.isError = true
}
} else {
if (r.status === 'success') {
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
if (this.chartInfo.type === 'log') {
this.logChartDataFormat()
}
}).catch(res => {
console.info(res)
}).finally(() => {
this.loading = false
})
break
}
}
} catch (e) {
this.loading = false
}
},
resize () {
this.$refs.chart.resize()
},
refresh () {
this.getChartData(true)
},
refreshLogs (params) {
this.getChartData(true, params)
},
logChartDataFormat () {
this.chartData.forEach((item, index) => {
const elements = this.chartInfo.elements[index]
item.forEach(row => {
row.elements = elements
})
})
},
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()
})
},
showFullscreen (show) {
this.$emit('showFullscreen', show, this.chartInfo)
},
getAlertMessageInfo () {
this.tabNoData = false
this.$get('/alert/message/' + this.chartInfo.id).then(res => {
if (res.code === 200) {
this.infoData = res.data
this.tabNoData = false
} else {
this.tabNoData = true
}
})
}
},
watch: {
timeRange: {
deep: true,
handler (n) {
this.refresh()
}
},
loading: {
immediate: true,
deep: true,
handler (n) {
// console.log(n)
}
}
},
mounted () {
this.chartInfo.loaded && this.getChartData()
this.showAllData = !this.showMultiple(this.chartInfo.type)
this.getAlertMessageInfo()
}
}
</script>

View File

@@ -0,0 +1,63 @@
<template>
<div class="info-box-header">
<div v-for="item in cardNames" :key="item.key" v-if="infoData[item.key]">
<div class="info-box-title">{{item.label}}</div>
<div v-if="item.key === 'summary' || item.key === 'description'" class="info-box-content">
{{infoData[item.key]}}
</div>
<div v-if="item.key==='labels'" class="info-box-content">
<span v-for="(item, i) in labelsSort(infoData.labels)" :key="i">
<span
@mouseenter="labelHover(infoData, item.label, true, true, $event)"
@mouseleave="labelHover(infoData, item.label, false, true,)">
<nz-alert-tag
v-if="item.label !== 'alertname' && item.label !== 'severity'" :key="item.label" :cursor-point="tagType(item.label) !== 'info'"
:label="item.label"
:type="tagType(item.label)"
style="margin: 5px 0 5px 5px;"
>
{{item.value}}
</nz-alert-tag>
</span>
</span>
</div>
<div v-if="item.key==='startAt'" class="info-box-content">
{{utcTimeToTimezoneStr(infoData[item.key])}}
</div>
</div>
<alertLabel
v-if="alertLabelShow"
:id="alertLabelId"
:that="alertLabelObj"
:type="alertLabelType"
></alertLabel>
</div>
</template>
<script>
import alertMessageLabelMixin from '@/components/common/alert/alertMessageLabelMixin'
import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
export default {
name: 'alertMessageInfoDetail',
props: {
infoData: {
type: Object
}
},
mixins: [alertMessageLabelMixin, alertLabelMixin],
data () {
return {
cardNames: [
{ key: 'summary', label: this.$t('alert.summary') },
{ key: 'description', label: this.$t('overall.remark') },
{ key: 'labels', label: this.$t('alert.list.labels') },
{ key: 'startAt', label: this.$t('alert.startAt') }
]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,156 @@
<template>
<div>
<el-tabs v-model="activeName" type="card" v-if="!nodata">
<el-tab-pane v-for="item in cardNames" :label="item.label" :name="item.key" :key="item.key">
<div v-if="item.key === 'detail' && activeName === 'detail'">
<alert-message-info-detail :info-data="infoData"/>
</div>
<div v-else-if="(activeName === item.key) && infoData[item.key]" class="no-position-alert-label">
<!-- <searchItemInfo :obj="findData(item.key)" :severityData="severityData" :fa-loading="false"></searchItemInfo>-->
<alertLabel
v-if="item.key !=='alertRule'"
:id="infoData[item.key].id"
:that="findData2(item.key)"
:alertTableDialog="true"
:type="item.key"/>
<alertRuleInfo
v-else
:id="infoData[item.key].id"
:severity-data="severityData"
:that="findData2(item.key)"
/>
</div>
<div v-else-if="item.key === 'trbShot' && activeName === 'trbShot'">
<div v-html="infoData.alertRule.trbShot">
</div>
</div>
</el-tab-pane>
</el-tabs>
<div v-else class="table-no-data">
<svg class="icon" aria-hidden="true">
<use xlink:href="#nz-icon-no-data-list"></use>
</svg>
<div class="table-no-data__title">No results found</div>
</div>
</div>
</template>
<script>
import alertMessageInfoDetail from '@/components/common/alert/alertMessageInfoDetail'
import searchItemInfo from '@/components/common/globalSearch/searchItemInfo'
import alertLabel from '@/components/common/alert/alertLabel'
import alertRuleInfo from '@/components/common/alert/alertRuleInfo'
// import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
export default {
name: 'alertMessageInfoTab',
components: {
alertMessageInfoDetail,
searchItemInfo,
alertLabel,
alertRuleInfo
},
// mixins: [alertLabelMixin],
props: {
infoData: {
type: Object
},
nodata: {
type: Boolean,
default: false
}
},
computed: {
severityData () {
return this.$store.getters.severityData
}
},
data () {
return {
activeName: 'detail',
cardNames: [{
key: 'detail',
label: this.$t('overall.detail')
}],
sysArr: [{
key: 'alertRule',
label: this.$t('alert.alertRule')
}, {
key: 'dc',
label: this.$t('overall.dc')
}, {
key: 'asset',
label: this.$t('overall.asset')
}, {
key: 'endpoint',
label: this.$t('overall.endpoint')
}, {
key: 'module',
label: this.$t('overall.module')
}, {
key: 'project',
label: this.$t('overall.project')
}]
}
},
watch: {
infoData: {
immediate: true,
handler (n) {
if (n) {
this.cardNames = [{
key: 'detail',
label: this.$t('overall.detail')
}]
this.sysArr.forEach(item => {
if (n[item.key]) {
this.cardNames.push(item)
}
})
if (n.alertRule && n.alertRule.trbShot) {
this.cardNames.push({
key: 'trbShot',
label: this.$t('alert.config.trbShot')
})
}
}
}
}
},
mounted () {
},
methods: {
findData (key) {
if (key) {
const obj = {
...this.$loadsh.cloneDeep(this.infoData[key]),
type: key
}
if (key === 'dc') {
obj.type = 'datacenter'
} else if (key === 'alertRule') {
obj.type = 'alertrule'
}
return { ...obj }
}
},
findData2 (key) {
if (key) {
const obj = {
...this.$loadsh.cloneDeep(this.infoData[key]),
type: key,
position: {
top: 0,
left: 0
}
}
return { ...obj }
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,242 @@
<template>
<div style="height: 100%;width: 100%">
<div class="time-line-header">
<span>{{$t('alert.relatedAlerts')}}</span>
<div class="scope-icon-box">
<div class="scope-box" v-for="item in scopeList" :class="item.isSelect ? 'is-select' : ''" :key="item.type" @click="scopeChange(item)" :title="item.label">
<i class="nz-icon" :class="selectIcon(item)" />
</div>
</div>
</div>
<el-timeline v-my-loading="loading" v-if="!noData && timeLineData.length">
<el-timeline-item
v-for="(item,index) in timeLineData"
:key="item.id"
:class="{
'only': timeLineData.length === 1 ,
'has-time': item.startAt,
'last': index === timeLineData.length-1 && index !==0
}"
:color="item.severity.color"
:timestamp="item.startAt?item.startAt: ''"
placement="top">
<div >
<div class='margin-b-10'>
<span slot="title-icon" v-if="item['state']" style="margin-left: 5px" class="alert-message-state" :class="{'gray-bg': item['state'] == 3, 'red-bg': item['state'] == 1,'yellow-bg': item['state'] == 2}">{{$t(stateOptions.find(state=>state.value == item['state']).label)}}</span>
<span class="time-line-item-header"> {{item.alertRule.name}}</span>
</div>
<div>
<span v-for="(label, i) in labelsSort(JSON.parse(item.labels))" :key="i">
<span
@mouseenter="labelHover(item, label.label, true, true, $event)"
@mouseleave="labelHover(item, label.label, false, true,)">
<nz-alert-tag
v-if="label.label !== 'alertname' && label.label !== 'severity'" :key="label.label" :cursor-point="tagType(label.label) !== 'info'"
:label="label.label"
:type="tagType(label.label)"
style="margin: 5px 0 5px 5px;"
>
{{label.value}}
</nz-alert-tag>
</span>
</span>
</div>
</div>
</el-timeline-item>
<div v-if="timeLineData.length >= total" style="text-align: center">{{$t('overall.noMoreData')}}</div>
<div v-else class="load-more-box">
<el-button size="small" @click="getTimeLineData()" :loading="loading">{{$t('overall.loadMore')}}</el-button>
</div>
</el-timeline>
<div class="table-no-data" v-else>
<svg class="icon" aria-hidden="true">
<use xlink:href="#nz-icon-no-data-list"></use>
</svg>
<div class="table-no-data__title">No results found</div>
</div>
<alertLabel
v-if="alertLabelShow"
:alertTableDialog="true"
:id="alertLabelId"
:that="alertLabelObj"
:type="alertLabelType"
></alertLabel>
</div>
</template>
<script>
import { alertMessage as alertMessageConstant } from '@/components/common/js/constants'
import alertMessageLabelMixin from '@/components/common/alert/alertMessageLabelMixin'
import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
export default {
name: 'alertMessageInfoTimeLine',
props: {
infoData: {
type: Object
},
time: {}
},
mixins: [alertMessageLabelMixin, alertLabelMixin],
computed: {
severityData () {
return this.$store.getters.severityData
}
},
watch: {
time: {
immediate: true,
deep: true,
handler (n) {
if (n && n.length) {
this.pageNo = 1
this.getTimeLineData()
}
}
}
},
data () {
return {
pageNo: 1,
pageSize: 20,
scope: ['asset', 'datacenter', 'project', 'module', 'endpoint', 'alertrule', 'hash'],
timeLineData: [],
lastDataTime: '',
loading: false,
dateFormatStr: localStorage.getItem('nz-default-dateFormat') ? localStorage.getItem('nz-default-dateFormat') : 'YYYY-MM-DD HH:ss:mm',
noData: false,
stateOptions: alertMessageConstant.states,
scopeList: [{
key: 'asset',
isSelect: true,
label: this.$t('overall.asset')
}, {
key: 'datacenter',
isSelect: true,
label: this.$t('overall.dc')
}, {
key: 'project',
isSelect: true,
label: this.$t('overall.project')
}, {
key: 'module',
isSelect: true,
label: this.$t('overall.module')
}, {
key: 'endpoint',
isSelect: true,
label: this.$t('overall.endpoint')
},
{
key: 'alertrule',
isSelect: true,
label: this.$t('alert.alertRule')
}, {
key: 'hash',
isSelect: true,
label: this.$t('overall.hash')
}
],
total: 20,
scopeChangeTimer: null
}
},
mounted () {
// this.getTimeLineData(1)
const dateFormatStr = localStorage.getItem('nz-default-dateFormat')
if (dateFormatStr) {
this.dateFormatStr = dateFormatStr.split(' ')[0]
} else {
this.dateFormatStr = 'YYYY-MM-DD'
}
},
methods: {
getTimeLineData () {
this.noData = false
this.loading = true
const params = {
pageNo: this.pageNo,
pageSize: this.pageSize,
scope: this.scopeList.filter(item => item.isSelect).map(item => item.key).join(','),
id: this.infoData.id,
state: '',
startAt: this.timezoneToUtcTimeStr(this.time[0] * 1000, 'YYYY-MM-DD HH:mm:ss'),
endAt: this.timezoneToUtcTimeStr(this.time[1] * 1000, 'YYYY-MM-DD HH:mm:ss'),
orderBy: '-startAt'
}
this.$get('/alert/message/rel', params).then(res => {
this.loading = false
if (res.code === 200) {
this.total = res.data.total
if (this.pageNo == 1) {
this.timeLineData = res.data.list
} else {
this.timeLineData.push(...res.data.list)
}
this.disposeTime(this.pageNo)
this.noData = false
this.pageNo++
} else {
this.noData = true
}
}).catch(() => {
this.loading = false
this.noData = true
})
},
disposeTime (pageNo) {
let i = (pageNo - 1) * this.pageSize
for (i; i < this.timeLineData.length; i++) {
const lastDataTime = this.timestampStr(this.timeLineData[i].startAt, this.dateFormatStr)
this.timeLineData[i].color = '#fa8'
if (this.lastDataTime !== lastDataTime) {
this.lastDataTime = lastDataTime
this.timeLineData[i].startAt = lastDataTime
} else {
this.timeLineData[i].startAt = ''
}
}
},
selectIcon (item) {
switch (item.key) {
case 'asset' : return 'nz-icon-overview-project'
case 'datacenter' : return 'nz-icon-Datacenter2'
case 'project' : return 'nz-icon-project'
case 'module' : return 'nz-icon-overview-module'
case 'endpoint' : return 'nz-icon-overview-endpoint'
case 'alertrule' : return 'nz-icon-Alertrule'
case 'hash' : return 'nz-icon-module5'
}
return 'nz-icon-module5'
},
scopeChange (scope) {
if (this.scopeChangeTimer) {
clearInterval(this.scopeChangeTimer)
this.scopeChangeTimer = null
}
this.loading = true
const isSelectArr = this.scopeList.filter(item => item.isSelect)
if (isSelectArr.length === this.scopeList.length) {
this.scopeList.forEach(item => {
item.isSelect = false
})
scope.isSelect = !scope.isSelect
} else if (isSelectArr.length === 1 && isSelectArr[0].key === scope.key) {
this.scopeList.forEach(item => {
item.isSelect = true
})
} else {
scope.isSelect = !scope.isSelect
}
this.scopeChangeTimer = setTimeout(() => {
this.pageNo = 1
this.getTimeLineData()
}, 100)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,67 @@
import nzAlertTag from '@/components/page/alert/nzAlertTag'
export default {
components: {
nzAlertTag
},
data () {
return {
exclusiveLabels: ['_id', 'severity', '__name__']
}
},
computed: {
tagType () {
return (key) => {
if (key == 'asset' || key == 'module' || key == 'project' || key == 'dc' || key == 'endpoint') {
return 'normal'
} else {
return 'info'
}
}
},
tagValue () {
return (key, value) => {
if (key == 'type') {
if (value == 1) {
value = this.$t('project.project.projectName')
} else if (value == 2) {
value = this.$t('module.module.module')
} else if (value == 3) {
value = this.$t('asset.asset')
}
}
return key + '' + value
}
}
},
methods: {
labelsSort (obj) {
const buildIn = ['asset', 'endpoint', 'module', 'cpu', 'datacenter', 'project', 'parent_asset', 'user']
if (typeof obj === 'string') obj = JSON.parse(obj)
const labels = JSON.parse(JSON.stringify(obj))
const result = []
for (const key of this.exclusiveLabels) {
Object.keys(labels).forEach(labelsKey => {
if (labelsKey.indexOf(key) !== -1) {
delete labels[labelsKey]
}
})
}
for (const key of buildIn) {
if (key in labels) {
if (key === 'datacenter') {
result.push({ label: 'dc', value: labels.datacenter })
delete labels.datacenter
} else {
result.push({ label: key, value: labels[key] })
}
delete labels[key]
}
}
Object.keys(labels).sort().forEach(key => {
result.push({ label: key, value: labels[key] })
delete labels[key]
})
return result
}
}
}

View File

@@ -35,7 +35,7 @@
<div class="alert-rule-value" v-if="alertRuleData">
<i :class="alertRuleData.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{alertRuleData.alertNum}}</div>

View File

@@ -90,7 +90,7 @@
fullscreen
:modal-append-to-body="false"
>
<panel-chart
<alertMessageInfo
:ref="'chart-fullscreen' + chartInfo.id"
:chart-info="chartInfo"
:from="fromRoute.alertMessage"
@@ -98,7 +98,7 @@
:is-fullscreen="true"
:time-range="searchTime"
@showFullscreen="showFullscreen"
></panel-chart>
></alertMessageInfo>
</el-dialog>
<el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')"
:visible.sync="dialogShowText"
@@ -131,6 +131,7 @@ import chart from '@/components/page/dashboard/overview/chart'
import { alertMessage as alertMessageConstant, fromRoute } from '@/components/common/js/constants'
import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox'
import detailViewRightMixin from '@/components/common/mixin/detailViewRightMixin'
import alertMessageInfo from '@/components/common/alert/alertMessageInfo'
import panelChart from '@/components/chart/panelChart'
import lodash from 'lodash'
import lineData from '@/components/chart/defaultLineData'
@@ -144,7 +145,8 @@ export default {
alertMessageTable,
alertSilenceBox,
chart,
panelChart
panelChart,
alertMessageInfo
},
props: {
from: String
@@ -426,9 +428,6 @@ export default {
this.deleteBox.show = true
},
messageDetail (row) {
if (row.alertRule.type == 3) {
return
}
this.$get('/alert/rule/' + row.alertRule.id).then(res => {
this.currentMsg = { ...row, alertRule: { ...res.data } }
this.$nextTick(() => {
@@ -635,8 +634,9 @@ export default {
},
queryDate () {
this.chartLoading = true
if (this.currentMsg.alertRule.type === 1) {
const chartInfo = lodash.cloneDeep(lineData)
let chartInfo = {}
if (this.currentMsg.alertRule.type === 1 || this.currentMsg.alertRule.type === 3) {
chartInfo = lodash.cloneDeep(lineData)
chartInfo.elements = [{}]
if (!isNaN(this.currentMsg.alertRule.threshold)) {
chartInfo.param.enable.thresholds = true
@@ -645,12 +645,9 @@ export default {
color: '#d64f40'
}]
}
chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, '')
chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
chartInfo.elements && (chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
} else if (this.currentMsg.alertRule.type === 2) {
const chartInfo = lodash.cloneDeep(logData)
chartInfo = lodash.cloneDeep(logData)
chartInfo.elements = [{}]
if (!isNaN(this.currentMsg.alertRule.threshold)) {
chartInfo.param.enable.thresholds = true
@@ -659,11 +656,15 @@ export default {
color: '#d64f40'
}]
}
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)))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
chartInfo.elements && (chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\r|\n+/g, ''))
}
chartInfo.id = this.currentMsg.id
chartInfo.name = this.currentMsg.alertRule.name
chartInfo.isAlertMessage = true
chartInfo.alertRule = this.currentMsg.alertRule
chartInfo.elements && (chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels))))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
},
exportLog ({ limit, descending }) {
const start = this.searchTime[0] ? this.searchTime[0] : getTime(-1, 'h')

View File

@@ -66,7 +66,7 @@
<div style="cursor: pointer" v-else-if="item.key === 'alertNum'">
<i :class="Number(getPathContent(item.key)) ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover('',true, $event)" @mouseleave="tooltipHover('',false, $event)"></i>
<div v-if="alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: position.left + 'px',top:position.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{getPathContent(item.key)}}</div>

View File

@@ -212,7 +212,7 @@ export const alertMessage = {
export const statisticsList = [
{ value: 'min', label: i18n.t('dashboard.panel.chartForm.statisticsVal.min') },
{ value: 'max', label: i18n.t('dashboard.panel.chartForm.statisticsVal.max') },
{ value: 'average', label: i18n.t('dashboard.panel.chartForm.statisticsVal.average') },
{ value: 'avg', label: i18n.t('dashboard.panel.chartForm.statisticsVal.average') },
{ value: 'total', label: i18n.t('dashboard.panel.chartForm.statisticsVal.total') },
{ value: 'first', label: i18n.t('dashboard.panel.chartForm.statisticsVal.first') },
{ value: 'last', label: i18n.t('dashboard.panel.chartForm.statisticsVal.last') },

View File

@@ -13,6 +13,7 @@ export const clickoutside = {
let oldValue
try {
oldValue = JSON.parse(JSON.stringify(binding.value.obj))
el.__newValue__ = oldValue
} catch (e) {
}
@@ -36,8 +37,8 @@ export const clickoutside = {
return false
}
if (oldValue) {
const newValue = JSON.parse(JSON.stringify(binding.value.obj))
if (unsavedChange == 'on' && !isEqual(oldValue, newValue)) {
// const newValue = JSON.parse(JSON.stringify(binding.value.obj))
if (unsavedChange == 'on' && !isEqual(oldValue, el.__newValue__)) {
MessageBox.confirm(i18n.t('tip.confirmCancel'), {
confirmButtonText: i18n.t('tip.yes'),
cancelButtonText: i18n.t('tip.no'),
@@ -66,6 +67,9 @@ export const clickoutside = {
el.__vueClickOutside__ = documentHandler
document.addEventListener('mousedown', documentHandler)
},
update (el, binding, vnode) {
el.__newValue__ = binding.value.obj
},
unbind (el, binding) {
// 解除事件监听
document.removeEventListener('mousedown', el.__vueClickOutside__)
@@ -199,9 +203,9 @@ export const cancelWithChange = {
if (!binding.value || !binding.value.obj) return
const unsavedChange = localStorage.getItem('nz-unnsaved-change')
const oldValue = JSON.parse(JSON.stringify(binding.value.obj))
el.__newValue__ = oldValue
function domClick (e) {
const newValue = JSON.parse(JSON.stringify(binding.value.obj))
if (unsavedChange == 'on' && !isEqual(oldValue, newValue)) {
if (unsavedChange == 'on' && !isEqual(oldValue, el.__newValue__)) {
MessageBox.confirm(i18n.t('tip.confirmCancel'), {
confirmButtonText: i18n.t('tip.yes'),
cancelButtonText: i18n.t('tip.no'),
@@ -218,6 +222,9 @@ export const cancelWithChange = {
el.__vueDomClick__ = domClick
el.addEventListener('click', domClick)
},
update (el, binding, vnode) {
el.__newValue__ = binding.value.obj
},
unbind: function (el, binding) {
// 解除事件监听
document.removeEventListener('click', el.__vueDomClick__)
@@ -900,15 +907,32 @@ export function getMetricTypeValue (queryItem, type) {
let copy = JSON.parse(JSON.stringify(queryItem))
switch (type) {
case 'min': {
const min = copy.sort((x, y) => { return parseFloat(x[1]) - parseFloat(y[1]) })[0][1]
let min = copy.sort((x, y) => {
const x1 = isNaN(x[1]) && !x[1] ? 0 : x[1]
const y1 = isNaN(y[1]) && !y[1] ? 0 : y[1]
return x1 - y1
})[0][1]
if (isNaN(min)) {
min = 0
}
return min
}
case 'max': {
const max = copy.sort((x, y) => { return parseFloat(y[1]) - parseFloat(x[1]) })[0][1]
let max = copy.sort((x, y) => {
const x1 = isNaN(x[1]) && !x[1] ? 0 : x[1]
const y1 = isNaN(y[1]) && !y[1] ? 0 : y[1]
return y1 - x1
})[0][1]
if (isNaN(max)) {
max = 0
}
return max
}
case 'average': {
copy = copy.map(t => parseFloat(t[1]))
case 'avg': {
copy = copy.map(t => {
const t1 = isNaN(t[1]) && !t[1] ? 0 : t[1]
return parseFloat(t1)
})
const sum = eval(copy.join('+'))
const avg = sum / copy.length
return avg
@@ -922,13 +946,30 @@ export function getMetricTypeValue (queryItem, type) {
return first
}
case 'total': {
copy = copy.map(t => parseFloat(t[1]))
copy = copy.map(t => {
const t1 = isNaN(t[1]) && !t[1] ? 0 : t[1]
return parseFloat(t1)
})
const total = eval(copy.join('+'))
return total
}
case 'range': {
const min = copy.sort((x, y) => { return parseFloat(x[1]) - parseFloat(y[1]) })[0][1]
const max = copy.sort((x, y) => { return parseFloat(y[1]) - parseFloat(x[1]) })[0][1]
let min = copy.sort((x, y) => {
const x1 = isNaN(x[1]) && !x[1] ? 0 : x[1]
const y1 = isNaN(y[1]) && !y[1] ? 0 : y[1]
return x1 - y1
})[0][1]
if (isNaN(min)) {
min = 0
}
let max = copy.sort((x, y) => {
const x1 = isNaN(x[1]) && !x[1] ? 0 : x[1]
const y1 = isNaN(y[1]) && !y[1] ? 0 : y[1]
return y1 - x1
})[0][1]
if (isNaN(max)) {
max = 0
}
return max - min
}
case 'different': {

View File

@@ -349,7 +349,7 @@ const cn = {
statisticsVal: {
min: 'Min',
max: 'Max',
average: 'Average',
avg: 'Avg',
total: 'Total',
first: 'First',
last: 'Last',

View File

@@ -365,7 +365,7 @@ const en = {
statisticsVal: {
min: 'Min',
max: 'Max',
average: 'Average',
avg: 'Avg',
total: 'Total',
first: 'First',
last: 'Last',

View File

@@ -167,14 +167,6 @@ export default {
this.$i18n.locale = this.lang
this.theme = res.data.user.theme
this.userInfo = res.data.user
// 获取可选语言
get('/sys/dict/all?type=lang').then(response => {
if (response.code === 200) {
const langList = response.data.map(lang => ({ name: lang.name, value: lang.value }))
this.$store.commit('setLangList', langList)
localStorage.setItem('nz-language-list', JSON.stringify(langList))
}
})
localStorage.setItem('nz-token', res.data.authToken)
if (res.data.authFlag === 1) {
if (res.data.authBind === 0) {

View File

@@ -1,4 +1,8 @@
import alertLabel from '@/components/common/alert/alertLabel'
export default {
components: {
alertLabel
},
data () {
return {
alertLabelShow: false,

View File

@@ -6,7 +6,7 @@
<el-tab-pane :label="$t('project.topology.data')" name="1">
<el-form v-model="selection.pen.data" class="pens-data" label-position="top">
<!--module-->
<el-form-item v-if="!selection.pen.type&&!fromDiagram" class="sub-box half-form-item" label="Module"
<el-form-item v-if="!selection.pen.type&&!fromDiagram" class="sub-box half-form-item" :label="$t('overall.module')"
prop="moduleId">
<el-select v-model="selection.pen.data.moduleId" :placeholder="$t('el.select.placeholder')"
:popper-append-to-body="true" popper-class="asset-dropdown right-box-select-top" size="small"
@@ -274,7 +274,7 @@
<!--</div>-->
<!--</el-collapse-item>-->
<!--样式-->
<el-collapse-item :title="'Style'" name="4" v-if="selection.pen">
<el-collapse-item :title="$t('project.topology.style')" name="4" v-if="selection.pen">
<div class="flex flex-warp">
<div class="props-pen-item" v-if="selection.pen&&!selection.pen.type">
@@ -650,7 +650,7 @@
</div>
</el-collapse-item>
<el-collapse-item :title="'Font'" name="5" v-if="selection.pen&&!selection.pen.type">
<el-collapse-item :title="$t('project.topology.font')" name="5" v-if="selection.pen&&!selection.pen.type">
<div class="flex flex-warp">
<div class="props-pen-item" style="width: 100%">
<div>{{ $t('project.topology.textContent') }}</div>

View File

@@ -1,7 +1,7 @@
<template>
<div class="info-content pop-data-info-content" v-if="showInfo">
<div class="info-box" v-my-loading="loading">
<div class="info-box-title">Module info</div>
<div class="info-box"v-my-loading="loading">
<div class="info-box-title">{{$t('overall.module')}} {{$t('project.topo.icon.info')}}</div>
<div class="info-box-content">
<div class="content-box">
<span class="content-title">ID</span>
@@ -16,7 +16,7 @@
<span class="content-text">{{moduleInfo.project ? moduleInfo.project.name : '--'}}</span>
</div>
<div class="content-box">
<span class="content-title">{{ $t('project.endpoint.endpoints') }}</span>
<span class="content-title">{{ $t('asset.endpoint') }}</span>
<span class="content-text">
<i class="nz-icon nz-icon-overview-endpoint monitorColor"></i>&nbsp;
<span>{{moduleInfo.endpointNum ? moduleInfo.endpointNum : 0}}</span>

View File

@@ -14,7 +14,7 @@
>
<template v-slot:default="slotProps">
<endpoint-table
style="height: calc(100% - 200px)"
style="height: 100%"
ref="dataTable"
:orderByFa="orderBy"
v-my-loading="tools.loading"

View File

@@ -422,7 +422,7 @@
</transition>
<!--thresholdConfig-->
<div class="form__sub-title">
<div class="form__sub-title" v-if="isThresholdConfig(chartConfig.type)">
<span>{{$t('dashboard.panel.chartForm.threshold')}}</span>
<el-switch
v-model="chartConfig.param.enable.thresholds"
@@ -431,7 +431,7 @@
></el-switch>
</div>
<transition name="el-zoom-in-top">
<el-row v-if="chartConfig.param.enable.thresholds">
<el-row v-if="chartConfig.param.enable.thresholds && isThresholdConfig(chartConfig.type)">
<el-form-item
v-for="(item,index) in chartConfig.param.thresholds"
:key="index"
@@ -487,7 +487,7 @@
<span @click="addColumns('')">
<i class="nz-icon nz-icon-create-square" style="font-weight: normal; font-size: 17px; cursor: pointer;"></i>
</span>
<span class="nz-icon-copy">
<span style="margin-right: 5px">
<i @click="copyColumns(index)" class="nz-icon nz-icon-override"></i>
</span>
<span class="nz-icon-minus-medium">

View File

@@ -1,5 +1,5 @@
<template>
<div v-clickoutside="{obj:editChart, func:clickOutside}" :class="boxClass" class="right-box right-box-chart">
<div v-clickoutside="{obj: editChart, func:clickOutside}" :class="boxClass" class="right-box right-box-chart">
<transition v-if="from !== 'chartTemp'" name="right-box">
<!-- <panel-box v-if="!showPanel.type" ref="panelBox2" :panel="panel" @reload="panelReload"></panel-box>-->
</transition>
@@ -207,6 +207,8 @@ export default {
},
// 保存endpoint
save () {
const self = this
let resetFlag = false // 页面是否需要重排
const arr = [this.$refs.chartForm.validate()]
arr.push(this.$refs['childrenFrom' + this.editChart.datasource].$refs.chartForm.validate())
Promise.all(arr).then(res => {
@@ -234,14 +236,19 @@ export default {
params.x = 0
params.y = 0
}
if (!params.x && !params.y && params.groupId) { // group 内的坐标需要单独计算
if (isNaN(params.y) && isNaN(params.y) && params.groupId) { // group 内的坐标需要单独计算
params.x = 0
params.y = 999
}
if (!params.x && !params.y) {
if (isNaN(params.y) && isNaN(params.y)) {
params.x = this.chartLastPosition.x + params.span > 12 ? 0 : this.chartLastPosition.x
params.y = this.chartLastPosition.y + 12
}
if (params.x + params.span > 12) {
params.x = 0
params.y += 1
resetFlag = true
}
delete params.panel
if (params.type === 'table') {
delete params.param.tags
@@ -253,8 +260,18 @@ export default {
this.$put('visual/panel/chart', params).then(response => {
if (response.code === 200) {
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') })
this.$emit('on-create-success', { id: this.panelId, name: this.panelName })
this.esc(true)
if (resetFlag) {
bus.$emit('creat-chart-success', {
...params,
cb: function () {
self.$emit('on-create-success', { id: this.panelId, name: this.panelName })
self.esc(true)
}
})
} else {
self.$emit('on-create-success', { id: this.panelId, name: this.panelName })
self.esc(true)
}
} else {
this.$message.error(response.msg)
}
@@ -263,8 +280,18 @@ export default {
this.$post('visual/panel/chart', params).then(response => {
if (response.code === 200) {
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') })
this.$emit('on-create-success', { id: this.panelId, name: this.panelName })
this.esc(true)
if (resetFlag) {
bus.$emit('creat-chart-success', {
...params,
cb: function () {
self.$emit('on-create-success', { id: this.panelId, name: this.panelName })
self.esc(true)
}
})
} else {
self.$emit('on-create-success', { id: this.panelId, name: this.panelName })
self.esc(true)
}
} else {
this.$message.error(response.msg)
}
@@ -457,42 +484,53 @@ export default {
if (obj.param && !obj.param.thresholds) {
obj.param.thresholds = []
}
this.editChart = obj
if (this.editChart.groupId === -1) {
this.editChart.groupId = ''
if (obj.groupId === -1) {
obj.groupId = ''
}
if (this.editChart.param) {
if (!this.editChart.param.min) {
this.editChart.param.min = 0
if (obj.param) {
if (!obj.param.min) {
obj.param.min = 0
}
if (!this.editChart.param.max) {
this.editChart.param.max = 100
if (!obj.param.max) {
obj.param.max = 100
}
if (!this.editChart.param.link) {
this.$set(this.editChart.param, 'link', '')
if (!obj.param.text && obj.param.display) {
obj.param.text = obj.param.display
}
if (!this.editChart.param.enable) {
this.editChart.param.enable = {
if (!obj.param.link) {
this.$set(obj.param, 'link', '')
}
if (!obj.param.enable) {
obj.param.enable = {
thresholds: false,
legend: false,
valueMapping: false
}
}
// this.editChart.varType = 1
if (this.editChart.param.enable.legend && !this.editChart.param.legend) {
this.editChart.param.legend = { placement: 'bottom', values: [], show: true }
if (obj.param.enable.legend && !obj.param.legend) {
obj.param.legend = { placement: 'bottom', values: [], show: true }
}
if (this.editChart.param.datasource && !this.editChart.param.datasource[0].legend) {
this.editChart.param.datasource[0].legend = ''
if (obj.param.datasource && !obj.param.datasource[0].legend) {
obj.param.datasource[0].legend = ''
}
if (this.editChart.param.valueMapping) {
this.editChart.param.valueMapping.forEach(item => {
if (obj.param.valueMapping) {
obj.param.valueMapping.forEach(item => {
if (!item.show) {
item.show = false
}
if (item.text && !item.display) {
item.display = item.text
} else if (!item.display) {
item.display = '{{A.$value}}'
}
if (item.columns && !item.column) {
item.column = item.columns
}
})
}
}
this.editChart = obj
}
},
'editChart.type': {
@@ -501,6 +539,12 @@ export default {
this.editChart.groupId = ''
}
}
},
editChart: {
deep: true,
handler () {
}
}
}
}

View File

@@ -93,6 +93,23 @@ export default {
default: return false
}
},
isThresholdConfig(type) {
switch (type) {
case 'line':
case 'area':
case 'point':
return true
case 'table':
case 'stat':
case 'hexagon':
case 'gauge':
case 'treemap':
case 'pie':
case 'bar':
return false
default: return false
}
},
isShowLegendVlaues (type) {
switch (type) {
case 'line':

View File

@@ -165,7 +165,7 @@ export default {
label: this.$t('dashboard.panel.chartForm.legend'),
value: 'legend'
}, {
label: this.$t('config.assetLabel.all'),
label: this.$t('project.topology.none'),
value: 'none'
}
],
@@ -346,6 +346,7 @@ export default {
},
showMapping (index) {
this.chartConfig.param.valueMapping[index].show = !this.chartConfig.param.valueMapping[index].show
this.change()
},
mappingItemChange (index, type) {
const mapping = this.chartConfig.param.valueMapping[index]
@@ -416,6 +417,7 @@ export default {
},
showColumns (index) {
this.chartConfig.param.columns[index].show = !this.chartConfig.param.columns[index].show
this.change()
},
tagsChange (newTags) {
this.chartConfig.param.tags = newTags

View File

@@ -384,7 +384,7 @@
</transition>
<!--thresholdConfig-->
<div class="form__sub-title">
<div class="form__sub-title" v-if="isThresholdConfig(chartConfig.type)">
<span>{{$t('dashboard.panel.chartForm.threshold')}}</span>
<el-switch
v-model="chartConfig.param.enable.thresholds"
@@ -393,7 +393,7 @@
></el-switch>
</div>
<transition name="el-zoom-in-top">
<el-row v-if="chartConfig.param.enable.thresholds">
<el-row v-if="chartConfig.param.enable.thresholds && isThresholdConfig(chartConfig.type)">
<el-form-item
v-for="(item,index) in chartConfig.param.thresholds"
:key="index"
@@ -449,7 +449,7 @@
<span @click="addColumns('')">
<i class="nz-icon nz-icon-create-square" style="font-weight: normal; font-size: 17px; cursor: pointer;"></i>
</span>
<span class="nz-icon-copy">
<span style="margin-right: 5px">
<i @click="copyColumns(index)" class="nz-icon nz-icon-override"></i>
</span>
<span class="nz-icon-minus-medium">

View File

@@ -86,7 +86,7 @@
</span>
</template>
<span v-else-if="item.prop === 'state'">
<span class="alert-message-state" :class="{'green-bg': scope.row['state'] == 3, 'red-bg': scope.row['state'] == 1,'yellow-bg': scope.row['state'] == 2}">
<span class="alert-message-state" :class="{'gray-bg': scope.row['state'] == 3, 'red-bg': scope.row['state'] == 1,'yellow-bg': scope.row['state'] == 2}">
{{$t(stateOptions.find(state=>state.value == scope.row['state']).label)}}
</span>
</span>
@@ -101,7 +101,7 @@
fixed="right">
<div slot="header" class="table-operation-title">{{$t('overall.option')}}</div>
<div slot-scope="scope" class="table-operation-items">
<button v-if="scope.row.alertRule&&scope.row.alertRule.type !== 3" class="table-operation-item" @click="$emit('messageDetail', scope.row)"><i class="nz-icon nz-icon-view1"></i></button>
<button v-if="scope.row.alertRule" class="table-operation-item" @click="$emit('messageDetail', scope.row)"><i class="nz-icon nz-icon-view1"></i></button>
<el-dropdown v-has="['alertMessage_expired', 'alertSilence_add']" size="medium" trigger="click" @command="tableOperation">
<div class="table-operation-item table-operation-item--more">
<i class="nz-icon nz-icon-more3"></i>
@@ -139,19 +139,16 @@
import bus from '../../../../libs/bus'
import axios from 'axios'
import table from '@/components/common/mixin/table'
import nzAlertTag from '../../../page/alert/nzAlertTag'
import chartDataFormat from '../../../charts/chartDataFormat'
import alertRuleInfo from '../../alert/alertRuleInfo'
import alertLabel from '../../alert/alertLabel'
import { calcDurationByStringTimeB } from '../../js/tools'
import { alertMessage as alertMessageConstant } from '@/components/common/js/constants'
import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
import alertMessageLabelMixin from '@/components/common/alert/alertMessageLabelMixin'
export default {
name: 'alertMessageTable',
components: {
nzAlertTag,
alertRuleInfo: alertRuleInfo,
alertLabel: alertLabel
},
props: {
nowTime: {
@@ -165,7 +162,7 @@ export default {
loading: Boolean,
chartAlertList: Boolean
},
mixins: [table, bus, alertLabelMixin],
mixins: [table, bus, alertLabelMixin, alertMessageLabelMixin],
data () {
return {
/* 二级列表相关 */
@@ -176,7 +173,6 @@ export default {
graphShow: false,
chartDatas: [],
sameLabels: ['instance', 'module', 'project', 'asset', 'endpoint', 'dc'],
exclusiveLabels: ['_id', 'severity', '__name__'],
legend: [],
searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
currentMsg: {},
@@ -254,29 +250,6 @@ export default {
}
},
computed: {
tagType () {
return (key) => {
if (key == 'asset' || key == 'module' || key == 'project' || key == 'dc' || key == 'endpoint') {
return 'normal'
} else {
return 'info'
}
}
},
tagValue () {
return (key, value) => {
if (key == 'type') {
if (value == 1) {
value = this.$t('project.project.projectName')
} else if (value == 2) {
value = this.$t('module.module.module')
} else if (value == 3) {
value = this.$t('asset.asset')
}
}
return key + '' + value
}
},
getDuration () {
return function (record) {
if (record.endAt) {
@@ -297,35 +270,6 @@ export default {
}
})
},
labelsSort (obj) {
const buildIn = ['asset', 'endpoint', 'module', 'cpu', 'datacenter', 'project', 'parent_asset', 'user']
if (typeof obj === 'string') obj = JSON.parse(obj)
const labels = JSON.parse(JSON.stringify(obj))
const result = []
for (const key of this.exclusiveLabels) {
Object.keys(labels).forEach(labelsKey => {
if (labelsKey.indexOf(key) !== -1) {
delete labels[labelsKey]
}
})
}
for (const key of buildIn) {
if (key in labels) {
if (key === 'datacenter') {
result.push({ label: 'dc', value: labels.datacenter })
delete labels.datacenter
} else {
result.push({ label: key, value: labels[key] })
}
delete labels[key]
}
}
Object.keys(labels).sort().forEach(key => {
result.push({ label: key, value: labels[key] })
delete labels[key]
})
return result
},
chartUnitChange: function (unit) {
this.chartUnit = unit
this.$nextTick(() => {

View File

@@ -45,7 +45,7 @@
<span style="cursor: pointer" @click="queryMessage(scope.row)">
<i :class="scope.row.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover(scope.row,true, $event)" @mouseleave="tooltipHover(scope.row,false, $event)"></i>
<div v-if="scope.row.alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: scope.row.left + 'px',top:scope.row.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{scope.row.alertNum}}</div>

View File

@@ -69,7 +69,7 @@
<span style="cursor: pointer" @click="$emit('showBottomBox', 'alertMessageTab', scope.row)">
<i :class="scope.row.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover(scope.row,true, $event)" @mouseleave="tooltipHover(scope.row,false, $event)"></i>
<div v-if="scope.row.alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: scope.row.left + 'px',top:scope.row.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{scope.row.alertNum}}</div>

View File

@@ -76,7 +76,7 @@
<span style="cursor: pointer" @click="showBottomBox('endpointAlertMessage', scope.row)">
<i :class="scope.row.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover(scope.row,true, $event)" @mouseleave="tooltipHover(scope.row,false, $event)"></i>
<div v-if="scope.row.alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: scope.row.left + 'px',top:scope.row.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{scope.row.alertNum}}</div>

View File

@@ -55,7 +55,7 @@
<span style="cursor: pointer" @click="showBottomBox('moduleAlertMessage', scope.row)">
<i :class="scope.row.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover(scope.row,true, $event)" @mouseleave="tooltipHover(scope.row,false, $event)"></i>
<div v-if="scope.row.alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: scope.row.left + 'px',top:scope.row.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{scope.row.alertNum}}</div>

View File

@@ -59,7 +59,7 @@
<span style="cursor: pointer" @click="jumpAlertMessage(scope.row)">
<i :class="scope.row.alertNum ? 'red' : 'green'" class="nz-icon nz-icon-overview-alert vertical-align-top;" @mouseenter="tooltipHover(scope.row,true, $event)" @mouseleave="tooltipHover(scope.row,false, $event)"></i>
<div v-if="scope.row.alertNumtooltipShow" class="alert-days-info-tooltip" :style="{left: scope.row.left + 'px',top:scope.row.top + 'px'}">
<div class="tooltip-title">Alert message (active)</div>
<div class="tooltip-title">{{$t('project.topology.alert')}}({{$t('asset.pingActive')}})</div>
<div class="severity-info" style='justify-content: space-between'>
<div class="severity-name">{{$t('overall.result.total')}}</div>
<div class="severity-value">{{scope.row.alertNum}}</div>

View File

@@ -113,7 +113,7 @@
fullscreen
:modal-append-to-body="false"
>
<panel-chart
<alertMessageInfo
:ref="'chart-fullscreen' + chartInfo.id"
:chart-info="chartInfo"
:from="fromRoute.alertMessage"
@@ -121,7 +121,7 @@
:is-fullscreen="true"
:time-range="searchTimeDialog"
@showFullscreen="showFullscreen"
></panel-chart>
></alertMessageInfo>
</el-dialog>
<!--全屏-->
<el-dialog class="nz-dialog table-chart-dialog" :title="$t('alert.config.trbShot')"
@@ -157,7 +157,7 @@ import { alertMessage as alertMessageConstant, fromRoute } from '@/components/co
import alertSilenceBox from '@/components/common/rightBox/alertSilenceBox'
import clickSearch from '@/components/common/labelFilter/clickSearch'
import routerPathParams from '@/components/common/mixin/routerPathParams'
import panelChart from '@/components/chart/panelChart'
import alertMessageInfo from '@/components/common/alert/alertMessageInfo'
import lineData from '@/components/chart/defaultLineData'
import logData from '@/components/chart/defaultLogData'
import lodash from 'lodash'
@@ -172,7 +172,7 @@ export default {
deleteButton,
alertSilenceBox,
clickSearch,
panelChart
alertMessageInfo
},
mixins: [dataListMixin, routerPathParams],
data () {
@@ -578,9 +578,6 @@ export default {
})
},
messageDetail (row) {
if (row.alertRule.type == 3) {
return
}
this.$get('/alert/rule/' + row.alertRule.id).then(res => {
this.currentMsg = { ...row, alertRule: { ...res.data } }
this.$nextTick(() => {
@@ -606,8 +603,9 @@ export default {
},
queryDate () {
this.chartLoading = true
if (this.currentMsg.alertRule.type === 1) {
const chartInfo = lodash.cloneDeep(lineData)
let chartInfo = {}
if (this.currentMsg.alertRule.type === 1 || this.currentMsg.alertRule.type === 3) {
chartInfo = lodash.cloneDeep(lineData)
chartInfo.elements = [{}]
if (!isNaN(this.currentMsg.alertRule.threshold)) {
chartInfo.param.enable.thresholds = true
@@ -616,12 +614,9 @@ export default {
color: '#d64f40'
}]
}
chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, '')
chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels)))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
chartInfo.elements && (chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\"/g, '\'').replace(/\r|\n+/g, ''))
} else if (this.currentMsg.alertRule.type === 2) {
const chartInfo = lodash.cloneDeep(logData)
chartInfo = lodash.cloneDeep(logData)
chartInfo.elements = [{}]
if (!isNaN(this.currentMsg.alertRule.threshold)) {
chartInfo.param.enable.thresholds = true
@@ -630,11 +625,15 @@ export default {
color: '#d64f40'
}]
}
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)))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
chartInfo.elements && (chartInfo.elements[0].expression = this.currentMsg.alertRule.expr.replace(/\r|\n+/g, ''))
}
chartInfo.id = this.currentMsg.id
chartInfo.name = this.currentMsg.alertRule.name
chartInfo.isAlertMessage = true
chartInfo.alertRule = this.currentMsg.alertRule
chartInfo.elements && (chartInfo.elements[0].filter = encodeURIComponent(decodeURIComponent(this.promQueryParamLabels(this.currentMsg.labels))))
chartInfo.unit = this.currentMsg.alertRule.unit
this.showFullscreen(true, chartInfo)
},
exportLog ({ limit, descending }) {
const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)

View File

@@ -134,7 +134,7 @@
show-overflow-tooltip
>
<template slot-scope="scope" :column="item">
<template v-if="item.prop === 'time'">{{utcTimeToTimezoneStr(scope.row.time)}}</template>
<template v-if="item.prop === 'time'">{{timeFormate(scope.row.time)}}</template>
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
<template v-else>-</template>
</template>

View File

@@ -319,11 +319,11 @@ export default {
nowTimeType: JSON.stringify(this.nowTimeType),
searchTime: JSON.stringify(this.searchTime)
}
// this.dateChange()
// this.getTableData()
const path = this.fromRoute.panel
this.updatePath(param, path)
this.getData(this.filter)
this.dateChange()
// this.getData(this.filter)
this.$refs.chartList.cleanData()
},

View File

@@ -192,7 +192,7 @@ export default new Vue({
statisticsRlt = dataArray.reduce(function (a, b) {
return b > a ? b : a
})
} else if (statistics === 'average') { // average:平均值
} else if (statistics === 'avg') { // avg:平均值
let sum = 0
dataArray.forEach((item) => {
sum = Number(sum) + Number(item)

View File

@@ -14,7 +14,7 @@ import router from './router'
import VueResource from 'vue-resource'
import axios from 'axios'
import { hasPermission, hasButton } from './permission'
import loadsh from 'lodash'
import plTable from 'pl-table'
import 'pl-table/themes/index.css'
@@ -62,6 +62,7 @@ Vue.prototype.$post = post
Vue.prototype.$get = get
Vue.prototype.$put = put
Vue.prototype.$delete = del
Vue.prototype.$loadsh = loadsh
Vue.prototype.$CONSTANTS = constants
Vue.prototype.$TOOLS = tools
Vue.prototype.$bottomBoxWindow = bottomBoxWindow // 底部上滑框控制
@@ -97,24 +98,24 @@ Vue.mixin({
}
},
methods: {
utcTimeToTimezone: function (time) {
utcTimeToTimezone: function (time) { // 将utc时间 转为系统设者的时间 返回时间戳
if (time) {
return bus.UTCTimeToConfigTimezone(time)
}
},
utcTimeToTimezoneStr: function (time) {
utcTimeToTimezoneStr: function (time) { // 将utc时间 转为系统设者的时间 返回String
if (time) {
return bus.timeFormate(bus.UTCTimeToConfigTimezone(time), localStorage.getItem('nz-default-dateFormat') ? localStorage.getItem('nz-default-dateFormat') : localStorage.getItem('nz-default-dateFormat') ? localStorage.getItem('nz-default-dateFormat') : 'YYYY-MM-DD HH:mm:ss')
return bus.timeFormate(bus.UTCTimeToConfigTimezone(time), localStorage.getItem('nz-default-dateFormat') || 'YYYY-MM-DD HH:mm:ss')
} else {
return '-'
}
},
timezoneToUtcTime: function (time) {
timezoneToUtcTime: function (time) { // 将系统设者的时间 转为utc时间 返回时间戳
if (time) {
return bus.configTimezoneToUTCTime(time)
}
},
timezoneToUtcTimeStr: function (time, fmt) {
timezoneToUtcTimeStr: function (time, fmt) { // 将系统设者的时间 转为utc时间 返回String
if (!fmt) {
fmt = localStorage.getItem('nz-default-dateFormat') || 'YYYY-MM-DD HH:mm:ss'
}
@@ -122,7 +123,7 @@ Vue.mixin({
return bus.timeFormate(this.timezoneToUtcTime(time), fmt)
}
},
timestampStr: function (time, fmt) {
timestampStr: function (time, fmt) { // 将utc时间 转为系统设者的时间 返回String
const date = new Date(time)
const localOffset = date.getTimezoneOffset() * 60 * 1000 // 默认 一分钟显示时区偏移的结果
const dateStr = new Date(time).getTime() + localOffset
@@ -135,6 +136,9 @@ Vue.mixin({
return '-'
}
},
timeFormate (time) {
return bus.timeFormate(time)
},
hasButton (code) {
return hasButton(this.$store.getters.buttonList, code)
},

View File

@@ -101,6 +101,14 @@ const user = {
localStorage.setItem('nz-mfa-enable', Number(res.data.mfaAuthEnable) ? 1 : 0)
store.commit('setLanguage', res.data.user.lang || defaultAppearance.language)
store.commit('setTimeFormatMain', localStorage.getItem('nz-default-dateFormat') || 'YYYY-MM-DD HH:mm:ss')
// 获取可选语言
get('/sys/dict/all?type=lang').then(response => {
if (response.code === 200) {
const langList = response.data.map(lang => ({ name: lang.name, value: lang.value }))
store.commit('setLangList', langList)
localStorage.setItem('nz-language-list', JSON.stringify(langList))
}
})
post('/sys/user/permissions', { token: res.data.token }).then(res => {
const menuList = sortByOrderNum(res.data.menus)
// localStorage.setItem('nz-user-permissions', JSON.stringify(res.data.buttons))