CN-980 feat: 实体详情开发准备
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
.edit-appearance-base__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
justify-content: flex-start;
|
||||
height: 100px;
|
||||
margin-top: 3px;
|
||||
padding-left:200px;
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
align-items: center;
|
||||
}
|
||||
.el-table__header tr th:nth-of-type(1) .cell {
|
||||
justify-content: start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.score-cell {
|
||||
display: flex !important;
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
.panel-box2.panel-box2--entity-detail {
|
||||
height: 100%;
|
||||
|
||||
.chart-list {
|
||||
height: 100%;
|
||||
|
||||
&>.vue-grid-layout {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.panel-box2 {
|
||||
height: calc(100% - 20px);
|
||||
.panel__header {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*
|
||||
.entity-detail.cn-home {
|
||||
.panel-chart {
|
||||
width: 100%;
|
||||
@@ -105,3 +106,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -58,9 +58,12 @@ export const panelTypeAndRouteMapping = {
|
||||
networkOverviewDrillDown: 13,
|
||||
networkAppPerformance: 2,
|
||||
dnsServiceInsights: 3,
|
||||
ipEntityDetail: 4,
|
||||
/* ipEntityDetail: 4,
|
||||
domainEntityDetail: 5,
|
||||
appEntityDetail: 6,
|
||||
appEntityDetail: 6,*/
|
||||
ipEntityDetail: 21,
|
||||
domainEntityDetail: 22,
|
||||
appEntityDetail: 23,
|
||||
cryptocurrency: 7,
|
||||
ipDrillDownTest: 8,
|
||||
linkMonitor: 14,
|
||||
|
||||
@@ -160,6 +160,24 @@
|
||||
:chart="chart"
|
||||
@toggleLoading="toggleLoading"
|
||||
></dns-traffic-line>
|
||||
<entity-detail-basic-info
|
||||
v-else-if="chart.type === typeMapping.entityDetail.basicInfo"
|
||||
:chart="chart"
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-basic-info>
|
||||
<entity-detail-line
|
||||
v-else-if="chart.type === typeMapping.entityDetail.line"
|
||||
:chart="chart"
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-line>
|
||||
<entity-detail-tabs-chart
|
||||
v-else-if="chart.type === typeMapping.entityDetail.tabsChart"
|
||||
:chart="chart"
|
||||
:entity="entity"
|
||||
@toggleLoading="toggleLoading"
|
||||
></entity-detail-tabs-chart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -190,6 +208,9 @@ import DnsActiveMaliciousDomain from '@/views/charts2/charts/dnsInsight/DnsActiv
|
||||
import DnsEventChart from '@/views/charts2/charts/dnsInsight/DnsEventChart'
|
||||
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 EntityDetailTabsChart from '@/views/charts2/charts/entityDetail/EntityDetailTabsChart'
|
||||
|
||||
import { getNowTime } from '@/utils/date-util'
|
||||
import { ref } from 'vue'
|
||||
@@ -222,13 +243,17 @@ export default {
|
||||
DnsActiveMaliciousDomain,
|
||||
DnsEventChart,
|
||||
DnsRecentEvents,
|
||||
DnsTrafficLine
|
||||
DnsTrafficLine,
|
||||
EntityDetailBasicInfo,
|
||||
EntityDetailLine,
|
||||
EntityDetailTabsChart
|
||||
},
|
||||
props: {
|
||||
chart: Object,
|
||||
metric: String,
|
||||
timeFilter: Object,
|
||||
extraParams: Object
|
||||
extraParams: Object,
|
||||
entity: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
:metric="metric"
|
||||
:extra-params="extraParams"
|
||||
:id="item.id"
|
||||
:entity="entity"
|
||||
ref="chartGrid"
|
||||
@npmTabChange="npmTabChange"
|
||||
:chart="item"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="panel-box2">
|
||||
<div class="panel__header">
|
||||
<div class="panel-box2" :class="{'panel-box2--entity-detail': entity.entityType}">
|
||||
<div class="panel__header" v-if="!entity.entityType">
|
||||
<div class="panel__title">{{panelName?panelName:(panel.i18n ? $t(panel.i18n) : panel.name)}}
|
||||
<div v-if="showScore" class="score">
|
||||
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export default {
|
||||
props: {
|
||||
chart: Object,
|
||||
timeFilter: Object
|
||||
timeFilter: Object,
|
||||
entity: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -31,5 +31,10 @@ export const typeMapping = {
|
||||
dnsEventChart: 711,
|
||||
dnsRecentEvents: 605,
|
||||
dnsActiveMaliciousDomain: 604
|
||||
},
|
||||
entityDetail: {
|
||||
basicInfo: 712,
|
||||
line: 107,
|
||||
tabsChart: 713
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div style="border: 1px solid #ff5500; height: 100%;">{{entity}}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailBasicInfo',
|
||||
mixins: [chartMixin]
|
||||
}
|
||||
</script>
|
||||
16
src/views/charts2/charts/entityDetail/EntityDetailLine.vue
Normal file
16
src/views/charts2/charts/entityDetail/EntityDetailLine.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div style="border: 1px solid #ff5500; height: 100%;">{{entity}}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailLine',
|
||||
mixins: [chartMixin],
|
||||
mounted () {
|
||||
this.toggleLoading(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div style="border: 1px solid #ff5500; height: 100%;">{{entity}}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailTabsChart',
|
||||
mixins: [chartMixin]
|
||||
}
|
||||
</script>
|
||||
@@ -1,68 +1,46 @@
|
||||
<template>
|
||||
<div class="cn-home entity-detail">
|
||||
<div class="entity-detail__header">
|
||||
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
||||
<div class="cn-entity__name">{{entityData.ip || entityData.domain || entityData.appName }}</div>
|
||||
</div>
|
||||
<main class="cn-body entity-detail__body">
|
||||
<div class="entity-detail__menu">
|
||||
<template v-for="(anchor,index) in anchorPoints" :key="anchor.id">
|
||||
<div class="menu-item" :class="{'menu-item--active':anchor.isActive}" @click="jumpToAnchor(index,anchor)">
|
||||
<span>{{anchor.label}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="entity-detail__content" @scroll="scroll" id="detailWrapper">
|
||||
<cn-panel
|
||||
ref="cnPanel"
|
||||
<div class="entity-detail" style="height: 100%;">
|
||||
<panel
|
||||
:entity="entityData"
|
||||
:is-entity-detail="true"
|
||||
@chartLoaded="chartLoaded"
|
||||
></cn-panel>
|
||||
</div>
|
||||
</main>
|
||||
></panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useRoute } from 'vue-router'
|
||||
import Panel from '@/views/charts/Panel'
|
||||
import Panel from '@/views/charts2/Panel'
|
||||
import { panelTypeAndRouteMapping } from '@/utils/constants'
|
||||
export default {
|
||||
name: 'EntityDetail',
|
||||
components: {
|
||||
cnPanel: Panel
|
||||
Panel
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
anchorPoints: [], // { id, label, top, height }
|
||||
top: 0,
|
||||
scrollHeight: 0,
|
||||
clientHeight: 0,
|
||||
currentAnchor: 0
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
setup (props) {
|
||||
const { query } = useRoute()
|
||||
let panelType
|
||||
const entityData = { entityType: query.entityType }
|
||||
switch (query.entityType) {
|
||||
case 'ip': {
|
||||
panelType = 4
|
||||
panelType = panelTypeAndRouteMapping.ipEntityDetail
|
||||
entityData.ip = query.name
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
panelType = 5
|
||||
panelType = panelTypeAndRouteMapping.domainEntityDetail
|
||||
entityData.domain = query.name
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
panelType = 6
|
||||
panelType = panelTypeAndRouteMapping.appEntityDetail
|
||||
entityData.appName = query.name
|
||||
break
|
||||
}
|
||||
default: {
|
||||
panelType = 4
|
||||
panelType = panelTypeAndRouteMapping.ipEntityDetail
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -72,83 +50,8 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
chartLoaded (chartList) {
|
||||
this.chartList = chartList
|
||||
this.anchorPoints = []
|
||||
let anchorPoints = []
|
||||
const panelDom = document.querySelector('#detailWrapper')
|
||||
this.scrollHeight = panelDom.scrollHeight
|
||||
this.clientHeight = panelDom.clientHeight
|
||||
chartList.forEach((chart, index) => {
|
||||
if (chart.params.anchorPoint) {
|
||||
const dom = document.querySelector(`[id='${chart.params.anchorPoint}']`)
|
||||
dom && anchorPoints.push({
|
||||
id: chart.params.anchorPoint,
|
||||
isActive: index === 0,
|
||||
label: chart.i18n ? this.$t(chart.i18n) : chart.name,
|
||||
top: dom.offsetTop + 10/* ,
|
||||
height: document.querySelector(`#${chart.params.anchorPoint}}`).scrollHeight */
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 从小到大排序
|
||||
anchorPoints = anchorPoints.sort((a, b) => {
|
||||
return a.top - b.top
|
||||
})
|
||||
if (!this.$_.isEmpty(anchorPoints)) {
|
||||
anchorPoints[0].top = 0
|
||||
}
|
||||
this.anchorPoints = anchorPoints
|
||||
},
|
||||
scroll (e) {
|
||||
this.top = (e.target.scrollTop + 10) || 0
|
||||
},
|
||||
jumpToAnchor (index, anchor) {
|
||||
const anchorEle = document.getElementById(anchor.id)
|
||||
this.anchorPoints.forEach((anchor, i) => {
|
||||
if (index === i) {
|
||||
anchor.isActive = true
|
||||
} else {
|
||||
anchor.isActive = false
|
||||
}
|
||||
})
|
||||
if (anchorEle) {
|
||||
anchorEle.scrollIntoView()
|
||||
document.documentElement.scrollTop = document.documentElement.scrollTop - 30
|
||||
}
|
||||
},
|
||||
resize () {
|
||||
this.chartLoaded(this.chartList)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.debounceFunc = this.$_.debounce(this.resize, 400)
|
||||
window.addEventListener('resize', this.debounceFunc)
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.debounceFunc)
|
||||
},
|
||||
computed: {
|
||||
iconClass () {
|
||||
let className
|
||||
switch (this.entityData.entityType) {
|
||||
case ('ip'): {
|
||||
className = 'cn-icon cn-icon-ip2'
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
className = 'cn-icon cn-icon-domain2'
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
className = 'cn-icon cn-icon-app2'
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return className
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
154
src/views/entityExplorer/EntityDetailOld.vue
Normal file
154
src/views/entityExplorer/EntityDetailOld.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div class="cn-home entity-detail">
|
||||
<div class="entity-detail__header">
|
||||
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
||||
<div class="cn-entity__name">{{entityData.ip || entityData.domain || entityData.appName }}</div>
|
||||
</div>
|
||||
<main class="cn-body entity-detail__body">
|
||||
<div class="entity-detail__menu">
|
||||
<template v-for="(anchor,index) in anchorPoints" :key="anchor.id">
|
||||
<div class="menu-item" :class="{'menu-item--active':anchor.isActive}" @click="jumpToAnchor(index,anchor)">
|
||||
<span>{{anchor.label}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="entity-detail__content" @scroll="scroll" id="detailWrapper">
|
||||
<cn-panel
|
||||
ref="cnPanel"
|
||||
:entity="entityData"
|
||||
:is-entity-detail="true"
|
||||
@chartLoaded="chartLoaded"
|
||||
></cn-panel>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useRoute } from 'vue-router'
|
||||
import Panel from '@/views/charts/Panel'
|
||||
export default {
|
||||
name: 'EntityDetail',
|
||||
components: {
|
||||
cnPanel: Panel
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
anchorPoints: [], // { id, label, top, height }
|
||||
top: 0,
|
||||
scrollHeight: 0,
|
||||
clientHeight: 0,
|
||||
currentAnchor: 0
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const { query } = useRoute()
|
||||
let panelType
|
||||
const entityData = { entityType: query.entityType }
|
||||
switch (query.entityType) {
|
||||
case 'ip': {
|
||||
panelType = 4
|
||||
entityData.ip = query.name
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
panelType = 5
|
||||
entityData.domain = query.name
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
panelType = 6
|
||||
entityData.appName = query.name
|
||||
break
|
||||
}
|
||||
default: {
|
||||
panelType = 4
|
||||
break
|
||||
}
|
||||
}
|
||||
entityData.type = panelType
|
||||
return {
|
||||
entityData
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
chartLoaded (chartList) {
|
||||
this.chartList = chartList
|
||||
this.anchorPoints = []
|
||||
let anchorPoints = []
|
||||
const panelDom = document.querySelector('#detailWrapper')
|
||||
this.scrollHeight = panelDom.scrollHeight
|
||||
this.clientHeight = panelDom.clientHeight
|
||||
chartList.forEach((chart, index) => {
|
||||
if (chart.params.anchorPoint) {
|
||||
const dom = document.querySelector(`[id='${chart.params.anchorPoint}']`)
|
||||
dom && anchorPoints.push({
|
||||
id: chart.params.anchorPoint,
|
||||
isActive: index === 0,
|
||||
label: chart.i18n ? this.$t(chart.i18n) : chart.name,
|
||||
top: dom.offsetTop + 10/* ,
|
||||
height: document.querySelector(`#${chart.params.anchorPoint}}`).scrollHeight */
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 从小到大排序
|
||||
anchorPoints = anchorPoints.sort((a, b) => {
|
||||
return a.top - b.top
|
||||
})
|
||||
if (!this.$_.isEmpty(anchorPoints)) {
|
||||
anchorPoints[0].top = 0
|
||||
}
|
||||
this.anchorPoints = anchorPoints
|
||||
},
|
||||
scroll (e) {
|
||||
this.top = (e.target.scrollTop + 10) || 0
|
||||
},
|
||||
jumpToAnchor (index, anchor) {
|
||||
const anchorEle = document.getElementById(anchor.id)
|
||||
this.anchorPoints.forEach((anchor, i) => {
|
||||
if (index === i) {
|
||||
anchor.isActive = true
|
||||
} else {
|
||||
anchor.isActive = false
|
||||
}
|
||||
})
|
||||
if (anchorEle) {
|
||||
anchorEle.scrollIntoView()
|
||||
document.documentElement.scrollTop = document.documentElement.scrollTop - 30
|
||||
}
|
||||
},
|
||||
resize () {
|
||||
this.chartLoaded(this.chartList)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.debounceFunc = this.$_.debounce(this.resize, 400)
|
||||
window.addEventListener('resize', this.debounceFunc)
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.debounceFunc)
|
||||
},
|
||||
computed: {
|
||||
iconClass () {
|
||||
let className
|
||||
switch (this.entityData.entityType) {
|
||||
case ('ip'): {
|
||||
className = 'cn-icon cn-icon-ip2'
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
className = 'cn-icon cn-icon-domain2'
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
className = 'cn-icon cn-icon-app2'
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return className
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user