feat: alertMessage 详情开发

This commit is contained in:
zhangyu
2022-03-28 16:44:40 +08:00
parent b2ec953c95
commit fc5a9a70c0
7 changed files with 414 additions and 18 deletions

View File

@@ -0,0 +1,31 @@
.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{
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;
.nz-chart {
height: 36%;
margin-bottom: 20px;
border: 1px solid $--border-color-light;
}
.alert-message-info-tab{
flex: 1;
}
}
.info-box-right{
flex: 1;
}
}
}

View File

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

View File

@@ -26,7 +26,10 @@
</span> </span>
</el-popover> </el-popover>
</span> </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"> <div class="chart-header__tools">
<span v-if="chartInfo.remark" class="chart-header__tool top-tool-btn-group"> <span v-if="chartInfo.remark" class="chart-header__tool top-tool-btn-group">
<el-tooltip :content="chartInfo.remark" effect="light" placement="top"> <el-tooltip :content="chartInfo.remark" effect="light" placement="top">

View File

@@ -72,6 +72,15 @@ export default {
methods: { methods: {
initChart (chartOptions = this.chartOption) { initChart (chartOptions = this.chartOption) {
const chartOption = lodash.cloneDeep(chartOptions) 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.legends = []
this.series = chartOption.series = this.handleTimeSeries(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends this.series = chartOption.series = this.handleTimeSeries(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends
if (!this.series.length) { if (!this.series.length) {

View File

@@ -0,0 +1,330 @@
<template>
<!-- chart外层箱子 -->
<div :class="{'panel-chart--fullscreen': isFullscreen}" class="panel-chart" :id="isFullscreen ? ('chart-screen-' + chartInfo.id ) : ('chart-local-' + chartInfo.id)" v-my-loading="loading">
<!-- 全屏的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"> active </span>
</chart-screen-header>
<!-- chart -->
<!-- 数据查询后传入chart组件chart组件内不查询只根据接传递的数据来渲染 -->
<div class="alert-message-info-box">
<div class="info-box-left">
<chart
ref="chart"
: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"
v-if="!isGroup(chartInfo.type) || !chartInfo.param.collapse"
></chart>
<alertMessageInfoTab class="alert-message-info-tab">
</alertMessageInfoTab>
</div>
<div class="info-box-right">
时间
</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 { 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'
export default {
name: 'panelChart',
components: {
alertMessageInfoTab,
chart,
ChartScreenHeader
},
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
}
},
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.chartInfo.loaded && 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)
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)
}
},
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)
}
}
</script>

View File

@@ -0,0 +1,26 @@
<template>
<div>
<el-tabs v-model="activeName" type="card">
<el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane>
<el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
<el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
export default {
name: 'alertMessageInfoTab',
data () {
return {
activeName: '',
}
}
}
</script>
<style scoped>
</style>

View File

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