CN-708 feat: 色块图开发

This commit is contained in:
chenjinsong
2022-09-10 23:13:42 +08:00
parent 503315b8ad
commit 9bc4fa8fdb
15 changed files with 363 additions and 18 deletions

View File

@@ -62,4 +62,7 @@
@import './views/charts2/npmAppEventTable'; @import './views/charts2/npmAppEventTable';
@import './views/charts2/npmRelatedSessions'; @import './views/charts2/npmRelatedSessions';
@import './views/charts2/npmTrafficLine'; @import './views/charts2/npmTrafficLine';
@import './views/charts2/linkBlock';
@import './views/charts2/linkTrafficSankey';
@import './views/charts2/linkDirectionGrid';
//@import '../chart'; //@import '../chart';

View File

@@ -0,0 +1,85 @@
.link-blocks {
$blue: #046ECA;
$grey: #353636;
border: 1px solid #E2E5EC;
height: 100%;
width: 100%;
border-radius: 4px;
background-color: #F7F7F7;
.el-tabs {
margin-left: 20px;
.el-tabs__nav-wrap {
padding-top: 5px;
&::after {
height: 1px;
background-color: transparent ;
}
}
.el-tabs__nav.is-top {
height: 33px;
.el-tabs__active-bar {
background-color: $blue;
}
.el-tabs__item {
padding: 0 10px;
height: 33px;
color: $grey;
font-size: 14px;
&.el-tabs__item.is-top.is-active {
color: $blue;
}
&:nth-child(2) {
padding-left: 0;
}
}
}
}
.block-list {
display: flex;
flex-wrap: wrap;
padding: 8px 14px 0 20px;
.link-block {
height: 30px;
width: 30px;
border-radius: 2px;
margin: 0 6px 6px 0;
}
}
}
.link-block__popper {
background-color: #1F2B33 !important;
border-color: #F7F7F7 !important;
.el-popper__arrow::before {
background-color: #1F2B33 !important;
border-color: #F7F7F7 !important;
}
.popper-content {
.popper-content__link-id {
padding-bottom: 4px;
font-size: 14px;
color: white;
}
.popper-content__link-info {
display: flex;
font-size: 12px;
.info__label {
color: #D8D8D8;
flex-basis: 110px;
}
.info__value {
color: white;
}
}
}
}

View File

@@ -0,0 +1,3 @@
.link-direction-grid {
}

View File

@@ -0,0 +1,42 @@
.link-traffic-sankey {
$blue: #046ECA;
$grey: #353636;
border: 1px solid #E2E5EC;
height: 100%;
width: 100%;
border-radius: 4px;
.el-tabs {
margin-left: 20px;
.el-tabs__nav-wrap {
padding-top: 5px;
&::after {
height: 1px;
background-color: transparent ;
}
}
.el-tabs__nav.is-top {
height: 33px;
.el-tabs__active-bar {
background-color: $blue;
}
.el-tabs__item {
padding: 0 10px;
height: 33px;
color: $grey;
font-size: 14px;
&.el-tabs__item.is-top.is-active {
color: $blue;
}
&:nth-child(2) {
padding-left: 0;
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
.tabs { .tabs {
$blue: #2C72C6; $blue: #046ECA;
$grey: #353636; $grey: #353636;
height:calc(100% - 64px); height:calc(100% - 64px);
font-size:12px; font-size:12px;
@@ -84,7 +84,7 @@
} }
} }
.el-tabs__header { .el-tabs__header {
margin-bottom: 3px; margin-bottom: 10px;
width: calc(100% - 272px); width: calc(100% - 272px);
} }
.el-tabs__nav-wrap::after { .el-tabs__nav-wrap::after {
@@ -92,24 +92,25 @@
background-color: transparent ; background-color: transparent ;
} }
.el-tabs__nav.is-top { .el-tabs__nav.is-top {
height: 33px;
.el-tabs__active-bar { .el-tabs__active-bar {
display: none; background-color: $blue;
} }
.el-tabs__item { .el-tabs__item {
margin: 0 20px 0 0; padding: 0 10px;
padding:0px;
font-weight: 400;
color:$grey;
font-size:14px;
}
.el-tabs__item.is-top.is-active {
border-bottom: 2px solid $blue;
color:$blue;
height: 33px; height: 33px;
margin:0 20px 7px 0; color: $grey;
padding:0px; font-size: 14px;
font-weight:400;
&.el-tabs__item.is-top.is-active {
color:$blue;
}
&:nth-child(2) {
padding-left: 0;
}
} }
} }
.el-tabs__content { .el-tabs__content {
height: calc(100% - 40px); height: calc(100% - 40px);

View File

@@ -1 +1,2 @@
import './npm' import './npm'
import './linkMonitor'

18
src/mock/linkMonitor.js Normal file
View File

@@ -0,0 +1,18 @@
import Mock from 'mockjs'
const openMock = true
if (openMock) {
Mock.mock(BASE_CONFIG.baseUrl + 'interface/linkMonitor/links', 'get', function (requestObj) {
const linkData = []
for (let i = 0; i < 94; i++) {
linkData.push({ linkId: 20 * (i + 300), totalBitsRate: Math.floor(Math.pow(1.1, i) * 10000) })
}
return {
msg: 'success',
code: 200,
data: {
result: linkData
}
}
})
}

View File

@@ -194,6 +194,9 @@ export const api = {
recentEventsD: '/interface/application/performance/overview/drilldown/dimension/recentEvents', recentEventsD: '/interface/application/performance/overview/drilldown/dimension/recentEvents',
dimensionEvents: '/interface/overview/event/dimensionEvents' dimensionEvents: '/interface/overview/event/dimensionEvents'
} }
},
linkMonitor: {
links: '/interface/linkMonitor/links'
} }
} }

