CN-1481 Subscribe详情页KPI组件开发;CN-1482 Subscribe详情页top app组件开发
This commit is contained in:
@@ -9,6 +9,8 @@ const DEFAULT_TIME_FILTER_RANGE = {
|
||||
entity: {
|
||||
list: 60,
|
||||
trafficLine: 60,
|
||||
subscriberKpi: 60,
|
||||
subscriberTopApp: 60,
|
||||
informationAggregation: 0,
|
||||
relatedEntity: 60 * 24 * 7,
|
||||
openPort: 60 * 24 * 7,
|
||||
|
||||
@@ -83,6 +83,8 @@
|
||||
|
||||
@import 'views/setting/knowledgeBase';
|
||||
@import 'views/charts2/entityDetailLine';
|
||||
@import 'views/charts2/EntityDetailSubscriberKpi.scss';
|
||||
@import 'views/charts2/EntityDetailSubscriberTopApp.scss';
|
||||
@import 'views/charts2/entityDetailTabs';
|
||||
@import 'views/charts2/digitalCertificate';
|
||||
@import 'views/charts2/entityDetailBasicInfo';
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
.subscriber-kpi {
|
||||
height: 100%;
|
||||
|
||||
.subscriber-kpi-header {
|
||||
height:34px;
|
||||
padding-bottom:10px;
|
||||
font-family: NotoSansHans-Medium;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 500;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.subscriber-kpi-title {
|
||||
height:24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.subscriber-kpi-body {
|
||||
border: 1px solid #E2E5EC;
|
||||
border-radius: 4px;
|
||||
height:calc(100% - 34px);
|
||||
.subscriber-kpi-content {
|
||||
height: calc(100% - 36px);
|
||||
padding: 20px 0 20px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.panel-chart__no-data {
|
||||
height: calc(100% - 46px);
|
||||
}
|
||||
.kpi-type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content:space-between;
|
||||
height: calc(100% - 65px);
|
||||
.kpi-type-value {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom:20px;
|
||||
.kpi-type-value-name {
|
||||
line-height: 12px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
color: #575757;
|
||||
font-weight: 400;
|
||||
}
|
||||
.kpi-type-data {
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
.kpi-type-value-number {
|
||||
font-family: Helvetica-Bold;
|
||||
font-size: 20px;
|
||||
color: #353636;
|
||||
font-weight: 700;
|
||||
}
|
||||
.data-trend {
|
||||
display: flex;
|
||||
width: 50%;
|
||||
|
||||
.data-total-trend {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
margin-left: 6px;
|
||||
font-size: 12px;
|
||||
justify-content: center;
|
||||
margin-top: 2px;
|
||||
border-radius: 10px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
height: 20px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.data-total-trend-black {
|
||||
background-color: rgba(113,113,113,0.12);
|
||||
color: #717171;
|
||||
width: 36px;
|
||||
}
|
||||
.data-total-trend-green {
|
||||
background-color: rgba(126,159,84,0.12);
|
||||
color: #7E9F54;
|
||||
}
|
||||
.data-total-trend-red {
|
||||
background-color: rgba(226,97,84,0.12);
|
||||
color: #E26154;
|
||||
.cn-icon-rise1{
|
||||
color: #E44D3E;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
.subscriber-top-app {
|
||||
height: 100%;
|
||||
|
||||
.subscriber-top-app-header {
|
||||
height:34px;
|
||||
padding-bottom:10px;
|
||||
font-family: NotoSansHans-Medium;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 500;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.subscriber-top-app-title {
|
||||
height:24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.subscriber-top-app-body {
|
||||
border: 1px solid #E2E5EC;
|
||||
border-radius: 4px;
|
||||
height:calc(100% - 34px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 20px 20px;
|
||||
|
||||
.panel-chart__no-data {
|
||||
height: calc(100% - 46px);
|
||||
}
|
||||
.top-app-left {
|
||||
height:100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right:15px;
|
||||
.app-data {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
height:calc(100%/10);
|
||||
//padding:5.6px 0 5.6px;
|
||||
.app-index {
|
||||
text-align: right;
|
||||
width:20px;
|
||||
margin-right:20px;
|
||||
}
|
||||
.app-name {
|
||||
width:50px;
|
||||
margin-right:30px;
|
||||
}
|
||||
.top-app-divider {
|
||||
height:10px;
|
||||
background: #717171;
|
||||
margin-left:10px;
|
||||
margin-right:8px;
|
||||
}
|
||||
.app-trend {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-right:3px;
|
||||
font-size:12px;
|
||||
color: #717171;
|
||||
}
|
||||
}
|
||||
.app-up {
|
||||
font-size: 12px;
|
||||
color: #717171;
|
||||
letter-spacing: -0.2px;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
}
|
||||
.app-down {
|
||||
font-size: 12px;
|
||||
color: #717171;
|
||||
letter-spacing: -0.2px;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
.top-app-right {
|
||||
height: 100%;
|
||||
width:calc(100% - 248px);
|
||||
position: relative;
|
||||
.chart-content {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1887,6 +1887,8 @@ export const chartColor5 = ['#E26154', '#E7B34E', '#88AF65']
|
||||
|
||||
export const chartColor6 = ['#E99F67', '#D9C74B']
|
||||
export const chartColorForBehaviorPattern = ['#7acac7', '#b4d38e', '#fee9b9', '#fec396', '#fb9b79', '#e3799c', '#edd5f5', '#868cac', '#a4adde', '#64b4e6']
|
||||
export const chartColorForSubscriberTopApp = ['#A7C186', '#AFCC8A', '#BEDCAC', '#80BEA5', '#7BBBBC', '#8CB9C8', '#E6BF88', '#E6D99B', '#E0D1B0', '#ECAE95']
|
||||
|
||||
export const iso36112 = {
|
||||
[storageKey.iso36112Capital]: 'data/countriesWithCapital',
|
||||
[storageKey.iso36112WorldLow]: 'worldChinaLow',
|
||||
|
||||
@@ -166,6 +166,18 @@
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-basic-info>
|
||||
<entity-detail-subscriber-kpi
|
||||
v-else-if="chart.type === typeMapping.entityDetail.subscriberKpi"
|
||||
:chart="chart"
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-subscriber-kpi>
|
||||
<entity-detail-subscriber-top-app
|
||||
v-else-if="chart.type === typeMapping.entityDetail.subscriberTopApp"
|
||||
:chart="chart"
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-subscriber-top-app>
|
||||
<entity-detail-line
|
||||
v-else-if="chart.type === typeMapping.entityDetail.line"
|
||||
:chart="chart"
|
||||
@@ -210,6 +222,8 @@ import DnsRecentEvents from '@/views/charts2/charts/dnsInsight/DnsRecentEvents'
|
||||
import DnsTrafficLine from '@/views/charts2/charts/dnsInsight/DnsTrafficLine'
|
||||
import EntityDetailBasicInfo from '@/views/charts2/charts/entityDetail/EntityDetailBasicInfo'
|
||||
import EntityDetailLine from '@/views/charts2/charts/entityDetail/EntityDetailLine'
|
||||
import EntityDetailSubscriberKpi from '@/views/charts2/charts/entityDetail/EntityDetailSubscriberKpi'
|
||||
import EntityDetailSubscriberTopApp from '@/views/charts2/charts/entityDetail/EntityDetailSubscriberTopApp'
|
||||
import EntityDetailTabsChart from '@/views/charts2/charts/entityDetail/EntityDetailTabs'
|
||||
|
||||
import { getNowTime } from '@/utils/date-util'
|
||||
@@ -245,6 +259,8 @@ export default {
|
||||
DnsRecentEvents,
|
||||
DnsTrafficLine,
|
||||
EntityDetailBasicInfo,
|
||||
EntityDetailSubscriberKpi,
|
||||
EntityDetailSubscriberTopApp,
|
||||
EntityDetailLine,
|
||||
EntityDetailTabsChart
|
||||
},
|
||||
|
||||
@@ -34,6 +34,8 @@ export const typeMapping = {
|
||||
},
|
||||
entityDetail: {
|
||||
basicInfo: 712,
|
||||
subscriberKpi: 714,
|
||||
subscriberTopApp: 715,
|
||||
line: 107,
|
||||
tabsChart: 713
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="subscriber-kpi">
|
||||
<div class="subscriber-kpi-header">
|
||||
<div class="subscriber-kpi-title">{{$t('subscriber.kpi')}}</div>
|
||||
<date-time-range
|
||||
class="entity-detail-date-time-range"
|
||||
:start-time="timeFilter.startTime"
|
||||
:end-time="timeFilter.endTime"
|
||||
:date-range="timeFilter.dateRangeValue"
|
||||
ref="dateTimeRange"
|
||||
@change="reload"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="subscriber-kpi-body">
|
||||
<chart-no-data v-if="isNoData" test-id="noData"></chart-no-data>
|
||||
<chart-error v-if="showError" :content="errorMsg" />
|
||||
|
||||
<div class="subscriber-kpi-content" v-if="!isNoData && !showError">
|
||||
<div class="kpi-type">
|
||||
<div class="kpi-type-value">
|
||||
<div class="kpi-type-value-name">{{$t('subscriber.volume')}}</div>
|
||||
<div class="kpi-type-data" >
|
||||
<div class="kpi-type-value-number">
|
||||
{{unitConvert($_.get(kpiData, 'volume'), unitTypes.number).join(' ')}}
|
||||
</div>
|
||||
|
||||
<div class="data-trend">
|
||||
<div class="data-total-trend data-total-trend-red">
|
||||
<i class="cn-icon-rise1 cn-icon"></i>
|
||||
<span >32%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-type-value">
|
||||
<div class="kpi-type-value-name">{{$t('subscriber.throughput')}}</div>
|
||||
<div class="kpi-type-data" >
|
||||
<div class="kpi-type-value-number" >{{unitConvert($_.get(kpiData, 'throughput'), unitTypes.bps).join(' ')}}</div>
|
||||
<div class="data-trend">
|
||||
|
||||
<div class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span >8%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="kpi-type-value">
|
||||
<div class="kpi-type-value-name">{{$t('subscriber.latency')}}</div>
|
||||
<div class="kpi-type-data" >
|
||||
<div class="kpi-type-value-number" >{{unitConvert($_.get(kpiData, 'latency'), unitTypes.time).join(' ')}}</div>
|
||||
<div class="data-trend">
|
||||
|
||||
<div 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.packetLoss')}}</div>
|
||||
<div class="kpi-type-data" >
|
||||
<div class="kpi-type-value-number" >{{unitConvert($_.get(kpiData, 'packetLoss'), unitTypes.percent).join(' ')}}</div>
|
||||
<div class="data-trend">
|
||||
|
||||
<div class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span >66%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/utils/api'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
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 axios from 'axios'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailSubscriberKpi',
|
||||
components: {
|
||||
ChartError,
|
||||
ChartNoData
|
||||
},
|
||||
mixins: [chartMixin],
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const queryCondition = ref(query.queryCondition || '')
|
||||
|
||||
// 获取url携带的range、startTime、endTime
|
||||
const rangeParam = query.kpiRange
|
||||
const startTimeParam = query.kpiStartTime
|
||||
const endTimeParam = query.kpiEndTime
|
||||
|
||||
// 优先级:url > config.js > 默认值。
|
||||
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.entity.subscriberKpi || 60)
|
||||
const timeFilter = ref({ dateRangeValue })
|
||||
if (!startTimeParam || !endTimeParam) {
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
timeFilter.value.startTime = startTime
|
||||
timeFilter.value.endTime = endTime
|
||||
} else {
|
||||
timeFilter.value.startTime = parseInt(startTimeParam)
|
||||
timeFilter.value.endTime = parseInt(endTimeParam)
|
||||
}
|
||||
|
||||
return {
|
||||
queryCondition,
|
||||
timeFilter
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
kpiData: {
|
||||
volume: 5300000000,
|
||||
throughput: 600000,
|
||||
latency: 21,
|
||||
packetLoss: 0.0192
|
||||
},
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
isNoData: false,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
timeFilter: {
|
||||
handler () {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init (val, show, active, n) {
|
||||
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 => {
|
||||
const res = response.data
|
||||
if (response.status === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.showError = false
|
||||
if (!this.isNoData) {
|
||||
this.kpiData = res.data.result
|
||||
}
|
||||
} else {
|
||||
this.httpError(res)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.httpError(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
// 测试代码
|
||||
// this.isNoData = false
|
||||
})
|
||||
},
|
||||
httpError (e) {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
},
|
||||
reload (startTime, endTime, dateRangeValue) {
|
||||
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime) }
|
||||
const { query } = this.$route
|
||||
|
||||
const newUrl = urlParamsHandler(window.location.href, query, {
|
||||
kpiStartTime: this.timeFilter.startTime,
|
||||
kpiEndTime: this.timeFilter.endTime,
|
||||
kpiRange: dateRangeValue.value
|
||||
})
|
||||
overwriteUrl(newUrl)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,290 @@
|
||||
<template>
|
||||
<div class="subscriber-top-app">
|
||||
<div class="subscriber-top-app-header">
|
||||
<div class="subscriber-top-app-title">{{$t('subscriber.topApp')}}</div>
|
||||
<date-time-range
|
||||
class="entity-detail-date-time-range"
|
||||
:start-time="timeFilter.startTime"
|
||||
:end-time="timeFilter.endTime"
|
||||
:date-range="timeFilter.dateRangeValue"
|
||||
ref="dateTimeRange"
|
||||
@change="reload"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<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" />
|
||||
|
||||
<div class="top-app-left" v-show="!isNoData && !showError">
|
||||
<div class="app-data" v-for="(app, index) in topAppData">
|
||||
<div class="app-index">{{++index}}</div>
|
||||
<div class="app-name">{{app.name}}</div>
|
||||
<div class="app-trend">
|
||||
<i class="cn-icon cn-icon-egress"></i>
|
||||
<div class="app-up">{{app.up}}</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>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-app-right" >
|
||||
<div class="chart-content" id="subscriberTopAppChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/utils/api'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
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 axios from 'axios'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
import * as echarts from 'echarts'
|
||||
import { entityDetailSubscriberTopApp } from '@/views/charts2/charts/options/echartOption'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailSubscriberTopApp',
|
||||
components: {
|
||||
ChartError,
|
||||
ChartNoData
|
||||
},
|
||||
mixins: [chartMixin],
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const queryCondition = ref(query.queryCondition || '')
|
||||
|
||||
// 获取url携带的range、startTime、endTime
|
||||
const rangeParam = query.topAppRange
|
||||
const startTimeParam = query.topAppStartTime
|
||||
const endTimeParam = query.topAppEndTime
|
||||
|
||||
// 优先级:url > config.js > 默认值。
|
||||
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.entity.subscriberTopApp || 60)
|
||||
const timeFilter = ref({ dateRangeValue })
|
||||
if (!startTimeParam || !endTimeParam) {
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
timeFilter.value.startTime = startTime
|
||||
timeFilter.value.endTime = endTime
|
||||
} else {
|
||||
timeFilter.value.startTime = parseInt(startTimeParam)
|
||||
timeFilter.value.endTime = parseInt(endTimeParam)
|
||||
}
|
||||
|
||||
return {
|
||||
queryCondition,
|
||||
timeFilter,
|
||||
myChart: shallowRef(null)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
topAppData: [
|
||||
{
|
||||
name: 'Wetchat',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'QQ',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Douyin',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Weibo',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Tecent',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Kuaishou',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Taobao',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Jd',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Aiqiyi',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
},
|
||||
{
|
||||
name: 'Baidu',
|
||||
up: '1.2GB',
|
||||
down: '28MB'
|
||||
}
|
||||
],
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
isNoData: false,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
timeFilter: {
|
||||
handler () {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init (val, show, active, n) {
|
||||
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 => {
|
||||
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()
|
||||
}
|
||||
} else {
|
||||
this.httpError(res)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.httpError(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
// 无数据时的测试代码
|
||||
//this.isNoData = false
|
||||
//this.initEchart()
|
||||
})
|
||||
},
|
||||
initEchart (data) {
|
||||
data = [
|
||||
{
|
||||
count: 0.307,
|
||||
app: 1
|
||||
},
|
||||
{
|
||||
count: 0.206,
|
||||
app: 2
|
||||
},
|
||||
{
|
||||
count: 0.09,
|
||||
app: 3
|
||||
},
|
||||
{
|
||||
count: 0.082,
|
||||
app: 4
|
||||
},
|
||||
{
|
||||
count: 0.06,
|
||||
app: 5
|
||||
},
|
||||
{
|
||||
count: 0.032,
|
||||
app: 6
|
||||
},
|
||||
{
|
||||
count: 0.024,
|
||||
app: 7
|
||||
},
|
||||
{
|
||||
count: 0.017,
|
||||
app: 8
|
||||
},
|
||||
{
|
||||
count: 0.009,
|
||||
app: 9
|
||||
},
|
||||
{
|
||||
count: 0.006,
|
||||
app: 10
|
||||
}
|
||||
]
|
||||
if (data && data.length > 0) {
|
||||
const chartDom = document.getElementById('subscriberTopAppChart')
|
||||
this.myChart = echarts.getInstanceByDom(chartDom)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.myChart = echarts.init(chartDom)
|
||||
const chartOption = this.$_.cloneDeep(entityDetailSubscriberTopApp)
|
||||
chartOption.series[0].data = data.map(d => {
|
||||
return [d.count, d.app]
|
||||
}).reverse()
|
||||
this.myChart.setOption(chartOption)
|
||||
}
|
||||
},
|
||||
resize () {
|
||||
if (this.myChart) {
|
||||
this.myChart.resize()
|
||||
}
|
||||
},
|
||||
httpError (e) {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
},
|
||||
reload (startTime, endTime, dateRangeValue) {
|
||||
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime) }
|
||||
const { query } = this.$route
|
||||
|
||||
const newUrl = urlParamsHandler(window.location.href, query, {
|
||||
topAppStartTime: this.timeFilter.startTime,
|
||||
topAppEndTime: this.timeFilter.endTime,
|
||||
topAppRange: dateRangeValue.value
|
||||
})
|
||||
overwriteUrl(newUrl)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.myChart = null
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
window.addEventListener('resize', this.resize)
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
// 检测时发现该方法占用较大内存,且未被释放
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
chartColor5,
|
||||
chartColor6,
|
||||
chartColorForBehaviorPattern,
|
||||
unitTypes
|
||||
unitTypes,
|
||||
chartColorForSubscriberTopApp
|
||||
} from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { axisFormatter } from '@/views/charts/charts/tools'
|
||||
@@ -666,3 +667,58 @@ export const stackedBarChartOption = {
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const entityDetailSubscriberTopApp = {
|
||||
xAxis: {
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: 0,
|
||||
left: 15,
|
||||
right: 20,
|
||||
bottom: 0
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#E2E5EC'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
barWidth: 14,
|
||||
barMaxHeight: 20,
|
||||
itemStyle: {
|
||||
color: function (params) {
|
||||
const colorList = chartColorForSubscriberTopApp
|
||||
return colorList[params.dataIndex]
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
type: 'bar',
|
||||
label: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
valueAnimation: true,
|
||||
formatter: function (param, index, callback) {
|
||||
return `${unitConvert(param.value[0], unitTypes.percent, null, null, 1).join(' ')}`
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user