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
cyber-narrator-cn-ui/src/views/charts2/Panel.vue

554 lines
20 KiB
Vue
Raw Normal View History

2022-07-06 21:08:12 +08:00
<template>
<div class="panel-box2" :class="{'panel-box2--entity-detail': entity && entity.entityType}">
<div class="panel__header" v-if="!entity">
<div class="panel__title">{{panelName?panelName:(panel.i18n ? $t(panel.i18n) : panel.name)}}
<div v-if="showScore" class="score">
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
Score:{{score}}
</div>
<div v-if="showEntityDetail" class="panel-show-detail">
<el-tooltip
effect="light"
trigger="hover"
:content="$t('entity.jumpToEntityDetails')"
placement="right"
popper-class="panel-tooltip"
>
<i class="cn-icon cn-icon-jump-to" @click="jumpEntityDetail"></i>
</el-tooltip>
</div>
</div>
<div class="panel__tools">
<el-select
size="mini"
v-model="metric"
placeholder=" "
popper-class="common-select"
v-if="showMetric"
:popper-append-to-body="false"
@change="metricChange"
>
<template #prefix>
<span class="select-prefix">Metric:</span>
</template>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<div class="panel__time">
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
<time-refresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"
/>
</div>
2022-07-06 21:08:12 +08:00
</div>
</div>
<chart-list
ref="chartList"
:time-filter="timeFilter"
:metric="metric"
2022-07-06 21:08:12 +08:00
:chart-list="chartList"
2022-07-18 15:04:32 +08:00
:panel-type="panelType"
2022-07-06 21:08:12 +08:00
:panel-lock="panelLock"
2022-07-22 18:09:18 +08:00
:extra-params="extraParams"
2022-07-06 21:08:12 +08:00
:entity="entity"
></chart-list>
</div>
</template>
<script>
import { useRoute } from 'vue-router'
2022-07-06 21:08:12 +08:00
import { ref } from 'vue'
import {
panelTypeAndRouteMapping,
curTabState,
drillDownPanelTypeMapping,
metricOptions,
fromRoute
} from '@/utils/constants'
import { getPanelList, getChartList, api } from '@/utils/api'
import { getNowTime, getSecond } from '@/utils/date-util'
2022-07-06 21:08:12 +08:00
import { getTypeCategory } from '@/views/charts/charts/tools'
import { urlParamsHandler, overwriteUrl, getDnsMapData, computeScore } from '@/utils/tools'
2022-07-06 21:08:12 +08:00
import ChartList from '@/views/charts2/ChartList'
2022-10-19 15:27:26 +08:00
import { useStore } from 'vuex'
import axios from 'axios'
import _ from 'lodash'
2022-07-06 21:08:12 +08:00
export default {
name: 'Panel',
props: {
entity: Object,
typeName: String
},
components: {
ChartList
},
data () {
return {
2022-11-01 17:11:55 +08:00
panelTypeAndRouteMapping,
metricOptions,
2022-07-06 21:08:12 +08:00
chartList: [], // 普通panel的chart
2022-07-22 18:09:18 +08:00
panelLock: true,
extraParams: {},
panelName: '',
dnsRcodeMapData: [],
dnsQtypeMapData: [],
score: null,
2023-10-22 20:21:32 +08:00
curTabState: curTabState,
performanceData: {},
scoreDataState: false // 评分数据是否加载完成
2022-07-06 21:08:12 +08:00
}
},
2022-08-24 13:29:21 +08:00
computed: {
// npmThirdLevelMenuScore () {
// return this.$store.getters.getNpmThirdLevelMenuScore
// }
// 显示顶部的Metric单位选项标识
showMetric () {
return this.panelType === panelTypeAndRouteMapping.networkOverview || this.panelType === panelTypeAndRouteMapping.networkOverviewDrillDown
2023-10-22 20:21:32 +08:00
},
scoreBaseState () {
return this.$store.getters.scoreBaseReady
}
2022-08-24 13:29:21 +08:00
},
watch: {
timeFilter: {
2022-11-29 17:21:01 +08:00
handler () {
2023-10-22 20:21:32 +08:00
if (this.$route.path === '/panel/networkAppPerformance') {
this.$store.commit('resetScoreBase')
this.queryScoreBase()
if (this.lineQueryCondition || this.networkOverviewBeforeTab) {
this.scoreCalculation()
}
}
}
2023-10-22 20:21:32 +08:00
},
scoreBaseState (n) {
if (n && this.scoreDataState) {
this.handleScoreData()
}
},
scoreDataState (n) {
if (n && this.scoreBaseState) {
this.handleScoreData()
}
}
2022-08-24 13:29:21 +08:00
},
2022-07-06 21:08:12 +08:00
async mounted () {
// this.panelName = this.$store.getters.getPanelName
const pName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
const curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
2022-11-29 17:21:01 +08:00
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.$store.commit('setDnsQtypeMapData', this.dnsQtypeMapData)
this.$store.commit('setDnsRcodeMapData', this.dnsRcodeMapData)
}
if (curTabProp === 'qtype') {
this.panelName = this.dnsQtypeMapData.get(pName)
} else if (curTabProp === 'rcode') {
this.panelName = this.dnsRcodeMapData.get(pName)
} else {
this.panelName = pName
}
2022-09-23 19:01:30 +08:00
// const curOperationType = this.$store.getters.getTabOperationType
/* const curOperationType = this.getUrlParam(this.curTabState.tabOperationType, '', true)
2022-08-24 13:29:21 +08:00
if (this.panelName && this.$route.path === '/panel/networkAppPerformance' && curOperationType !== operationType.thirdMenu) {
// const columnValue = this.$store.getters.getBreadcrumbColumnValue
const columnValue = this.getUrlParam(this.curTabState.fourthMenu, '')
const queryParams = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
// type: this.$store.getters.getDimensionType,
type: this.$route.query.dimensionType ? this.$route.query.dimensionType : '',
params: columnValue || ''
}
const requestGroup = []
scoreUrl.forEach(url => {
if (url) {
const request = get(url, queryParams, true)
requestGroup.push(request)
}
})
const scoreGroup = []
let score = 0
Promise.all(requestGroup).then(res => {
res.forEach(t => {
if (t.code === 200) {
const data = t.data.result ? t.data.result[0] : null
if (data) {
customTableTitlesForAppPerformance.forEach(item => {
if (data[bytesColumnNameGroupForNpm[item.prop]]) {
score = computeScore(data, item.scoreType)
scoreGroup.push(score)
} else {
scoreGroup.push(0)
}
})
}
}
})
}).finally(() => {
scoreGroup.forEach(i => {
score = Number(score) + Number(i)
})
score = Math.ceil(score * 6)
if (score > 6) {
score = 6
}
this.score = score || 0
})
2022-08-24 13:29:21 +08:00
} else if (this.$route.path === '/panel/networkAppPerformance' && curOperationType === operationType.thirdMenu) {
this.score = this.$store.getters.getNpmThirdLevelMenuScore
} */
2022-07-06 21:08:12 +08:00
await this.init()
2022-07-26 13:54:09 +08:00
const vm = this
this.emitter.on('reloadChartList', async function () {
2022-08-04 12:03:15 +08:00
vm.chartList = []
2022-07-26 13:54:09 +08:00
vm.chartList = (await getChartList({ panelId: vm.panel.id, pageSize: -1 })).map(chart => {
chart.i = chart.id
// 递归初始化各属性
vm.initChartAttr(chart)
return chart
})
})
2023-10-22 20:21:32 +08:00
if (this.$route.path === '/panel/networkAppPerformance') {
if (this.lineQueryCondition || this.networkOverviewBeforeTab) {
this.scoreCalculation()
}
}
if (this.$route.path === '/panel/networkAppPerformance' || this.$route.path === '/panel/linkMonitor') {
this.$store.commit('resetScoreBase')
this.queryScoreBase()
}
2022-07-06 21:08:12 +08:00
},
2022-11-29 17:21:01 +08:00
setup (props) {
2023-05-29 10:20:39 +08:00
// router引入store会报错故在panel里调用
2022-10-19 15:27:26 +08:00
const store = useStore()
const cancelList = store.state.panel.httpCancel
// 进入页面时,发现有未结束的请求,终止请求
if (cancelList.length > 0) {
cancelList.forEach((cancel, index) => {
cancel()
delete cancelList[index]
})
}
2022-07-06 21:08:12 +08:00
const panel = ref({})
let panelType = 1 // 取得panel的type
2022-11-07 15:28:25 +08:00
let { params, query, path } = useRoute()
// 获取路由跳转过的历史状态,赋值给当前界面,起到保留状态的作用,如浏览器的回退前进等
const routerObj = store.getters.getRouterHistoryList.find(item => item.t === query.t)
2022-11-07 15:28:25 +08:00
if (routerObj) {
params = routerObj.params
query = routerObj.query
path = routerObj.path
// 如果当前界面之前载入过,获取状态后更新地址栏,以便后续的赋值操作
const newUrl = urlParamsHandler(window.location.href, useRoute().query, query)
overwriteUrl(newUrl)
}
2022-11-07 15:28:25 +08:00
const thirdPanel = query.thirdPanel
const fourthPanel = query.fourthPanel
const entityType = ref('')
const entityValue = ref('')
const showEntityDetail = ref(false)
if (fourthPanel) {
// networkOverviewBeforeTab是dashboard点击下钻标识dimensionType是详情页到下钻页标识
const tab = query.networkOverviewBeforeTab || query.dimensionType
const value = query.fourthMenu
2023-08-18 09:32:58 +08:00
const ipList = ['ip', 'clientIp', 'serverIp', 'a', 'aaaa']
const appList = ['appLabel']
2023-08-18 09:32:58 +08:00
const domainList = ['sslSni', 'domain']
if (ipList.indexOf(tab) > -1) {
entityType.value = 'ip'
showEntityDetail.value = true
} else if (appList.indexOf(tab) > -1) {
entityType.value = 'app'
showEntityDetail.value = true
} else if (domainList.indexOf(tab) > -1) {
entityType.value = 'domain'
showEntityDetail.value = true
}
entityValue.value = value
panelType = Number(fourthPanel)
} else if (thirdPanel) {
panelType = Number(thirdPanel)
} else {
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
}
2022-07-06 21:08:12 +08:00
// 获取url携带的range、startTime、endTime
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
2022-11-07 15:28:25 +08:00
2023-03-13 16:48:37 +08:00
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
2023-03-13 16:48:37 +08:00
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = getSecond(startTime)
timeFilter.value.endTime = getSecond(endTime)
// 如果没有时间参数就将参数写入url
const newUrl = urlParamsHandler(window.location.href, useRoute().query, { startTime: timeFilter.value.startTime, endTime: timeFilter.value.endTime, range: dateRangeValue })
overwriteUrl(newUrl)
} else {
timeFilter.value.startTime = parseInt(startTimeParam)
timeFilter.value.endTime = parseInt(endTimeParam)
}
2022-07-06 21:08:12 +08:00
// npm是否展示分数
const showScorePanel = [drillDownPanelTypeMapping.npmOverviewIp, drillDownPanelTypeMapping.npmOverviewDomain, drillDownPanelTypeMapping.npmOverviewApp, drillDownPanelTypeMapping.npmOverviewCommon, drillDownPanelTypeMapping.npmThirdMenu]
const showScore = showScorePanel.indexOf(panelType) > -1
const metric = ref(query.metric || 'Bits/s')
2022-11-07 15:28:25 +08:00
const lineQueryCondition = ref(query.lineQueryCondition || '')
const dimensionType = ref(query.dimensionType || '')
// 三级菜单判断
const tabOperationType = ref(query.tabOperationType)
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab || '')
2022-07-06 21:08:12 +08:00
return {
panelType,
panel,
timeFilter,
showScore,
2022-11-07 15:28:25 +08:00
metric,
path,
lineQueryCondition,
dimensionType,
tabOperationType,
networkOverviewBeforeTab,
showEntityDetail,
entityType,
entityValue
2022-07-06 21:08:12 +08:00
}
},
methods: {
async init () {
const panels = await getPanelList({ type: this.panelType })
if (panels && panels.length > 0) {
this.panel = panels[0]
}
if (this.panel.id) {
if (this.panel.params) {
this.panel.params = JSON.parse(this.panel.params)
} else {
this.panel.params = {}
}
this.chartList = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
chart.i = chart.id
// 递归初始化各属性
this.initChartAttr(chart)
return chart
})
}
},
initChartAttr (chart) {
chart.i = chart.id
chart.category = getTypeCategory(chart.type)
// 初始化params
chart.params = chart.params ? JSON.parse(chart.params) : {}
chart.firstShow = false
if (!this.$_.isEmpty(chart.children)) {
chart.children.forEach(c => {
this.initChartAttr(c)
})
}
},
2022-08-23 21:42:42 +08:00
reload (startTime, endTime, dateRangeValue) {
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime), dateRangeValue: dateRangeValue }
const { query } = this.$route
this.$store.commit('setTimeRangeArray', [this.timeFilter.startTime, this.timeFilter.endTime])
this.$store.commit('setTimeRangeFlag', dateRangeValue.value)
const newUrl = urlParamsHandler(window.location.href, query, {
startTime: this.timeFilter.startTime,
endTime: this.timeFilter.endTime,
range: dateRangeValue.value
})
overwriteUrl(newUrl)
2022-07-06 21:08:12 +08:00
},
2022-08-23 21:42:42 +08:00
timeRefreshChange () {
// 不是自选时间
if (this.$refs.dateTimeRange) {
if (!this.$refs.dateTimeRange.isCustom) {
const value = this.timeFilter.dateRangeValue
this.$refs.dateTimeRange.quickChange(value)
} else {
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))
}
2022-08-23 21:42:42 +08:00
} else {
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))
}
},
2022-09-23 19:01:30 +08:00
getUrlParam (param, defaultValue, isNumber) {
if (isNumber) {
return this.$route.query[param] ? Number(this.$route.query[param]) : defaultValue
2022-09-23 19:01:30 +08:00
} else {
return this.$route.query[param] ? this.$route.query[param] : defaultValue
}
},
metricChange (value) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
metric: value
})
overwriteUrl(newUrl)
},
2023-10-22 20:21:32 +08:00
// 动态查询评分基准
queryScoreBase () {
const params = {
startTime: this.timeFilter.startTime,
endTime: this.timeFilter.endTime
}
const tcp = axios.get(api.npm.overview.tcpSessionDelay, { params: params })
const http = axios.get(api.npm.overview.httpResponseDelay, { params: params })
const ssl = axios.get(api.npm.overview.sslConDelay, { params: params })
const tcpPercent = axios.get(api.npm.overview.tcpLostlenPercent, { params: params })
const packetPercent = axios.get(api.npm.overview.packetRetransPercent, { params: params })
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
const scoreBase = {}
res.forEach((t, i) => {
if (t.status === 200) {
if (i === 0) {
scoreBase.establishLatencyMsP10 = _.get(t.data, 'data.result.establishLatencyMsP10', null)
scoreBase.establishLatencyMsP90 = _.get(t.data, 'data.result.establishLatencyMsP90', null)
} else if (i === 1) {
scoreBase.httpResponseLatencyP10 = _.get(t.data, 'data.result.httpResponseLatencyP10', null)
scoreBase.httpResponseLatencyP90 = _.get(t.data, 'data.result.httpResponseLatencyP90', null)
} else if (i === 2) {
scoreBase.sslConLatencyP10 = _.get(t.data, 'data.result.sslConLatencyP10', null)
scoreBase.sslConLatencyP90 = _.get(t.data, 'data.result.sslConLatencyP90', null)
} else if (i === 3) {
scoreBase.tcpLostlenPercentP10 = _.get(t.data, 'data.result.tcpLostlenPercentP10', null)
scoreBase.tcpLostlenPercentP90 = _.get(t.data, 'data.result.tcpLostlenPercentP90', null)
} else if (i === 4) {
scoreBase.pktRetransPercentP10 = _.get(t.data, 'data.result.pktRetransPercentP10', null)
scoreBase.pktRetransPercentP90 = _.get(t.data, 'data.result.pktRetransPercentP90', null)
}
}
})
this.$store.commit('setScoreBase', scoreBase)
}).catch((e) => {
}).finally(() => {
})
},
scoreCalculation () {
let condition = ''
let url = ''
if (this.lineQueryCondition.indexOf(' OR ') > -1) {
condition = this.lineQueryCondition.split(/["|'](.*?)["|']/)
} else if (this.lineQueryCondition.indexOf('+OR+') > -1) {
condition = this.lineQueryCondition.replace(/\+/g, ' ').split(/["|'](.*?)["|']/)
} else {
condition = this.lineQueryCondition
}
2022-11-29 17:21:01 +08:00
const type = this.dimensionType || this.networkOverviewBeforeTab
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
cycle: 0
}
if (condition && (typeof condition !== 'object') && type) {
if (type === 'clientIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='client'`
} else if (type === 'serverIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='server'`
} else if (type === 'clientCity') {
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'serverCity') {
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
} else {
params.q = condition
}
params.type = type
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else if (condition.length > 1 && type && type !== 'ip') {
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else {
params.q = `${condition[0]}'${condition[1]}'`
params.type = type
}
}
if (parseFloat(this.tabOperationType) === 3) {
url = api.npm.overview.allNetworkAnalysis
} else {
url = api.npm.overview.networkAnalysis
}
if ((type && condition) || type) {
2023-10-22 20:21:32 +08:00
this.scoreDataState = false
this.performanceData = {}
params.type = params.type || type
axios.get(url, { params }).then(res => {
if (res.status === 200) {
2023-10-22 20:21:32 +08:00
this.performanceData = {
establishLatencyMs: _.get(res, 'data.data.result.establishLatencyMsAvg', null),
httpResponseLatency: _.get(res, 'data.data.result.httpResponseLatencyAvg', null),
sslConLatency: _.get(res, 'data.data.result.sslConLatencyAvg', null),
tcpLostlenPercent: _.get(res, 'data.data.result.tcpLostlenPercentAvg', null),
pktRetransPercent: _.get(res, 'data.data.result.pktRetransPercentAvg', null)
}
}
2023-10-22 20:21:32 +08:00
}).finally(() => {
this.scoreDataState = true
})
}
},
jumpEntityDetail () {
const { href } = this.$router.resolve({
path: '/entityDetail',
query: {
entityType: this.entityType,
entityName: this.entityValue
}
})
window.open(href, '_blank')
2023-10-22 20:21:32 +08:00
},
handleScoreData () {
this.score = computeScore(this.performanceData, this.$store.getters.getScoreBase)
2022-09-23 19:01:30 +08:00
}
2022-11-07 15:28:25 +08:00
},
/**
* 页面销毁前更新历史中已保存的状态
* 之所以会在下钻时销毁前保存状态是因为panel第一次下钻时beforeUnmount获取不到下钻前参数
*/
beforeUnmount () {
const query = this.$_.cloneDeep(this.$route.query)
const routerObj = this.$store.getters.getRouterHistoryList.find(item => item.t === query.t)
// const routerObj = window.localRouterHistoryList.find(item => item.t === query.t)
2022-11-07 15:28:25 +08:00
if (routerObj !== undefined) {
if (Object.getOwnPropertyNames(query).length >= Object.getOwnPropertyNames(routerObj.query).length) {
routerObj.query = query
}
}
2022-11-29 17:21:01 +08:00
this.emitter.off('reloadChartList')
this.$store = null
this.emitter = null
2022-07-06 21:08:12 +08:00
}
}
</script>