View File

@@ -54,7 +54,8 @@ export const panelTypeAndRouteMapping = {
domainEntityDetail: 5, domainEntityDetail: 5,
appEntityDetail: 6, appEntityDetail: 6,
cryptocurrency: 7, cryptocurrency: 7,
ipDrillDownTest: 8 ipDrillDownTest: 8,
linkMonitor: 14
} }
/* operationLog state 执行状态属性 值与名称之间的映射 */ /* operationLog state 执行状态属性 值与名称之间的映射 */

View File

@@ -859,3 +859,30 @@ export function urlParamsHandler (url, oldParams, newParams, cleanOldParams) {
export function overwriteUrl (url) { export function overwriteUrl (url) {
window.history.pushState('', '', url) window.history.pushState('', '', url)
} }
/*
startColor: 渐变起始颜色,对应最大值
endColor: 渐变结束颜色,对应最小值
values: 从大到小排好序的数值
*/
export function colorGradientCalculation (startColor, endColor, values) {
const colors = []
const startRgbArr = colorHexToRgbArr(startColor)
const endRgbArr = colorHexToRgbArr(endColor)
const rDiff = endRgbArr[0] - startRgbArr[0]
const gDiff = endRgbArr[1] - startRgbArr[1]
const bDiff = endRgbArr[2] - startRgbArr[2]
const valueDiff = values[0] - values[values.length - 1]
values.forEach((v, i) => {
colors.push(`rgb(${startRgbArr[0] + Math.floor(rDiff * (valueDiff - diff(v)) / valueDiff)},${startRgbArr[1] + Math.floor(gDiff * (valueDiff - diff(v)) / valueDiff)},${startRgbArr[2] + Math.floor(bDiff * (valueDiff - diff(v)) / valueDiff)})`)
})
function diff (v) {
return v - values[values.length - 1]
}
return colors
}
// returns an array like [11,22,33]
export function colorHexToRgbArr (hex) {
return [1, 3, 5].map((h) => parseInt(hex.substring(h, h + 2), 16))
}

View File

@@ -110,6 +110,18 @@
:chart="chart" :chart="chart"
@toggleLoading="toggleLoading" @toggleLoading="toggleLoading"
></npm-traffic-line> ></npm-traffic-line>
<link-block
v-else-if="chart.type === typeMapping.linkMonitor.linkBlock"
:time-filter="timeFilter"
:chart="chart"
@toggleLoading="toggleLoading"
></link-block>
<link-traffic-sankey
v-else-if="chart.type === typeMapping.linkMonitor.linkTrafficSankey"
:time-filter="timeFilter"
:chart="chart"
@toggleLoading="toggleLoading"
></link-traffic-sankey>
</div> </div>
</template> </template>
@@ -133,6 +145,8 @@ import NpmEventsHeader from '@/views/charts2/charts/npm/NpmEventsHeader'
import RelatedSessions from '@/views/charts2/charts/npm/RelatedSessions' import RelatedSessions from '@/views/charts2/charts/npm/RelatedSessions'
import NpmIpMap from '@/views/charts2/charts/npm/NpmIpMap' import NpmIpMap from '@/views/charts2/charts/npm/NpmIpMap'
import NpmTrafficLine from '@/views/charts2/charts/npm/NpmTrafficLine' import NpmTrafficLine from '@/views/charts2/charts/npm/NpmTrafficLine'
import LinkBlock from '@/views/charts2/charts/linkMonitor/LinkBlock'
import LinkTrafficSankey from '@/views/charts2/charts/linkMonitor/LinkTrafficSankey'
import { get } from '@/utils/http' import { get } from '@/utils/http'
import { getNowTime, getSecond } from '@/utils/date-util' import { getNowTime, getSecond } from '@/utils/date-util'
import { ref } from 'vue' import { ref } from 'vue'
@@ -156,7 +170,9 @@ export default {
NpmAppEventTable, NpmAppEventTable,
RelatedSessions, RelatedSessions,
NpmIpMap, NpmIpMap,
NpmTrafficLine NpmTrafficLine,
LinkBlock,
LinkTrafficSankey
}, },
props: { props: {
chart: Object, chart: Object,

View File

@@ -19,5 +19,9 @@ export const typeMapping = {
npmNetworkQuantity: 703, npmNetworkQuantity: 703,
npmRecentEvents: 602, npmRecentEvents: 602,
appEventTable: 603 appEventTable: 603
},
linkMonitor: {
linkBlock: 707,
linkTrafficSankey: 708
} }
} }

