CN-708 feat: 色块图开发
This commit is contained in:
@@ -62,4 +62,7 @@
|
||||
@import './views/charts2/npmAppEventTable';
|
||||
@import './views/charts2/npmRelatedSessions';
|
||||
@import './views/charts2/npmTrafficLine';
|
||||
@import './views/charts2/linkBlock';
|
||||
@import './views/charts2/linkTrafficSankey';
|
||||
@import './views/charts2/linkDirectionGrid';
|
||||
//@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 {
|
||||
$blue: #2C72C6;
|
||||
$blue: #046ECA;
|
||||
$grey: #353636;
|
||||
height:calc(100% - 64px);
|
||||
font-size:12px;
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
}
|
||||
.el-tabs__header {
|
||||
margin-bottom: 3px;
|
||||
margin-bottom: 10px;
|
||||
width: calc(100% - 272px);
|
||||
}
|
||||
.el-tabs__nav-wrap::after {
|
||||
@@ -92,24 +92,25 @@
|
||||
background-color: transparent ;
|
||||
}
|
||||
.el-tabs__nav.is-top {
|
||||
height: 33px;
|
||||
|
||||
.el-tabs__active-bar {
|
||||
display: none;
|
||||
background-color: $blue;
|
||||
}
|
||||
.el-tabs__item {
|
||||
margin: 0 20px 0 0;
|
||||
padding:0px;
|
||||
font-weight: 400;
|
||||
padding: 0 10px;
|
||||
height: 33px;
|
||||
color: $grey;
|
||||
font-size: 14px;
|
||||
}
|
||||
.el-tabs__item.is-top.is-active {
|
||||
border-bottom: 2px solid $blue;
|
||||
|
||||
&.el-tabs__item.is-top.is-active {
|
||||
color:$blue;
|
||||
height: 33px;
|
||||
margin:0 20px 7px 0;
|
||||
padding:0px;
|
||||
font-weight:400;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.el-tabs__content {
|
||||
height: calc(100% - 40px);
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
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',
|
||||
dimensionEvents: '/interface/overview/event/dimensionEvents'
|
||||
}
|
||||
},
|
||||
linkMonitor: {
|
||||
links: '/interface/linkMonitor/links'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ export const panelTypeAndRouteMapping = {
|
||||
domainEntityDetail: 5,
|
||||
appEntityDetail: 6,
|
||||
cryptocurrency: 7,
|
||||
ipDrillDownTest: 8
|
||||
ipDrillDownTest: 8,
|
||||
linkMonitor: 14
|
||||
}
|
||||
|
||||
/* operationLog state 执行状态属性 值与名称之间的映射 */
|
||||
|
||||
@@ -859,3 +859,30 @@ export function urlParamsHandler (url, oldParams, newParams, cleanOldParams) {
|
||||
export function overwriteUrl (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"
|
||||
@toggleLoading="toggleLoading"
|
||||
></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>
|
||||
</template>
|
||||
|
||||
@@ -133,6 +145,8 @@ import NpmEventsHeader from '@/views/charts2/charts/npm/NpmEventsHeader'
|
||||
import RelatedSessions from '@/views/charts2/charts/npm/RelatedSessions'
|
||||
import NpmIpMap from '@/views/charts2/charts/npm/NpmIpMap'
|
||||
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 { getNowTime, getSecond } from '@/utils/date-util'
|
||||
import { ref } from 'vue'
|
||||
@@ -156,7 +170,9 @@ export default {
|
||||
NpmAppEventTable,
|
||||
RelatedSessions,
|
||||
NpmIpMap,
|
||||
NpmTrafficLine
|
||||
NpmTrafficLine,
|
||||
LinkBlock,
|
||||
LinkTrafficSankey
|
||||
},
|
||||
props: {
|
||||
chart: Object,
|
||||
|
||||
@@ -19,5 +19,9 @@ export const typeMapping = {
|
||||
npmNetworkQuantity: 703,
|
||||
npmRecentEvents: 602,
|
||||
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