CN-708 feat: 色块图开发
This commit is contained in:
@@ -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';
|
||||||
|
|||||||
85
src/assets/css/components/views/charts2/linkBlock.scss
Normal file
85
src/assets/css/components/views/charts2/linkBlock.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.link-direction-grid {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
import './npm'
|
import './npm'
|
||||||
|
import './linkMonitor'
|
||||||
|
|||||||
18
src/mock/linkMonitor.js
Normal file
18
src/mock/linkMonitor.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 执行状态属性 值与名称之间的映射 */
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -19,5 +19,9 @@ export const typeMapping = {
|
|||||||
npmNetworkQuantity: 703,
|
npmNetworkQuantity: 703,
|
||||||
npmRecentEvents: 602,
|
npmRecentEvents: 602,
|
||||||
appEventTable: 603
|
appEventTable: 603
|
||||||
|
},
|
||||||
|
linkMonitor: {
|
||||||
|
linkBlock: 707,
|
||||||
|
linkTrafficSankey: 708
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
src/views/charts2/charts/linkMonitor/LinkBlock.vue
Normal file
100
src/views/charts2/charts/linkMonitor/LinkBlock.vue
Normal 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>
|
||||||
12
src/views/charts2/charts/linkMonitor/LinkDirectionGrid.vue
Normal file
12
src/views/charts2/charts/linkMonitor/LinkDirectionGrid.vue
Normal 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>
|
||||||
29
src/views/charts2/charts/linkMonitor/LinkTrafficSankey.vue
Normal file
29
src/views/charts2/charts/linkMonitor/LinkTrafficSankey.vue
Normal 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>
|
||||||
Reference in New Issue
Block a user