View File

@@ -0,0 +1,100 @@
<template>
<div class="link-blocks">
<el-tabs v-model="tab">
<el-tab-pane :label="$t('linkMonitor.links')" :name="0"></el-tab-pane>
<el-tab-pane :label="$t('linkMonitor.nextHopInternet')" :name="1"></el-tab-pane>
</el-tabs>
<div class="block-list">
<el-popover
placement="bottom"
trigger="hover"
popper-class="link-block__popper"
v-for="(item, index) in linkData"
:width="220"
:key="index"
>
<template #reference>
<div class="link-block" :style="`background-color: ${item.color}`"></div>
</template>
<template #default>
<div class="popper-content">
<div class="popper-content__link-id">Link ID: {{item.linkId}}</div>
<div class="popper-content__link-info">
<div class="info__label">{{$t('linkMonitor.linkBlock.total')}}</div>
<div class="info__value">{{unitConvert(item.totalBitsRate, unitTypes.bps).join('')}}</div>
</div>
<div class="popper-content__link-info">
<div class="info__label">{{$t('linkMonitor.linkBlock.bandwidthUsage')}}</div>
<div class="info__value">50%</div>
</div>
</div>
</template>
</el-popover>
</div>
<div class="block-heat-legend"></div>
</div>
</template>
<script>
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { colorGradientCalculation } from '@/utils/tools'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
export default {
name: 'LinkBlock',
mixins: [chartMixin],
components: {
ChartNoData
},
data () {
return {
unitTypes,
linkData: [],
gradientColor: ['#FF005C', '#40537E'] // [start, end]
}
},
setup () {
const { query } = useRoute()
const tab = ref(query.blockTab || 0)
return {
tab
}
},
mounted () {
this.init()
},
methods: {
unitConvert,
init () {
this.toggleLoading(true)
get(api.linkMonitor.links).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
return
}
const sorted = res.data.result.sort((a, b) => b.totalBitsRate - a.totalBitsRate)
const colors = colorGradientCalculation(this.gradientColor[0], this.gradientColor[1], sorted.map(s => s.totalBitsRate))
sorted.forEach((s, i) => {
s.color = colors[i]
})
this.linkData = sorted
} else {
this.isNoData = true
}
}).catch(e => {
console.error(e)
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
}
}
}
</script>

View File

@@ -0,0 +1,12 @@
<template>
<div class="link-direction-grid"></div>
</template>
<script>
import chartMixin from '@/views/charts2/chart-mixin'
export default {
name: 'LinkDirectionGrid',
mixins: [chartMixin]
}
</script>

View File

@@ -0,0 +1,29 @@
<template>
<div class="link-traffic-sankey">
<el-tabs v-model="tab">
<el-tab-pane :label="$t('linkMonitor.ingress')" :name="0"></el-tab-pane>
<el-tab-pane :label="$t('linkMonitor.egress')" :name="1"></el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
export default {
name: 'LinksTrafficSankey',
mixins: [chartMixin],
components: {
ChartNoData
},
data () {
return {
tab: 0
}
},
mounted () {
this.toggleLoading(false)
}
}
</script>