fix: 1.错误信息提示框将时间选择器组件遮住;2.subscriber kpi代码调整;

This commit is contained in:
hanyuxia
2023-12-06 17:30:45 +08:00
parent 2f315bf52c
commit da9ae6831e
6 changed files with 327 additions and 141 deletions

View File

@@ -206,6 +206,7 @@
}
.my-date-picker {
z-index: 100004 !important;
.el-popper__arrow {
position: absolute;
top: 20px !important;

View File

@@ -14,7 +14,7 @@
<i class="cn-icon cn-icon-dropdown" :class="dropdownFlag ? 'cn-icon-up' : ''"></i>
</div>
</div>
<transition name="el-zoom-in-top" style="z-index: 4;">
<transition name="el-zoom-in-top" style="z-index: 100004;">
<div v-if="dropdownFlag" class="date-range-panel" :style="showPosition === 'left' ? leftStyle : rightStyle">
<el-row class="date-range-panel-top" style="position: relative">
<el-col :span="16" class="date-range-panel-content date-range-panel-content-left">

View File

@@ -275,6 +275,9 @@ export const api = {
domainNameResolutionAboutAppsOfDomain: apiVersion + '/entity/detail/domain/relate/apps',
domainNameResolutionAboutIpsOfDomain: apiVersion + '/entity/detail/domain/relate/ips',
domainNameResolutionAboutFQDNsOfDomain: apiVersion + '/entity/detail/domain/relate/fqdns',
// subscriber
subscriberKpi: apiVersion + '/entity/detail/traffic/overview/subscriber',
subscriberTopApp: apiVersion + '/entity/detail/subscriber/relate/apps',
// 开放端口ip、domain、app相关
openPortOfIp: apiVersion + '/entity/detail/ip/relate/ports',
openPortOfDomain: apiVersion + '/entity/detail/domain/relate/ports',
@@ -282,8 +285,8 @@ export const api = {
basicInfo: apiVersion + '/entity/detail/basic',
tags: apiVersion + '/entity/detail/kb/intelligence/tag',
informationAggregation: apiVersion + '/entity/detail/kb/intelligence/list',
deviceInformation: apiVersion + '/entity/detail/subscribe/device', // 暂时写的值
accountInformation: apiVersion + '/entity/detail/subscribe/account', // 暂时写的值
deviceInformation: apiVersion + '/entity/detail/subscriber/device', // 暂时写的值
accountInformation: apiVersion + '/entity/detail/subscriber/account', // 暂时写的值
locationTrack: apiVersion + '/entity/detail/subscribe/track',
// 实体关系
entityGraph: {

View File

@@ -22,9 +22,8 @@
<div class="kpi-type-value">
<div class="kpi-type-value-name">{{$t('subscriber.volume')}}</div>
<div class="kpi-type-data" >
<template v-if="$_.get(kpiData, 'volume')">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'volume') ? unitConvert($_.get(kpiData, 'volume')[0], unitTypes.bps).join(' ') : '-'}}</div>
<div class="data-trend">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'volume') ? unitConvert($_.get(kpiData, 'volume')[0], unitTypes.byte).join(' ') : '-'}}</div>
<div class="data-trend" v-if="$_.get(kpiData, 'volume')">
<div v-if="$_.get(kpiData, 'volume')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'volume')[2]}}</span>
</div>
@@ -35,18 +34,13 @@
<i class="cn-icon-constant cn-icon"></i>
</div>
</div>
</template>
<template v-else>
-
</template>
</div>
</div>
<div class="kpi-type-value">
<div class="kpi-type-value-name">{{$t('subscriber.throughput')}}</div>
<div class="kpi-type-data" >
<template v-if="$_.get(kpiData, 'throughput')">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'throughput') ? unitConvert($_.get(kpiData, 'throughput')[0], unitTypes.bps).join(' ') : '-'}}</div>
<div class="data-trend">
<div class="data-trend" v-if="$_.get(kpiData, 'throughput')">
<div v-if="$_.get(kpiData, 'throughput')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'throughput')[2]}}</span>
</div>
@@ -57,40 +51,47 @@
<i class="cn-icon-constant cn-icon"></i>
</div>
</div>
</template>
<template v-else>
-
</template>
</div>
</div>
<div class="kpi-type-value">
<div class="kpi-type-value-name">{{$t('subscriber.latency')}}</div>
<div class="kpi-type-value-name">{{$t('subscriber.httpLatency')}}</div>
<div class="kpi-type-data" >
<template v-if="$_.get(kpiData, 'latency')">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'latency') ? unitConvert($_.get(kpiData, 'latency')[0], unitTypes.bps).join(' ') : '-'}}</div>
<div class="data-trend">
<div v-if="$_.get(kpiData, 'latency')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'latency')[2]}}</span>
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'httpLatency') ? unitConvert($_.get(kpiData, 'httpLatency')[0], unitTypes.time).join(' ') : '-'}}</div>
<div class="data-trend" v-if="$_.get(kpiData, 'httpLatency')">
<div v-if="$_.get(kpiData, 'httpLatency')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'httpLatency')[2]}}</span>
</div>
<div v-else-if=" $_.get(kpiData, 'latency')[1] === 'down'" class="data-total-trend data-total-trend-green" >
<i class="cn-icon-decline cn-icon"></i><span>{{$_.get(kpiData, 'latency')[2]}}</span>
<div v-else-if=" $_.get(kpiData, 'httpLatency')[1] === 'down'" class="data-total-trend data-total-trend-green" >
<i class="cn-icon-decline cn-icon"></i><span>{{$_.get(kpiData, 'httpLatency')[2]}}</span>
</div>
<div v-else-if=" $_.get(kpiData, 'latency')[1] === 'noChange'" class="data-total-trend data-total-trend-black" >
<div v-else-if=" $_.get(kpiData, 'httpLatency')[1] === 'noChange'" class="data-total-trend data-total-trend-black" >
<i class="cn-icon-constant cn-icon"></i>
</div>
</div>
</div>
</div>
<div class="kpi-type-value">
<div class="kpi-type-value-name">{{$t('subscriber.sslLatency')}}</div>
<div class="kpi-type-data" >
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'sslLatency') ? unitConvert($_.get(kpiData, 'sslLatency')[0], unitTypes.time).join(' ') : '-'}}</div>
<div class="data-trend" v-if="$_.get(kpiData, 'sslLatency')">
<div v-if="$_.get(kpiData, 'sslLatency')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'sslLatency')[2]}}</span>
</div>
<div v-else-if=" $_.get(kpiData, 'sslLatency')[1] === 'down'" class="data-total-trend data-total-trend-green" >
<i class="cn-icon-decline cn-icon"></i><span>{{$_.get(kpiData, 'sslLatency')[2]}}</span>
</div>
<div v-else-if=" $_.get(kpiData, 'sslLatency')[1] === 'noChange'" class="data-total-trend data-total-trend-black" >
<i class="cn-icon-constant cn-icon"></i>
</div>
</div>
</template>
<template v-else>
-
</template>
</div>
</div>
<div class="kpi-type-value">
<div class="kpi-type-value-name">{{$t('subscriber.packetLoss')}}</div>
<div class="kpi-type-data" >
<template v-if="$_.get(kpiData, 'packetLoss')">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'packetLoss') ? unitConvert($_.get(kpiData, 'packetLoss')[0], unitTypes.bps).join(' ') : '-'}}</div>
<div class="data-trend">
<div class="kpi-type-value-number" >{{$_.get(kpiData, 'packetLoss') ? unitConvert($_.get(kpiData, 'packetLoss')[0], unitTypes.percent).join(' ') : '-'}}</div>
<div class="data-trend" v-if="$_.get(kpiData, 'packetLoss')">
<div v-if="$_.get(kpiData, 'packetLoss')[1] === 'up'" class="data-total-trend data-total-trend-red" >
<i class="cn-icon-rise1 cn-icon"></i><span>{{$_.get(kpiData, 'packetLoss')[2]}}</span>
</div>
@@ -101,10 +102,6 @@
<i class="cn-icon-constant cn-icon"></i>
</div>
</div>
</template>
<template v-else>
-
</template>
</div>
</div>
</div>
@@ -163,11 +160,12 @@ export default {
data () {
return {
kpiData: {
/*
volume: [5300000000, 'up', '6%'],
throughput: [600000, 'noChange', '6%'],
httpLatency: [21, 'down', '6%'],
sslLatency: [21, 'down', '6%'],
packetLoss: [0.0192, 'down', '2%']
packetLoss: [0.0192, 'down', '2%']*/
},
unitConvert,
unitTypes,
@@ -187,6 +185,12 @@ export default {
handleTrendData (curData, preData) {
let trend = ''
let trendPercent = ''
curData = Number(curData)
preData = Number(preData)
if(curData === 0 && preData === 0) {
trend = 'noChange'
trendPercent = ''
} else if(curData && preData) {
const totalDiff = curData - preData
const chainRatio = getChainRatio(curData, preData)
if (chainRatio !== '-') {
@@ -215,6 +219,7 @@ export default {
trendPercent = ''
}
}
}
return [curData, trend, trendPercent]
},
init () {
@@ -240,11 +245,11 @@ export default {
this.showError = false
if (!this.isNoData) {
this.kpiData = {
volume: [data ? data.total_bytes : '', '', ''],
throughput: [data ? data.avg_bits_per_sec : '', '', ''],
httpLatency: [data ? data.avg_http_response_latency_ms : '', '', ''],
sslLatency: [data ? data.avg_ssl_handshake_latency_ms : '', '', ''],
packetLoss: [data ? data.tcp_lost_bytes_ratio : '', '', '']
volume: [data ? data.total_bytes : null],
throughput: [data ? data.avg_bits_per_sec : null],
httpLatency: [data ? data.avg_http_response_latency_ms : null],
sslLatency: [data ? data.avg_ssl_handshake_latency_ms : null],
packetLoss: [data ? data.tcp_lost_bytes_ratio : null]
}
axios.get(api.entity.subscriberKpi, { params: preParams }).then(preCycleRes => {
@@ -252,25 +257,25 @@ export default {
if (preCycleRes.status === 200) {
const data = preRes.data
if (Object.keys(data).length > 0) {
const preVolume = data ? data.avg_bits_per_sec : ''
const preThroughput = data ? data.total_bytes : ''
const preHttpLatency = data ? data.avg_http_response_latency_ms : ''
const preSslLatency = data ? data.avg_ssl_handshake_latency_ms : ''
const prePacketLoss = data ? data.tcp_lost_bytes_ratio : ''
const preVolume = data ? data.avg_bits_per_sec : null
const preThroughput = data ? data.total_bytes : null
const preHttpLatency = data ? data.avg_http_response_latency_ms : null
const preSslLatency = data ? data.avg_ssl_handshake_latency_ms : null
const prePacketLoss = data ? data.tcp_lost_bytes_ratio : null
if (this.kpiData.volume[0] !== '' && preVolume !== '') {
if (this.kpiData.volume[0] !==null && preVolume !==null) {
this.kpiData.volume = this.handleTrendData(this.kpiData.volume[0], preVolume)
}
if (this.kpiData.throughput[0] !== '' && preThroughput !== '') {
if (this.kpiData.throughput[0] !==null && preThroughput !==null) {
this.kpiData.throughput = this.handleTrendData(this.kpiData.throughput[0], preThroughput)
}
if (this.kpiData.httpLatency[0] !== '' && preHttpLatency !== '') {
if (this.kpiData.httpLatency[0] !==null && preHttpLatency !==null) {
this.kpiData.httpLatency = this.handleTrendData(this.kpiData.httpLatency[0], preHttpLatency)
}
if (this.kpiData.sslLatency[0] !== '' && preSslLatency !== '') {
if (this.kpiData.sslLatency[0] !==null && preSslLatency !==null) {
this.kpiData.sslLatency = this.handleTrendData(this.kpiData.sslLatency[0], preSslLatency)
}
if (this.kpiData.packetLoss[0] !== '' && prePacketLoss !== '') {
if (this.kpiData.packetLoss[0] !==null && prePacketLoss !==null) {
this.kpiData.packetLoss = this.handleTrendData(this.kpiData.packetLoss[0], prePacketLoss)
}
}

View File

@@ -14,26 +14,26 @@
<div class="subscriber-top-app-body">
<chart-no-data v-if="isNoData" test-id="noData"></chart-no-data>
<chart-error v-if="showError" :content="errorMsg" />
<chart-error v-if="showError" :content="errorMsg" style="top:34px;"/>
<div class="top-app-left" v-show="!isNoData && !showError">
<div class="app-data" v-for="(app, index) in topAppData">
<div class="app-data" v-for="(appData, index) in topAppData">
<div class="app-index">{{++index}}</div>
<div class="app-name">{{app.name}}</div>
<div class="app-name">{{appData.app}}</div>
<div class="app-trend">
<i class="cn-icon cn-icon-egress"></i>
<div class="app-up">{{app.up}}</div>
<div class="app-up">{{appData.up ? unitConvert(appData.up, unitTypes.byte,null,null,1).join('') : '-'}}</div>
</div>
<el-divider direction="vertical" class="top-app-divider"/>
<div class="app-trend">
<i class="cn-icon cn-icon-ingress"></i>
<div class="app-down">{{app.down}}</div>
<div class="app-down">{{appData.down ? unitConvert(appData.down, unitTypes.byte,null,null,1).join('') : '-'}}</div>
</div>
</div>
</div>
<div class="top-app-right" >
<div class="chart-content" id="subscriberTopAppChart"></div>
<div class="chart-content" :style="isSetHeight ? newHeight : ''" id="subscriberTopAppChart"></div>
</div>
</div>
@@ -48,7 +48,7 @@ import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { overwriteUrl, urlParamsHandler, reverseSortBy } from '@/utils/tools'
import axios from 'axios'
import { useRoute } from 'vue-router'
import { getNowTime, getSecond } from '@/utils/date-util'
@@ -93,52 +93,52 @@ export default {
return {
topAppData: [
{
name: 'Wetchat',
app: 'Wetchat',
up: '1.2GB',
down: '28MB'
},
{
name: 'QQ',
app: 'QQ',
up: '1.2GB',
down: '28MB'
},
{
name: 'Douyin',
app: 'Douyin',
up: '1.2GB',
down: '28MB'
},
{
name: 'Weibo',
app: 'Weibo',
up: '1.2GB',
down: '28MB'
},
{
name: 'Tecent',
app: 'Tecent',
up: '1.2GB',
down: '28MB'
},
{
name: 'Kuaishou',
app: 'Kuaishou',
up: '1.2GB',
down: '28MB'
},
{
name: 'Taobao',
app: 'Taobao',
up: '1.2GB',
down: '28MB'
},
{
name: 'Jd',
app: 'Jd',
up: '1.2GB',
down: '28MB'
},
{
name: 'Aiqiyi',
app: 'Aiqiyi',
up: '1.2GB',
down: '28MB'
},
{
name: 'Baidu',
app: 'Baidu',
up: '1.2GB',
down: '28MB'
}
@@ -147,7 +147,9 @@ export default {
unitTypes,
isNoData: false,
showError: false,
errorMsg: ''
errorMsg: '',
isSetHeight: false,
newHeight: ''
}
},
watch: {
@@ -158,26 +160,33 @@ export default {
}
},
methods: {
init (val, show, active, n) {
init () {
const params = {
resource: this.entity.entityName,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
if (this.queryCondition) {
// params.q = this.queryCondition
}
this.toggleLoading(true)
axios.get(`${api.entity.throughput}/${this.entity.entityType}`, { params: params }).then(response => {
axios.get(api.entity.subscriberTopApp, { params: params }).then(response => {
const res = response.data
if (response.status === 200) {
this.isNoData = res.data.result.length === 0
this.showError = false
if (!this.isNoData) {
this.topAppData = res.data.result
this.initEchart()
const appDatas = res.data.result.map(item => {
const upData = item.outbound_byte ? item.outbound_byte : 0
const downData = item.inbound_byte ? item.inbound_byte : 0
return {
app: item.app,
up: upData,
down: downData,
appTotal: upData + downData
}
})
this.topAppData = appDatas.sort(reverseSortBy('appTotal'))
this.getTotalData()
}
} else {
this.httpError(res)
@@ -187,13 +196,177 @@ export default {
this.httpError(e)
}).finally(() => {
this.toggleLoading(false)
// 无数据时的测试代码
//this.isNoData = false
//this.initEchart()
// 无数据时的测试代码----------
const response = {
status: 200,
data: {
msg: 'success',
code: 200,
data: {
result: [
{
app: 'Wetchat',
inbound_byte: 9024,
inbound_pkt: 1024
}, /*
{
"app": "QQ",
"inbound_byte": 224,
"inbound_pkt": 1024,
"outbound_byte": 24956711,
"outbound_pkt": 2048
},{
"app": "Douyin",
"inbound_byte": 21356711,
"inbound_pkt": 1024,
"outbound_byte": 2048,
"outbound_pkt": 2048
}, */{
app: 'Weibo',
inbound_byte: 24356711,
inbound_pkt: 1024,
outbound_byte: 2048,
outbound_pkt: 2048
}, {
app: 'Tecent',
inbound_byte: 124356711,
inbound_pkt: 1024,
outbound_byte: 2048,
outbound_pkt: 2048
}, {
app: 'Kuaishou',
inbound_byte: 324356711,
inbound_pkt: 1024,
outbound_byte: 2048,
outbound_pkt: 2048
}, {
app: 'Taobao',
inbound_byte: 424356711,
inbound_pkt: 1024,
outbound_byte: 2048,
outbound_pkt: 2048
}/* {
"app": "Jd",
"inbound_byte": 924356711,
"inbound_pkt": 1024,
"outbound_byte": 2048,
"outbound_pkt": 2048
},{
"app": "Aiqiyi",
"inbound_byte": 624356711,
"inbound_pkt": 1024,
"outbound_byte": 2048,
"outbound_pkt": 2048
},{
"app": "Baidu",
"inbound_byte": 1624356711,
"inbound_pkt": 1024,
"outbound_byte": 2048,
"outbound_pkt": 2048
} */
]
}
}
}
const res = response.data
if (response.status === 200) {
this.isNoData = res.data.result.length === 0
this.showError = false
if (!this.isNoData) {
const appDatas = res.data.result.map(item => {
const upData = item.outbound_byte ? item.outbound_byte : 0
const downData = item.inbound_byte ? item.inbound_byte : 0
return {
app: item.app,
up: upData,
down: downData,
appTotal: upData + downData
}
})
this.topAppData = appDatas.sort(reverseSortBy('appTotal'))
this.getTotalData()
}
}
// 无数据时的测试代码----------
})
},
getTotalData () {
const params = {
resource: this.entity.entityName,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
axios.get(api.entity.subscriberKpi, { params: params }).then(response => {
const res = response.data
if (response.status === 200) {
const data = res.data
this.isNoData = Object.keys(data).length === 0
this.showError = false
if (!this.isNoData) {
const totalData = data.total_bytes ? data.total_bytes : 0
if (totalData !== 0) {
const echartDataList = []
this.topAppData.forEach(item => {
echartDataList.push({
count: (item.appTotal / totalData).toFixed(3),
app: item.app
})
})
this.initEchart(echartDataList)
}
}
} else {
this.httpError(res)
}
}).catch(e => {
console.error(e)
this.httpError(e)
}).finally(() => { // 无数据时的测试代码----------
const response = {
status: 200,
data: {
code: 200,
msg: 'ok',
data: {
total_bytes: 9024356711,
total_packets: 999,
avg_bits_per_sec: 888,
avg_pkts_per_sec: 888,
avg_http_response_latency_ms: 30,
avg_ssl_handshake_latency_ms: 10,
tcp_lost_bytes_ratio: 0.10
}
}
}
const res = response.data
if (response.status === 200) {
const data = res.data
this.isNoData = Object.keys(data).length === 0
this.showError = false
if (!this.isNoData) {
const totalData = data.total_bytes ? data.total_bytes : 0
if (totalData !== 0) {
const echartDataList = []
this.topAppData.forEach(item => {
echartDataList.push({
count: (item.appTotal / totalData).toFixed(3),
app: item.app
})
})
this.initEchart(echartDataList)
}
}
}
// 无数据时的测试代码----------
})
},
initEchart (data) {
data = [
/* data = [
{
count: 0.307,
app: 1
@@ -234,8 +407,12 @@ export default {
count: 0.006,
app: 10
}
]
] */
if (data && data.length > 0) {
if (data.length < 10) { // 重新设置图标高度
this.isSetHeight = true
this.newHeight = 'height:' + unitConvert(data.length / 10, unitTypes.percent, null, null, 0).join('') + ';'
}
const chartDom = document.getElementById('subscriberTopAppChart')
this.myChart = echarts.getInstanceByDom(chartDom)
if (this.myChart) {

View File

@@ -88,7 +88,7 @@ export default {
const tabObj = entityDetailTabConfig.find(tab => tab.name === entityType)
const tabs = reactive(tabObj ? tabObj.config : [])
const activeTab = ref(tabs[0].name)
const activeTab = ref(tabs[0] ? tabs[0].name : {})
const { query } = useRoute()
const item = tabs.find(item => item.name === query.currentTab)
@@ -180,7 +180,7 @@ export default {
this.promiseData(appsOfDomain, ipsOfDomain, fqdnsOfDomain)
}
if (this.entity.entityType === entityType.subscribe) {
if (this.entity.entityType === entityType.subscriber) {
axios.get(api.entity.deviceInformation, { params: this.getParamsByTabType(entityDetailTabsName.deviceInformation) }).then(response => {
const res = response.data
if (response.status === 200) {