This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nezha-nezha-fronted/nezha-fronted/src/components/common/table/alert/alertMessageTable.vue

631 lines
22 KiB
Vue
Raw Normal View History

<template>
<div style="height: 100%;">
<!--表格-->
<el-table
id="alertMessageTable"
ref="dataTable"
:cell-class-name="labelsClassName"
:data="tableData"
:height="height"
border
@header-dragend="dragend"
@sort-change="tableDataSort"
@selection-change="selectionChange"
@row-dblclick="(row)=>{rowDblclick(row)}"
>
<el-table-column
:resizable="false"
align="center"
type="selection"
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-if="item.show"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"
:min-width="`${item.minWidth}`"
:prop="item.prop"
:resizable="true"
:sort-orders="['ascending', 'descending']"
:sortable="item.sortable"
:width="`${item.width}`"
>
<template slot-scope="scope" :column="item">
<template v-if="item.prop === 'alertRule'">
<div v-if="scope.row.alertRule&&scope.row.alertRule.name" >
<span
@mouseenter="alertMessageHover(scope.row, true, $event)"
@mouseleave="alertMessageHover(scope.row, false)"
>{{scope.row.alertRule?scope.row.alertRule.name : '--'}}</span>
</div>
<template v-else>-</template>
</template>
<template v-else-if="item.prop === 'summary'">
<template v-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template>
<template v-else>-</template>
</template>
<template v-else-if="item.prop === 'description'">
<template v-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template>
<span v-else>-</span>
</template>
<template v-else-if="item.prop === 'remark'">
<template v-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template>
<span v-else>-</span>
</template>
<span v-else-if="item.prop === 'severityId'&&scope.row['severity']" class="severity">
2021-08-05 22:25:55 +08:00
<i :style="{color:scope.row['severity'].color,'font-size':'12px','margin-right':'5px'}" class="nz-icon nz-icon-circle"></i> {{scope.row['severity'].name}}
</span>
<span v-else-if="item.prop === 'startAt'">{{utcTimeToTimezoneStr(scope.row.startAt)}}</span>
2022-03-02 17:26:40 +08:00
<span v-else-if="item.prop === 'lastAt'">{{utcTimeToTimezoneStr(scope.row.lastAt)}}</span>
<template v-else-if="item.prop === 'duration'">
<el-tooltip :disabled="!scope.row.endAt" effect="light" placement="right">
<div slot="content">
{{$t('config.terminallog.endTime')}}<br/>
{{utcTimeToTimezoneStr(scope.row.endAt)}}
</div>
<span>{{getDuration(scope.row)}}</span>
</el-tooltip>
</template>
<template v-else-if="item.prop === 'labels'" class="labels">
2021-08-05 22:25:55 +08:00
<span v-for="(item, i) in labelsSort(scope.row.labels)" :key="i">
<span
@mouseenter="labelHover(scope.row, item.label, true, $event)"
@mouseleave="labelHover(scope.row, item.label, false)">
<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;"
2021-08-05 22:25:55 +08:00
>
{{item.value}}
</nz-alert-tag>
</span>
</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}">
{{$t(stateOptions.find(state=>state.value == scope.row['state']).label)}}
</span>
</span>
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
<template v-else>-</template>
</template>
</el-table-column>
<el-table-column
v-if="showOption"
:resizable="false"
:width="operationWidth"
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>
<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>
</div>
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top">
<!-- <el-dropdown-item :command="['showText', scope.row]"><i class="nz-icon nz-icon-guzhangshuju"></i><span class="operation-dropdown-text">{{$t('alert.config.trbShot')}}</span></el-dropdown-item>-->
<el-dropdown-item v-has="'alertMessage_view'" :command="['delete', scope.row]"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item>
<el-dropdown-item v-has="'alertSilence_add'" :command="['fastSilence', scope.row, 'alertMessage']"><i class="nz-icon nz-icon-fast-silence"></i><span class="operation-dropdown-text">{{$t('overall.silenceAlert')}}</span></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-table-column>
<template slot="empty">
<div v-if="!loading" 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 v-else>&nbsp;</div>
2021-08-05 22:25:55 +08:00
</template>
</el-table>
<alertRuleInfo v-if="alertRuleShow" :id="alertRuleId" :severity-data="severityData" :that="alertRuleObj.alertRule" @showText="$emit('showText',alertRuleObj)"></alertRuleInfo>
<alertLabel
v-if="alertLabelShow"
:id="alertLabelId"
:that="alertLabelObj"
:type="alertLabelType"
:alert-table-dialog="chartAlertList"
></alertLabel>
</div>
</template>
<script>
2021-04-13 20:33:12 +08:00
import bus from '../../../../libs/bus'
2021-03-19 18:52:19 +08:00
import axios from 'axios'
2021-04-13 20:33:12 +08:00
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'
2021-04-13 20:33:12 +08:00
import { calcDurationByStringTimeB } from '../../js/tools'
import {alertMessage as alertMessageConstant} from "@/components/common/js/constants";
2021-03-19 18:52:19 +08:00
export default {
name: 'alertMessageTable',
components: {
2021-04-13 20:33:12 +08:00
nzAlertTag,
2021-03-19 18:52:19 +08:00
alertRuleInfo: alertRuleInfo,
alertLabel: alertLabel
2021-03-19 18:52:19 +08:00
},
props: {
2021-04-13 20:33:12 +08:00
nowTime: {
type: String
},
showOption: {
type: Boolean,
default: true
},
2021-10-22 17:47:42 +08:00
alertMessageTabNew: Boolean,
loading: Boolean,
chartAlertList: Boolean
2021-03-19 18:52:19 +08:00
},
2021-04-13 20:33:12 +08:00
mixins: [table, bus],
2021-03-19 18:52:19 +08:00
data () {
return {
/* 二级列表相关 */
tabList: [], // 二级列表的标签
tabDetailList: [], // 多个详情
stateOptions: alertMessageConstant.states,
2021-03-19 18:52:19 +08:00
// 详情相关
graphShow: false,
chartDatas: [],
sameLabels: ['instance', 'module', 'project', 'asset', 'endpoint', 'dc'],
exclusiveLabels: ['_id', 'severity', '__name__'],
2021-03-19 18:52:19 +08:00
legend: [],
searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
currentMsg: {},
chartUnit: 5,
severityData: [],
2021-03-19 18:52:19 +08:00
tableTitle: [
2021-03-19 18:52:19 +08:00
{
label: 'ID',
prop: 'id',
show: true,
2021-05-25 16:13:59 +08:00
width: 160,
sortable: 'custom'
2021-03-19 18:52:19 +08:00
}, {
2021-05-10 15:59:39 +08:00
label: this.$t('alert.rule'),
2021-03-19 18:52:19 +08:00
prop: 'alertRule',
show: true,
2021-05-08 09:40:53 +08:00
width: 180,
sortable: 'custom'
2021-03-19 18:52:19 +08:00
}, {
label: this.$t('alert.list.labels'),
prop: 'labels',
show: true,
NotSet: true,
2021-05-08 09:40:53 +08:00
minWidth: 250,
sortable: 'custom'
2021-03-19 18:52:19 +08:00
}, {
label: this.$t('alert.severity'),
prop: 'severityId',
2021-03-19 18:52:19 +08:00
show: true,
2021-05-08 09:40:53 +08:00
width: 110,
sortable: 'custom'
2021-03-19 18:52:19 +08:00
}, {
label: this.$t('alert.summary'),
prop: 'summary',
show: true,
minWidth: 200
}, {
label: this.$t('overall.remark'),
2021-03-19 18:52:19 +08:00
prop: 'description',
show: true,
minWidth: 200
}, {
label: this.$t('alert.list.state'),
prop: 'state',
show: true,
width: 100,
sortable: 'custom'
}, {
2021-03-19 18:52:19 +08:00
label: this.$t('alert.startAt'),
prop: 'startAt',
2022-03-02 17:26:40 +08:00
show: false,
width: 150,
sortable: 'custom'
}, {
label: this.$t('alert.lastAt'),
prop: 'lastAt',
2021-03-19 18:52:19 +08:00
show: true,
2021-05-08 09:40:53 +08:00
width: 150,
sortable: 'custom'
2021-04-13 20:33:12 +08:00
}, {
2021-03-19 18:52:19 +08:00
label: this.$t('config.terminallog.duration'),
prop: 'duration',
show: true,
width: 150
}
2021-03-19 18:52:19 +08:00
],
viewAssetState: false,
tableDataInitNum: 0,
alertLabelShow: false,
alertLabelId: '',
alertLabelObj: {},
alertLabelType: '',
alertRuleShow: false,
alertRuleId: '',
alertRuleObj: ''
2021-03-19 18:52:19 +08:00
}
},
computed: {
tagType () {
return (key) => {
if (key == 'asset' || key == 'module' || key == 'project' || key == 'dc' || key == 'endpoint') {
return 'normal'
} else {
return 'info'
}
}
},
2021-03-19 18:52:19 +08:00
tagValue () {
return (key, value) => {
if (key == 'type') {
if (value == 1) {
value = this.$t('project.project.projectName')
2021-03-19 18:52:19 +08:00
} else if (value == 2) {
value = this.$t('module.module.module')
} else if (value == 3) {
value = this.$t('asset.asset')
}
}
2021-03-19 18:52:19 +08:00
return key + '' + value
}
},
getDuration () {
return function (record) {
if (record.endAt) {
2021-03-19 18:52:19 +08:00
return calcDurationByStringTimeB(record.startAt, record.endAt)
}
2021-03-19 18:52:19 +08:00
return calcDurationByStringTimeB(record.startAt, this.nowTime)
}
}
},
mounted () {
this.getSeverityData()
},
2021-03-19 18:52:19 +08:00
methods: {
getSeverityData () {
this.$get('alert/severity', { pageNo: 1, pageSize: -1 }).then(response => {
if (response.code == 200) {
this.severityData = response.data.list
}
})
},
2021-04-13 20:33:12 +08:00
labelsSort (obj) {
const buildIn = ['asset', 'endpoint', 'module', 'cpu', 'datacenter', 'project', 'parent_asset', 'user']
2021-03-19 18:52:19 +08:00
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]
}
})
}
2021-03-19 18:52:19 +08:00
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] })
}
2021-03-19 18:52:19 +08:00
delete labels[key]
}
2021-03-19 18:52:19 +08:00
}
Object.keys(labels).sort().forEach(key => {
2021-03-19 18:52:19 +08:00
result.push({ label: key, value: labels[key] })
delete labels[key]
})
2021-03-19 18:52:19 +08:00
return result
},
chartUnitChange: function (unit) {
this.chartUnit = unit
this.$nextTick(() => {
2021-05-08 11:25:40 +08:00
this.queryChartDate()
})
},
2021-04-13 20:33:12 +08:00
formatThreshold (value, unit) {
2021-03-19 18:52:19 +08:00
const unitMethod = chartDataFormat.getUnit(unit)
if (unitMethod && value) {
return unitMethod.compute(value, null, 2)
} else {
return value
}
},
queryChartDate () {
const $temp = this
const start = this.searchTime[0] ? this.searchTime[0] : this.getTime(-1, 'h')
const end = this.searchTime[1] ? this.searchTime[1] : this.getTime(0, 'h')
this.searchTime = [start, end]
const timeDiff = (new Date(end).getTime() - new Date(start).getTime()) / 1000 / (24 * 60 * 60)
let step = '15s'
if (timeDiff < 1) {
step = '15s'
} else if (timeDiff < 7) {
step = '5m'
} else if (timeDiff < 30) {
step = '10m'
} else {
step = '30m'
}
if (this.$refs.messageChart) {
this.$refs.messageChart.startLoading()
const axiosArr = []
const paramStr = JSON.stringify(this.promQueryParamConvert(this.currentMsg))
2021-06-25 17:38:34 +08:00
axiosArr.push(axios.get('/prom/api/v1/query_range?query=' + paramStr.substring(1, paramStr.length - 1) + '&start=' + this.$stringTimeParseToUnix(start) + '&end=' + this.$stringTimeParseToUnix(end) + '&step=' + step))
2021-03-19 18:52:19 +08:00
this.legend = []
this.chartDatas = []
axios.all(axiosArr).then(res => {
try {
res.forEach((response, promIndex) => {
if (response.status == 200) {
if (response.data.status == 'success') {
const queryData = response.data.data.result[0]
if (queryData) {
const chartData = {
type: 'line',
symbol: 'none', // 去掉点
smooth: 0.2, // 曲线变平滑
name: '',
lineStyle: {
width: 1,
opacity: 0.9
},
markLine: {
silent: true,
symbol: ['circle', 'circle'],
label: {
distance: this.computeDistance(chartDataFormat.getUnit(this.currentMsg.alertRule.unit ? this.currentMsg.alertRule.unit : 2).compute(this.currentMsg.alertRule.threshold)),
2021-04-13 20:33:12 +08:00
formatter (params) {
2021-03-19 18:52:19 +08:00
return chartDataFormat.getUnit($temp.currentMsg.alertRule.unit ? $temp.currentMsg.alertRule.unit : 2).compute(params.value)
}
},
lineStyle: {
color: '#d64f40',
width: 2,
type: 'dotted'
},
data: [{
yAxis: Number(this.currentMsg.alertRule.threshold)
}]
},
markArea: {
itemStyle: {
color: '#d64f40',
opacity: 0.1
},
data: [this.returnMarkArea()]
}
}
if (this.currentMsg.alertRule.operator == '==' || this.currentMsg.alertRule.operator == '!=') {
delete chartData.markArea
}
let alias = chartData.name
chartData.name += '{'
alias += '{'
Object.keys(queryData.metric).forEach((item, index) => {
const label = item
const value = queryData.metric[label]
chartData.name += label + "='" + value + "',"
})
chartData.name = chartData.name.charAt(chartData.name.length - 1) == ',' ? chartData.name.substr(0, chartData.name.length - 1) : chartData.name
chartData.name += '}'
const legend = {
name: chartData.name,
alias: alias,
isGray: false
}
this.legend.push(legend)
chartData.data = queryData.values.map((dpsItem, dpsIndex) => {
return [dpsItem[0] * 1000, parseFloat(dpsItem[1]).toFixed(2)]
})
this.chartDatas.push(chartData)
}
} else {
this.$message.error(response.data.error)
}
}
})
this.$nextTick(() => {
this.$refs.messageChart.setRandomColors(this.chartDatas.length)
this.$refs.messageChart.setLegend(this.legend)
this.$refs.messageChart.setSeries(this.chartDatas)
this.$refs.messageChart.endLoading()
})
} catch (err) {
this.$message.error(err)
this.$refs.messageChart.endLoading()
}
2021-03-19 18:52:19 +08:00
})
}
},
2021-04-13 20:33:12 +08:00
computeDistance (str) {
2021-03-19 18:52:19 +08:00
let width = 0
const html = document.createElement('span')
html.innerText = str
html.className = 'getTextWidth'
document.querySelector('body').appendChild(html)
width = document.querySelector('.getTextWidth').offsetWidth
document.querySelector('.getTextWidth').remove()
return Number('-' + (width + 5))
},
2021-04-13 20:33:12 +08:00
returnMarkArea () {
2021-03-19 18:52:19 +08:00
if (this.currentMsg) {
if (this.currentMsg.alertRule.operator == '>' || this.currentMsg.alertRule.operator == '>=') {
return [{ yAxis: this.currentMsg.alertRule.threshold }, {}]
} else {
return [{}, { yAxis: this.currentMsg.alertRule.threshold }]
}
2021-03-19 18:52:19 +08:00
}
},
detail (obj) {
if (!obj.current) { return }
this.chartDatas = []
this.legend = []
this.graphShow = true
this.currentMsg = obj
this.chartUnit = obj.alertRule.unit ? obj.alertRule.unit : 5
this.$nextTick(() => {
this.queryChartDate()
})
},
dialogClose () {
this.graphShow = false
2021-05-08 15:04:17 +08:00
},
2021-03-19 18:52:19 +08:00
getAlertList () {
if (!this.scrollbarWrap) {
this.$nextTick(() => {
2021-03-19 18:52:19 +08:00
this.scrollbarWrap = this.$refs.alertListTable.bodyWrapper
this.toTopBtnHandler(this.scrollbarWrap)
})
}
},
promQueryParamConvert (obj) {
let r = '(' + obj.alertRule.expr + ')'
let intoLabels = false
if (Object.keys(obj.labels).length > 0) {
r += (function () {
let group = ' and ' + '(group({'
let by = ' by ('
2021-03-19 18:52:19 +08:00
for (const k in obj.labels) {
if (k != 'alertname' && k != 'severity') {
intoLabels = true
group += k
group += '='
group += ("'" + obj.labels[k] + "',")
by += k
by += ','
}
2021-03-19 18:52:19 +08:00
}
if (intoLabels) {
group = group.substring(0, group.length - 1)
by = by.substring(0, by.length - 1)
group += '})'
by += ')'
return group + by + ')'
} else {
return ''
}
}())
}
return r
},
// asset弹框控制
tabControl (data) {
if (data === 'close') {
this.viewAssetState = false
this.$refs.assetEditUnit.tabView = false
}
},
toDeleteMessage (obj) {
2021-04-13 20:33:12 +08:00
this.$emit('toDelete', obj)
2021-03-19 18:52:19 +08:00
},
selectionChange (objs) {
this.$emit('selectionChange', objs)
2021-03-19 18:52:19 +08:00
},
closeDialog () {
this.importBox.show = false
this.deleteBox.show = false
},
2021-04-13 20:33:12 +08:00
getTimeString () {
2021-03-19 18:52:19 +08:00
const split = '-'
const date = new Date()
const year = date.getFullYear()
const month = this.formatNum(date.getMonth() + 1)
const day = this.formatNum(date.getDate())
const hours = this.formatNum(date.getHours())
const minutes = this.formatNum(date.getMinutes())
const seconds = this.formatNum(date.getSeconds())
return year + split + month + split + day + ' ' + hours + split + minutes + split + seconds
},
2021-04-13 20:33:12 +08:00
formatNum (num) {
2021-03-19 18:52:19 +08:00
return num > 9 ? num : '0' + num
},
labelsClassName (row) {
if (row.column.label == this.$t('alert.list.labels')) {
return 'alert-message-list-labels'
} else if (row.column.label == this.$t('alert.list.state')) {
if (row.row.state == 1) {
return ''
2021-03-19 18:52:19 +08:00
} else if (row.row.state == 2) {
return ''
2020-09-28 16:27:03 +08:00
}
2021-03-19 18:52:19 +08:00
} else {
return ''
}
},
2021-04-13 20:33:12 +08:00
closeViews () {
2021-03-19 18:52:19 +08:00
this.$refs.alertConfigBox.show(false, false)
this.$refs.projectBox.show(false, false)
this.$refs.moduleBox.show(false, false)
this.viewAssetState = false
},
// label tooltip是否显示
labelToolTipDis (labelType) {
switch (labelType) {
case 'asset':
case 'module':
case 'endpoint':
case 'project':
case 'dc':
2021-03-19 18:52:19 +08:00
return false
default: return true
}
},
2021-04-13 20:33:12 +08:00
// alertName鼠标划入
alertMessageHover (item, loading, e) {
2021-03-19 18:52:19 +08:00
if (e) {
const dom = e.currentTarget
const position = dom.getBoundingClientRect()
this.$set(item.alertRule, 'position', position)
this.alertRuleId = item.alertRule.id
this.alertRuleObj = item
2021-03-19 18:52:19 +08:00
}
this.$set(item.alertRule, 'loading', loading)
this.alertRuleShow = loading
2021-03-19 18:52:19 +08:00
},
// label 鼠标划入
labelHover (item, type, loading, e) {
if (this.labelToolTipDis(type)) {
return
}
if (e) {
const dom = e.currentTarget
const position = dom.getBoundingClientRect()
this.$set(item[type], 'position', position)
this.alertLabelId = item[type].id
this.alertLabelObj = item[type]
this.alertLabelType = type
2021-03-19 18:52:19 +08:00
}
this.$set(item[type], 'loading', loading)
this.alertLabelShow = loading
2021-03-19 18:52:19 +08:00
},
// Severity Label
returnSeverityLabel (key) {
2021-11-04 18:21:20 +08:00
return this.$t(this.$CONSTANTS.alertMessage.severityData.find(s => { return s.value == key }).label)
},
rowDblclick (row) {
if (!this.showOption) {
return
}
this.$emit('messageDetail', row)
2021-03-19 18:52:19 +08:00
}
}
2021-03-19 18:52:19 +08:00
}
</script>
<style>
.alert-message-tooltip.el-popover{
padding: 0 !important;
}
</style>