CN-1150: 实体列表接口对接

This commit is contained in:
刘洪洪
2023-07-07 17:22:51 +08:00
parent 87cd43dde2
commit 9c46e1af47
23 changed files with 1432 additions and 983 deletions

View File

@@ -3,60 +3,60 @@
class="entity-explorer"
:class="{'entity-explorer--show-list': showList}">
<!-- 顶部工具栏在列表页显示 -->
<!-- <div class="explorer-top-tools explorer-top-tools-new" v-show="showList">-->
<!-- <div class="explorer-detection-top-tools">-->
<!-- <div class="explorer-top-tools-title">{{$t('network.entity')}}</div>-->
<!-- </div>-->
<!-- <div class="explorer-top-tools">-->
<!-- <DateTimeRange :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>-->
<!-- <TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>-->
<!-- <el-button-group size="mini">-->
<!-- <el-button size="mini" @click="listMode = 'list'" :class="{'active': listMode === 'list'}"><i class="cn-icon cn-icon-list"></i></el-button>-->
<!-- <el-button size="mini" @click="listMode = 'block'" :class="{'active': listMode === 'block'}"><i class="cn-icon cn-icon-blocks"></i></el-button>-->
<!-- </el-button-group>-->
<div class="explorer-top-tools" v-show="showList">
<DateTimeRange :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
<el-button-group size="mini">
<el-button size="mini" @click="setListMode('list')" :class="{'active': listMode === 'list'}"><i class="cn-icon cn-icon-list"></i></el-button>
<el-button size="mini" @click="setListMode('block')" :class="{'active': listMode === 'block'}"><i class="cn-icon cn-icon-blocks"></i></el-button>
</el-button-group>
<div class="explorer-top-tools explorer-top-tools-new" style="margin: 2px 0;" v-show="showList">
<div class="explorer-detection-top-tools">
<div class="explorer-top-tools-title" style="padding: 0;margin-left: -10px;">{{$t('network.entity')}}</div>
</div>
<!-- </div>-->
</div>
<!-- 搜索组件 -->
<explorer-search
v-if="!showList"
ref="search"
:class="{'explorer-search--show-list': showList}"
:show-list="showList"
@search="search"
></explorer-search>
<!--todo静态数据之后记得修改-->
<!-- <div class="explorer-result" v-if="showList">-->
<!-- 8,866 resultsIP 2666Domain 3200APP 3000-->
<!-- </div>-->
<!-- 内容区 -->
<div class="explorer-container" v-if="showList" style="height: calc(100% - 20px); flex-direction: column">
<div style="display: flex; height: auto;">
<entity-filter
:filter-data="filterData"
:loading-left="loadingLeft"
:q="q"
:time-filter="timeFilter"
@filter="filter"
></entity-filter>
<entity-list
:list-data="listData"
:list-mode="listMode"
:pageObj="pageObj"
:time-filter="timeFilter"
@pageSize="pageSize"
@pageNo="pageNo"
:loading="listLoading"
></entity-list>
<div v-if="showList" style="display: flex;flex-direction: row;">
<entity-filter
:filter-data="newFilterData"
:loading-left="loadingLeft"
:q="q"
:time-filter="timeFilter"
@filter="filter"
></entity-filter>
<div class="explorer-container" style="height: calc(100% - 62px);flex-direction: column;width: 100%;">
<explorer-search
ref="search"
:class="{'explorer-search--show-list': showList}"
:show-list="showList"
@search="search"
></explorer-search>
<div style="display: flex;flex-direction: column;height: calc(100% - 42px);">
<div class="explorer-result" v-if="showList">
<loading :loading="loadingCount"></loading>
<span>{{ summaryCount.total }}</span>resultsIP
<span>{{ summaryCount.ipCount }}</span>Domain
<span>{{ summaryCount.fqdnCount }}</span>APP
<span>{{ summaryCount.appCount }}</span>
</div>
<entity-list
style="width: 100%;"
:list-data="listData"
:list-mode="listMode"
:pageObj="pageObj"
:time-filter="timeFilter"
@pageSize="pageSize"
@pageNo="pageNo"
:loading="listLoading"
></entity-list>
</div>
</div>
</div>
<div class="explorer-foot" v-else>
<div class="explorer-foot" v-if="!showList">
<div>
<el-divider direction="vertical"></el-divider>
<div class="entity-overview">
@@ -150,8 +150,6 @@
<script>
import ExplorerSearch from '@/views/entityExplorer/search/ExplorerSearch'
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
import EntityFilter from '@/views/entityExplorer/EntityFilter'
import EntityList from '@/views/entityExplorer/entityList/EntityList'
import { entityType, defaultPageSize, riskLevelMapping } from '@/utils/constants'
@@ -172,8 +170,6 @@ export default {
components: {
Loading,
ExplorerSearch,
DateTimeRange,
TimeRefresh,
EntityFilter,
EntityList
},
@@ -210,23 +206,15 @@ export default {
{
label: this.$t('overall.country'),
column: 'countryDistinctCount',
topColumn: 'ip_location_country', // top弹框查询字段
topColumn: 'country', // top弹框查询字段
icon: 'cn-icon cn-icon-country',
showTopTen: false,
value: 0
},
{
label: this.$t('overall.province'),
column: 'provinceDistinctCount',
topColumn: 'ip_location_province', // top弹框查询字段
icon: 'cn-icon cn-icon-position',
showTopTen: false,
value: 0
},
{
label: this.$t('overall.city'),
column: 'cityDistinctCount',
topColumn: 'ip_location_city', // top弹框查询字段
topColumn: 'region', // top弹框查询字段
icon: 'cn-icon cn-icon-city',
showTopTen: false,
value: 0
@@ -234,7 +222,7 @@ export default {
{
label: this.$t('entities.asn'),
column: 'asnDistinctCount',
topColumn: 'ip_asn', // top弹框查询字段
topColumn: 'asn', // top弹框查询字段
icon: 'cn-icon cn-icon-cloud',
showTopTen: false,
value: 0
@@ -346,6 +334,26 @@ export default {
]
}
],
newFilterData: [
{
icon: 'cn-icon cn-icon-registration-country',
title: 'Top Countries',
totalCount: 0,
data: []
},
{
icon: 'cn-icon cn-icon-city',
title: 'Top Cities',
totalCount: 0,
data: []
},
{
icon: 'cn-icon cn-icon-as',
title: 'Top ASNs',
totalCount: 0,
data: []
}
],
listData: [],
q: '',
metaList: [],
@@ -367,7 +375,14 @@ export default {
// 实体详情列表页面 左侧筛选条件
loadingLeft: false,
initFlag: false, // 初始化标志避免初始化时pageSize和pageNo会调用搜索
timer: null // 初始化标志的延时器,需要销毁
timer: null, // 初始化标志的延时器,需要销毁
summaryCount: {
total: 0,
fqdnCount: 0,
ipCount: 0,
appCount: 0
},
loadingCount: false // 实体基数统计的loading
}
},
methods: {
@@ -420,6 +435,12 @@ export default {
return result
},
search (param) {
// todo 下版本08版本删除 ---- start
if (param && param.q.indexOf("QUERY('") > -1) {
this.$message.error(this.$t('overall.versionNotSupportThisFormat'))
return true
}
// 下版本08版本删除 ---- end
let q
let metaList
if (param) {
@@ -489,29 +510,35 @@ export default {
} else {
this.limitFilterType = false
}
this.queryFilter({ entityType: entityType, q: this.q, ...this.timeFilter })
if (entityType === 'ip') {
this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
}
// this.queryFilter({ entityType: entityType, q: this.q, ...this.timeFilter })
// if (entityType === 'ip') {
// this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
// }
this.queryFilterNew({ q: this.q, ...this.pageObj, ...this.timeFilter })
this.queryList({ q: this.q, ...this.pageObj, ...this.timeFilter })
this.queryListTotal({ q: this.q, ...this.timeFilter })
this.queryCount({ q: this.q, ...this.pageObj, ...this.timeFilter })
// this.queryListTotal({ q: this.q, ...this.timeFilter })
} else {
this.limitFilterType = false
this.queryFilter({ entityType: 'ip', q: this.q, ...this.timeFilter })
this.queryFilter({ entityType: 'domain', q: this.q, ...this.timeFilter })
this.queryFilter({ entityType: 'app', q: this.q, ...this.timeFilter })
this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
// this.queryFilter({ entityType: 'ip', q: this.q, ...this.timeFilter })
// this.queryFilter({ entityType: 'domain', q: this.q, ...this.timeFilter })
// this.queryFilter({ entityType: 'app', q: this.q, ...this.timeFilter })
// this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
this.queryFilterNew({ q: this.q, ...this.pageObj, ...this.timeFilter })
this.queryList({ q: this.q, ...this.pageObj, ...this.timeFilter })
this.queryListTotal({ q: this.q, ...this.timeFilter })
this.queryCount({ q: this.q, ...this.pageObj, ...this.timeFilter })
// this.queryListTotal({ q: this.q, ...this.timeFilter })
}
} else {
this.limitFilterType = false
this.queryFilter({ entityType: 'ip', ...this.timeFilter })
this.queryFilter({ entityType: 'app', ...this.timeFilter })
this.queryFilter({ entityType: 'domain', ...this.timeFilter })
this.queryFilter({ entityType: 'dns', ...this.timeFilter })
// this.queryFilter({ entityType: 'ip', ...this.timeFilter })
// this.queryFilter({ entityType: 'app', ...this.timeFilter })
// this.queryFilter({ entityType: 'domain', ...this.timeFilter })
// this.queryFilter({ entityType: 'dns', ...this.timeFilter })
this.queryFilterNew({ ...this.pageObj, ...this.timeFilter })
this.queryList({ ...this.pageObj, ...this.timeFilter })
this.queryListTotal({ ...this.timeFilter })
this.queryCount({ ...this.pageObj, ...this.timeFilter })
// this.queryListTotal({ ...this.timeFilter })
// 延时一秒避免初始化时pageSize为20pageNo为1也会调用“搜索”的情况
if (!this.initFlag) {
@@ -636,27 +663,87 @@ export default {
}
})
},
/** 新版查询filter数据 */
queryFilterNew (params) {
const queryParams = {
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || ''
}
this.loadingLeft = true
const aggCountry = get(api.entity.entityList.aggCountry, queryParams)
const aggCity = get(api.entity.entityList.aggCity, queryParams)
const aggAsn = get(api.entity.entityList.aggAsn, queryParams)
Promise.all([aggCountry, aggCity, aggAsn]).then(response => {
response.forEach((item, index) => {
if (item.code === 200 && item.data.list) {
this.newFilterData[index].data = []
item.data.list.forEach(item => {
const obj = { label: item.value, flag: '011-china', topColumn: 'country', value: item.uniqueEntities }
if (index === 0) {
obj.flag = item.uniqueEntities // 接口字段名称为'China'目前svg名称为'011-china',后续再指定方案调整
}
if (index === 1) {
obj.topColumn = 'region'
}
if (index === 2) {
obj.topColumn = 'asn'
}
this.newFilterData[index].data.push(obj)
})
}
})
}).catch(e => {
// e
}).finally(() => {
this.loadingLeft = false
})
},
/** 实体列表查询 */
queryList (params) {
this.listLoading = true
const queryParams = {
...params,
startTime: getSecond(params.startTime),
endTime: getSecond(params.endTime)
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || ''
}
get(api.entityList, queryParams).then(response => {
get(api.entity.entityList.list, queryParams).then(response => {
if (response.code === 200) {
this.listData = []
this.$nextTick(() => {
this.listData = response.data.result
this.listData = response.data.list
this.pageObj.total = response.data.total
})
} else {
console.error(response.message)
this.$message.error(response.message)
}
}).finally(() => {
this.listLoading = false
})
},
/** 实体基数统计 */
queryCount (params) {
this.loadingCount = true
const queryParams = {
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || '' // 目前版本搜索不支持实体名称搜索,下版本改进
}
get(api.entity.entityList.summaryCount, queryParams).then(response => {
if (response.code === 200) {
this.summaryCount = response.data
} else {
this.summaryCount = { total: 0, fqdnCount: 0, ipCount: 0, appCount: 0 }
}
}).catch(e => {
console.log(e)
this.summaryCount = { total: 0, fqdnCount: 0, ipCount: 0, appCount: 0 }
}).finally(() => {
this.loadingCount = false
})
},
queryListTotal (params) {
const queryParams = {
@@ -677,11 +764,6 @@ export default {
},
getEntityIndexData () {
const now = window.$dayJs.tz().valueOf()
const timeFilter = {
startTime: parseInt(now / 1000 - 3600),
endTime: parseInt(now / 1000)
}
// Total
this.loadingApp = true
this.loadingDomain = true
@@ -695,61 +777,37 @@ export default {
this.loadingDomainActive = true
this.loadingIpActive = true
get(api.entityTotal, { entityType: 'app' }).then(response => {
get(api.entity.entityList.entityActive).then(response => {
if (response.code === 200) {
this.entityAppTotal = response.data.result
}
this.loadingApp = false
})
get(api.entityTotal, { entityType: 'domain' }).then(response => {
if (response.code === 200) {
this.entityDomainTotal = response.data.result
this.entityDomainTotal = response.data.domainCount
this.entityIpTotal = response.data.ipCount
this.entityAppTotal = response.data.appCount
}
this.loadingDomain = false
})
get(api.entityTotal, { entityType: 'ip' }).then(response => {
if (response.code === 200) {
this.entityIpTotal = response.data.result
}
this.loadingIp = false
this.loadingApp = false
})
// New
get(api.entityNew, { entityType: 'app', ...timeFilter }).then(response => {
get(api.entity.entityList.entityNew).then(response => {
if (response.code === 200) {
this.entityAppNew = response.data.result
}
this.loadingAppNew = false
})
get(api.entityNew, { entityType: 'domain', ...timeFilter }).then(response => {
if (response.code === 200) {
this.entityDomainNew = response.data.result
this.entityDomainNew = response.data.domainCount
this.entityIpNew = response.data.ipCount
this.entityAppNew = response.data.appCount
}
this.loadingDomainNew = false
})
get(api.entityNew, { entityType: 'ip', ...timeFilter }).then(response => {
if (response.code === 200) {
this.entityIpNew = response.data.result
}
this.loadingIpNew = false
this.loadingAppNew = false
})
// Active
get(api.entityActive, { entityType: 'app', ...timeFilter }).then(response => {
get(api.entity.entityList.entityActive).then(response => {
if (response.code === 200) {
this.entityAppActive = response.data.result
}
this.loadingAppActive = false
})
get(api.entityActive, { entityType: 'domain', ...timeFilter }).then(response => {
if (response.code === 200) {
this.entityDomainActive = response.data.result
this.entityDomainActive = response.data.domainCount
this.entityIpActive = response.data.ipCount
this.entityAppActive = response.data.appCount
}
this.loadingDomainActive = false
})
get(api.entityActive, { entityType: 'ip', ...timeFilter }).then(response => {
if (response.code === 200) {
this.entityIpActive = response.data.result
}
this.loadingIpActive = false
this.loadingAppActive = false
})
},
cleanFilterData (index) {

View File

@@ -1,150 +1,76 @@
<template >
<template>
<div class="entity-filter-case">
<div class="filter-case__header">{{$t('entities.filter')}}</div>
<div
class="entity-filter"
v-for="(filters, index) in filterData"
:key="index"
>
<div class="filter__header">{{filters.title}}</div>
<div class="filter__body">
<div class="filter-case__header">{{ $t('entities.filter1') }}</div>
<div class="filter__row" v-for="(item, i) in filters.data" :key="i">
<el-popover popper-class="filter__row-popover" placement="right-start" :width="440" v-model:visible="item.showTopTen">
<template #reference>
<div class="filter__row-popover" @click="showTopDialog(i, item, filters)">
<div class="row__label">
<i :class="item.icon"></i>
<span>{{item.label}}</span>
</div>
<div class="row__value">
<loading :loading="loadingLeft" size="small"></loading>
<span>{{item.value}}</span>
</div>
</div>
</template>
<entity-top
ref="entityTopTenPop"
:loading="loading"
:popover-data="popoverData"
:item-data="itemData"
:total-count="totalCount"
:top-column="item.topColumn"
@filter="filter"
></entity-top>
</el-popover>
<div class="entity-filter" v-for="(item, index) in filterData" :key="index">
<div class="filter__header">
<i :class="item.icon"></i>
{{ item.title }}
</div>
<div class="filter__body" style="position: relative">
<loading :loading="loadingLeft" style="top: -5px;"></loading>
<div class="filter__body-item" v-for="(data, i) in item.data" :key="i" @click="filter(data.label, data)">
<div class="filter__body-item-left">
<!-- 当前无更好方案匹配国旗后续解决-->
<!-- <div v-if="data.flag">-->
<!-- <img :src="require(`../../../public/images/flag/${data.flag}.svg`)" class="filter-country-flag"/>-->
<!-- </div>-->
<div class="filter__body-item-left-index">{{ i+1 }}</div>
<div class="filter__body-item-left-label">
<el-tooltip :content="data.label" placement="top" effect="light" :disabled="disabledLabel">
<span @mouseenter="handleMouse(`filter${index}${i}`)" :id="`filter${index}${i}`">{{ data.label }}</span>
</el-tooltip>
</div>
</div>
<div class="filter__body-item-right">{{ data.value }}</div>
</div>
<div class="filter-hr"></div>
</div>
</div>
</div>
</template>
<script>
import EntityTop from '@/views/entityExplorer/EntityTop'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import Loading from '@/components/common/Loading'
import { getSecond } from '@/utils/date-util'
export default {
name: 'EntityFilter',
components: {
Loading,
EntityTop
},
components: { Loading },
props: {
filterData: Array,
q: String,
timeFilter: Object,
loadingLeft: Boolean
filterData: {
type: Object
},
loadingLeft: {
type: Boolean
}
},
data () {
return {
topList: 'list',
topData: [],
entityTopTenData: [],
currentColumn: {},
totalCount: 0,
loading: false,
popoverData: [],
itemData: {}
}
},
watch: {
currentColumn (n, o) {
if (n.column === 'dnsServerOrgCount') {
this.totalCount = this.filterData[3].orgTotalCount
} else if (n.column === 'dnsServerSoftwareCount') {
this.totalCount = this.filterData[3].softwareTotalCount
} else if (n.column === 'dnsServerOsCount') {
this.totalCount = this.filterData[3].osTotalCount
} else if (n.column === 'categoryDistinctCount' && n.type === 'app') {
this.totalCount = this.filterData[1].totalCount
} else {
let count = 0
this.filterData.forEach(f => {
const filter = f.data.some(d => d.column === n.column)
if (filter) {
count = f.totalCount
}
})
this.totalCount = count
}
disabledLabel: true
}
},
methods: {
showTopDialog (i, item, filter) {
if (this.currentColumn.column === item.column && item.showTopTen) {
item.showTopTen = false
return
/**
* 判断文字是否溢出超出则鼠标移入tooltip显示否则鼠标移入不显示
* @param id
*/
handleMouse (id) {
const dom = document.getElementById(id)
if (dom) {
const width = document.getElementById(id).offsetWidth
this.disabledLabel = width < 180
} else {
this.disabledLabel = true
}
this.filterData.forEach(f => {
f.data.forEach(ff => {
ff.showTopTen = false
})
})
item.showTopTen = true
this.currentColumn = {
column: item.column,
type: filter.type
}
const queryParams = {
q: this.q,
entityType: filter.type,
column: item.topColumn,
top: 10,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
this.loading = true
this.popoverData = []
this.itemData = {}
get(api.filterTop, queryParams).then(response => {
if (response.code === 200) {
if (this.currentColumn.column === item.column) {
if (filter.type === 'dns') {
this.popoverData = response.data.result.filter(f => {
return f.count > 0
})
} else {
this.popoverData = response.data.result
}
this.itemData = item
}
} else {
this.popoverData = []
this.itemData = item
}
this.loading = false
}).catch(e => {
this.popoverData = []
this.itemData = item
this.loading = false
})
},
filter (name, topData) {
this.showTopDialog('', topData)
this.$emit('filter', name, topData)
filter (name, data) {
this.$emit('filter', name, data)
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -9,75 +9,76 @@
<div class="cn-entity__case">
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
<div class="cn-entity__row">
<div class="cn-entity__header">
{{ entityData.ipAddr || entityData.domainName || entityData.appName || 'Unknown' }}
<!-- <div class="cn-entity__header" style="display: flex">-->
<!-- <span class="cn-entity__header-title">{{ entityData.ipAddr || entityData.domainName || entityData.appName || 'Unknown' }}</span>-->
<!-- <span class="entity-detail" style="display: flex">-->
<!-- <span style="width: 62px;" class="entity-tag entity-tag&#45;&#45;small entity-tag&#45;&#45;level-two-positive margin-r-6">信息技术</span>-->
<!-- <span style="width: 50px;" class="entity-tag entity-tag&#45;&#45;small entity-tag&#45;&#45;level-two-normal margin-r-6">互联网</span>-->
<!-- </span>-->
<!--标签-->
<div class="cn-entity__header" style="display: flex;align-items: center">
<span class="cn-entity__header-title">{{ entityData.entityValue || 'Unknown' }}</span>
<span class="entity-detail" style="display: flex;margin-left: 6px;margin-top: 1px;">
<span v-for="(item, index) in levelTwoTags" :key="index" class="entity-tag entity-tag--small margin-r-10" :class="`entity-tag--level-two-${item.type}`">
{{ item.value }}
</span>
</span>
</div>
<div class="cn-entity__body">
<div class="body__basic-info">
<div class="basic-info">
<template v-if="entityData.entityType === 'ip'">
<div class="basic-info__item">
<i class="cn-icon cn-icon-country"></i>
<span>{{ $t('overall.country') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.ipLocationCountry || '-' }}</span>
<span class="row-item-label">{{ $t('overall.country') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.location ? entityData.location.country : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-position"></i>
<span>{{ $t('overall.region') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ ipLocationRegion(entityData) }}</span>
<span class="row-item-label">{{ $t('overall.region') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.location ? ipLocationRegion(entityData.location) : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-cloud"></i>
<span>{{ $t('entities.asn') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.ipAsn || '-' }}</span>
<span class="row-item-label">{{ $t('entities.asn') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.asn ? entityData.asn.asn : '-' }}</span>
</div>
</template>
<template v-else-if="entityData.entityType === 'domain'">
<div class="basic-info__item">
<i class="cn-icon cn-icon-category"></i>
<span>{{ $t('entities.domainDetail.categoryGroup') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.domainCategoryGroup || '-' }}</span>
<i class="cn-icon cn-icon-sub-category"></i>
<span class="row-item-label">{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? entityData.category.name : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-sub-category"></i>
<span>{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.domainCategory || '-' }}</span>
<i class="cn-icon cn-icon-category"></i>
<span class="row-item-label">{{ $t('entities.subcategory') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? entityData.category.group : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-credit"></i>
<span>{{ $t('entities.reputationLevel') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.domainReputationScore || '-' }}</span>
<span class="row-item-label">{{ $t('entities.reputationLevel') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? entityData.category.reputationLevel : '-' }}</span>
</div>
</template>
<template v-else-if="entityData.entityType === 'app'">
<div class="basic-info__item">
<i class="cn-icon cn-icon-id"></i>
<span>{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.appCategory || '-' }}</span>
<span class="row-item-label">{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? entityData.category.appCategory : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-category"></i>
<span>{{ $t('entities.subcategory') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.appSubcategory || '-' }}</span>
<span class="row-item-label">{{ $t('entities.subcategory') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? entityData.category.appSubcategory : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-sub-category"></i>
<span>{{ $t('entities.risk') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ appRisk(entityData.appRisk) || '-' }}</span>
<span class="row-item-label">{{ $t('entities.risk') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">{{ entityData.category ? appRisk(entityData.category.appRisk) : '-' }}</span>
</div>
</template>
<!-- 通用字段 -->
<div class="basic-info__item">
<div class="item__box">
<i class="cn-icon cn-icon-rise"></i>
<span>{{ $t('entities.sentThroughput') }}&nbsp;:&nbsp;&nbsp;</span>
<span>
<span class="row-item-label">{{ $t('entities.sentThroughput') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">
{{
entityData.bytesSentRate ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'
}}
@@ -107,8 +108,8 @@
<div class="basic-info__item">
<div class="item__box">
<i class="cn-icon cn-icon-fall"></i>
<span>{{ $t('entities.receivedThroughput') }}&nbsp;:&nbsp;&nbsp;</span>
<span>
<span class="row-item-label">{{ $t('entities.receivedThroughput') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value">
{{
entityData.bytesReceivedRate ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-'
}}
@@ -133,23 +134,7 @@
</div>
</div>
</div>
<!--新版实体列表改版去除这一段-->
<div class="basic-info__item">
<i class="cn-icon cn-icon-entity-alert"></i>
<span>{{ $t('entities.recentAlert') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.performanceCount }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-safe"></i>
<span>{{ $t('entities.recentSecurity') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ entityData.securityCount }}</span>
</div>
<!--新版实体列表改版去除这一段-->
</div>
<!-- <div class="show-detail" @click="showDetail">-->
<!-- {{ $t('overall.detail') }}>-->
<!-- </div>-->
<!-- 新版实体列表改版后续记得解开-->
</div>
</div>
</div>
@@ -172,6 +157,10 @@ import DetailOverview from '@/views/entityExplorer/entityList/detailOverview/Det
import entityListMixin from './entityListMixin'
import relatedServer from '@/mixins/relatedServer'
import Loading from '@/components/common/Loading'
import axios from 'axios'
import { api } from '@/utils/api'
import { entityDetailTags, psiphon3IpType } from '@/utils/constants'
import _ from 'lodash'
export default {
name: 'Row',
@@ -188,35 +177,109 @@ export default {
data () {
return {
loading: false,
isCollapse: true // 是否是折叠状态
isCollapse: true, // 是否是折叠状态
levelTwoTags: []
}
},
computed: {
ipLocationRegion () {
return function (entityData) {
const hasProvinceAndCity =
entityData.ipLocationProvince &&
entityData.ipLocationCity &&
entityData.ipLocationProvince !== 'null' &&
entityData.ipLocationCity !== 'null'
entityData.province &&
entityData.city &&
entityData.province !== 'null' &&
entityData.city !== 'null'
const hasProvince =
entityData.ipLocationProvince &&
entityData.ipLocationProvince !== 'null'
entityData.province &&
entityData.province !== 'null'
const hasCity =
entityData.ipLocationCity && entityData.ipLocationCity !== 'null'
entityData.city && entityData.city !== 'null'
if (hasProvinceAndCity) {
return `${entityData.ipLocationProvince}, ${entityData.ipLocationCity}`
return `${entityData.province}, ${entityData.city}`
} else if (hasProvince) {
return entityData.ipLocationProvince
return entityData.province
} else if (hasCity) {
return entityData.ipLocationCity
return entityData.city
} else {
return '-'
}
}
}
},
mounted () {
this.initData()
this.initTagsData()
},
methods: {
initData () {
let url = ''
switch (this.entity.entityType) {
case ('domain'): {
url = api.entity.entityList.domainBasicInfo
break
}
case ('ip'): {
url = api.entity.entityList.ipBasicInfo
break
}
case ('app'): {
url = api.entity.entityList.appBasicInfo
break
}
}
axios.get(`${url}?resource=${this.entity.entityValue}`).then(response => {
this.$nextTick(() => {
this.entityData = { ...response.data.data, ...this.entity }
})
})
},
initTagsData () {
let url = ''
switch (this.entity.entityType) {
case ('domain'): {
url = api.entity.entityList.domainTags
break
}
case ('ip'): {
url = api.entity.entityList.ipTags
break
}
case ('app'): {
url = api.entity.entityList.appTags
break
}
}
axios.get(`${url}?resource=${this.entity.entityValue}`).then(responese => {
const res = responese.data
if (res.code === 200) {
Object.keys(res.data).forEach(k => {
if (k !== 'userDefinedTags' && res.data[k]) {
Object.keys(res.data[k]).forEach(k2 => {
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
if (find) {
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(k, k2, res.data[k][k2]), type: find.type })
}
})
}
})
if (_.isArray(res.data.userDefinedTags)) {
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, type: 'normal' })))
}
this.hideTagArea = _.isEmpty(this.levelTwoTags)
}
})
},
tagValueHandler (k, k2, value) {
if (k === 'psiphon3Ip') {
if (k2 === 'type') {
const find = psiphon3IpType.find(t => t.value === value)
if (find) {
return find.name
}
}
}
return value
},
/* 切换折叠状态 */
switchCollapse () {
this.isCollapse = !this.isCollapse

View File

@@ -4,23 +4,23 @@
<div class="overview__content">
<div class="overview__row">
<div class="row__label row__label--width130">APP ID</div>
<div class="row__content">{{entity.appId|| '-'}}</div>
<div class="row__content">{{entity.category.appId || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
<div class="row__content">{{entity.appCategory|| '-'}}</div>
<div class="row__content">{{entity.category.appCategory || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.subcategory')}}</div>
<div class="row__content">{{entity.appSubcategory || '-'}}</div>
<div class="row__content">{{entity.category.appSubcategory || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.riskLevel')}}</div>
<div class="row__content">{{appRisk(entity.appRisk) || '-'}}</div>
<div class="row__content">{{appRisk(parseInt(entity.category.appRisk)) || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
<div class="row__content">{{entity.appDescription || '-'}}</div>
<div class="row__content">{{entity.category.appDescription || '-'}}</div>
</div>
</div>
</div>
@@ -43,103 +43,78 @@
<div class="row__charts-msg">{{$t('overall.sent')}}{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailSend${entity.appName}`" ></div>
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`" ></div>
</div>
</div>
<div class="row__content">
<div class="row__content row__content-accept">
<div class="row__charts-msg">{{$t('overall.received')}}{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailReceived${entity.appName}`" ></div>
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`" ></div>
</div>
</div>
</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
<loading :loading="loadingNetworkQuality" size="small" inner-style="left: 1rem;"></loading>
<div class="entity-score" v-if="!loadingNetworkQuality">
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
Score:{{score}}
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.relationship')}}</div>
<div class="overview__content domain__content">
<div class="overview__tags domain__tags" ref="relationship">
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataOne.length}}</span>
<span class="tag__desc">{{$t('entities.relatedDomains')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<span class="tag__desc">{{item.domain}}</span>
</div>
<div class="overview__tags domain__tags" ref="relationship"></div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.tab.relatedIp')}}</div>
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content overview__row-related">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
<span v-if="item.domain" :title="item.domain">{{item.domain}}</span>
</div>
</div>
<div v-if="relationshipShowOne">
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataTwo.length}}</span>
<span class="tag__desc">{{$t('entities.relatedServerIp')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<span class="tag__desc">{{item.ip}}</span>
</div>
</div>
<div class="overview__row overview__row-related">
<div class="row__label row__label--width130">{{$t('entities.tab.relatedIp')}}</div>
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
<span v-if="item.ip" :title="item.ip">{{item.ip}}</span>
</div>
</div>
<div v-if="relationshipShowTwo">
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
<div class="overview__content overview__content-loading-net">
<loading :loading="loadingNetworkQuality" size="small"></loading>
<div class="overview__row overview__row--single-value">
<chart-single-value
v-for="(chartInfo, i) in singleValues.chartInfos"
:chart-info="chartInfo"
:chart-data="singleValues.chartDatas[i]"
:key="i"
class="cn-chart__single-value--detail-overview"
></chart-single-value>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('entities.accessLink')}}</div>
<div class="overview__content">
<div class="overview__tags">
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingOut" size="small"></loading>
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}},</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingIn" size="small"></loading>
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}},</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.alert')}}</div>
<div class="overview__content overview__content-loading">
@@ -148,20 +123,17 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="performanceData.length > 0">
<div class="row__label">{{$t('entities.recentAlert')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
<div class="row__content">{{entityData.performanceNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width200">
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
<div>{{performance.eventType}}</div>
</div>
<div class="row__content-loading" style="position: relative;" >
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
<div class="row__charts" :id="`entityPerformanceChart${entity.appName}_${index}`"></div>
<div class="row__content-loading" style="position: relative;">
<div class="performance-event-remark">{{performance.eventType}}</div>
</div>
<div class="row__desc"></div>
</div>
<div class="overview__row overview__row--small-font" v-if="performanceData && performanceData.length > 5">
@@ -177,15 +149,26 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="securityData.length > 0">
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
<div class="row__content">{{entityData.securityNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
<div class="row__label row__label--width160">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width200">
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
<div>{{security.securityType}}</div>
</div>
<div class="cn-detection__header">
<i class="cn-icon cn-icon-attacker"></i>
<span>{{ security.offenderIp }}</span>
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
<span class="line">-------</span>
<span class="circle"></span>
<i class="cn-icon cn-icon-attacked"></i>
<span>{{ security.victimIp }}</span>
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
</div>
<div class="row__desc"></div>
</div>
<div class="overview__row overview__row--small-font" v-if="securityData && securityData.length > 5">
@@ -213,34 +196,38 @@ import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import { get } from '@/utils/http'
import relatedServer from '@/mixins/relatedServer'
import { getSecond, getMillisecond } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { ref } from 'vue'
export default {
name: 'App',
mixins: [entityDetailMixin, relatedServer],
components: {
Chart,
Loading,
ChartSingleValue
Loading
},
data () {
return {
// entityData: {}
entityType: 'app',
trafficUrl: api.entityAppDetailTraffic,
// trafficUrl: api.entityAppDetailTraffic,
trafficUrl: api.entity.entityList.appThroughput,
relationUrl: api.entityAppDetailRelation,
networkQuantityUrl: api.entityAppDetailNetworkQuantity,
// networkQuantityUrl: api.entityAppDetailNetworkQuantity,
networkQuantityUrl: api.entity.entityList.appPerformance,
linkInUrl: api.entityAppDetailLinkIn,
linkOutUrl: api.entityAppDetailLinkOut,
performanceUrl: api.entityAppDetailPerformance,
securityUrl: api.entityAppDetailSecurity,
trafficUrlMap: api.entityAppDetailTrafficMap,
relatedServerDomainUrl: api.entityAppRelatedServerDomain,
relatedServerIpUrl: api.entityAppRelatedServerIp,
// performanceUrl: api.entityAppDetailPerformance,
performanceUrl: api.entity.entityList.appEventPerformance,
securityUrl: api.entity.entityList.appSecurity,
// securityUrl: api.entityAppDetailSecurity,
// trafficUrlMap: api.entityAppDetailTrafficMap,
trafficUrlMap: api.entity.entityList.appTrafficMap,
relatedServerDomainUrl: api.entity.entityList.appRelatedDomain,
relatedServerIpUrl: api.entity.entityList.appRelatedIp,
chartData: null,
listMode: 'list',
singleValues: {
@@ -296,34 +283,34 @@ export default {
i18n: 'entities.pktRetransPercent'
}
],
chartDatas: [null, null, null, null, null],
loadingTraffic: false,
loadingRelationshipOne: false,
loadingRelationshipTwo: false,
loadingNetworkQuality: false,
loadingOut: false,
loadingIn: false,
loadingAlert: false,
loadingSecurityEvents: false,
loadingMap: false
}
chartDatas: [null, null, null, null, null]
},
loadingTraffic: false,
loadingRelationshipOne: false,
loadingRelationshipTwo: false,
loadingNetworkQuality: false,
loadingOut: false,
loadingIn: false,
loadingAlert: false,
loadingSecurityEvents: false,
loadingMap: false
}
},
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams () {
const queryParams = {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
appName: this.entity.appName
resource: this.entity.entityValue,
appName: this.entity.entityValue
}
return queryParams
},
getPerformanceQueryParams () {
const queryParams = {
appName: this.entity.appName
return {
appName: this.entity.entityValue
}
return queryParams
},
handleRelationData (result) {
this.entityData.domainCount = result.domainCount
@@ -353,6 +340,7 @@ export default {
})
},
setup (props) {
const entityData = ref({ ...props.entity })
return {
chart: {
params: {
@@ -366,7 +354,8 @@ export default {
entityCopy: {
..._.cloneDeep(props.entity)
},
unitConvert
unitConvert,
entityData
}
}
}

View File

@@ -4,36 +4,32 @@
<div class="overview__content">
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
<div class="row__content">{{entityData.domainCategory || '-'}}</div>
<div class="row__content">{{entityData.category ? entityData.category.categoryName : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.domainDetail.categoryGroup')}}</div>
<div class="row__content">{{entityData.domainCategoryGroup || '-'}}</div>
<div class="row__content">{{entityData.category ? entityData.category.categoryGroup : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.reputationLevel')}}</div>
<div class="row__content">{{entityData.domainReputationScore || '-'}}</div>
<div class="row__content">{{entityData.category ? entityData.category.reputationLevel : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.registration')}}</div>
<div class="row__content">{{entityData.domainWhoisAddress || '-'}}</div>
<div class="row__content">{{entityData.whois ? entityData.whois.registrantCountry : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.org')}}</div>
<div class="row__content">{{entityData.domainWhoisOrg || '-'}}</div>
<div class="row__content">{{entityData.whois ? entityData.whois.registrantOrg : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.icpCompanyName')}}</div>
<div class="row__content">{{entityData.domainIcpCompanyName || '-'}}</div>
<div class="row__content">{{entityData.icp ? entityData.icp.icpCompanyName : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.icpLicense')}}</div>
<div class="row__content">{{entityData.domainIcpSiteLicense || '-'}}</div>
<div class="row__content">{{entityData.icp ? entityData.icp.icpSiteLicense : '-'}}</div>
</div>
<!-- <div class="overview__row">
<div class="row__label row__label&#45;&#45;width130">{{$t('overall.remark')}}</div>
<div class="row__content">{{entityData.domainDescription || '-'}}</div>
</div>-->
</div>
</div>
<div class="overview-item">
@@ -55,103 +51,78 @@
<div class="row__charts-msg">{{$t('overall.sent')}}{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailSend${entity.domainName}`" >{</div>
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`" >{</div>
</div>
</div>
<div class="row__content">
<div class="row__content row__content-accept">
<div class="row__charts-msg">{{$t('overall.received')}}{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailReceived${entity.domainName}`" ></div>
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`" ></div>
</div>
</div>
</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
<loading :loading="loadingNetworkQuality" size="small" inner-style="left: 1rem;"></loading>
<div class="entity-score" v-if="!loadingNetworkQuality">
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
Score:{{score}}
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.relationship')}}</div>
<div class="overview__content domain__content">
<div class="overview__tags domain__tags" ref="relationship">
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataOne.length}}</span>
<span class="tag__desc">{{$t('entities.relatedApp')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<span class="tag__desc">{{item.appName}}</span>
</div>
<div class="overview__tags domain__tags" ref="relationship"></div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.tab.relatedApp')}}</div>
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content overview__row-related">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
<span v-if="item.appName" :title="item.appName">{{item.appName}}</span>
</div>
</div>
<div v-if="relationshipShowOne">
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataTwo.length}}</span>
<span class="tag__desc">{{$t('entities.relatedServerIp')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<span class="tag__desc">{{item.ip}}</span>
</div>
</div>
<div class="overview__row overview__row-related">
<div class="row__label row__label--width130">{{$t('entities.tab.relatedIp')}}</div>
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
<span v-if="item.ip" :title="item.ip">{{item.ip}}</span>
</div>
</div>
<div v-if="relationshipShowTwo">
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
<div class="overview__content overview__content-loading-net">
<loading :loading="loadingNetworkQuality" size="small"></loading>
<div class="overview__row overview__row--single-value">
<chart-single-value
v-for="(chartInfo, i) in singleValues.chartInfos"
:chart-info="chartInfo"
:chart-data="singleValues.chartDatas[i]"
:key="i"
class="cn-chart__single-value--detail-overview"
></chart-single-value>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('entities.accessLink')}}</div>
<div class="overview__content">
<div class="overview__tags">
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingOut" size="small"></loading>
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}},</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingIn" size="small"></loading>
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}},</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.alert')}}</div>
<div class="overview__content overview__content-loading">
@@ -160,18 +131,16 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="performanceData.length > 0">
<div class="row__label">{{$t('entities.recentAlert')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
<div class="row__content">{{entityData.performanceNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width200">
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
<div>{{performance.eventType}}</div>
</div>
<div class="row__content-loading" style="position: relative;" >
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
<div class="row__charts" :id="`entityPerformanceChart${entity.domainName}_${index}`"></div>
<div class="row__content-loading" style="position: relative;">
<div class="performance-event-remark">{{performance.eventType}}</div>
</div>
<div class="row__desc"></div>
</div>
@@ -188,14 +157,24 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="securityData.length > 0">
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
<div class="row__content">{{entityData.securityNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(security, i) in entityData.securityList" :key="i">
<div class="row__label row__label--width160">{{dateFormatByAppearance(getMillisecond(security.startTime)) || '-'}}</div>
<div class="row__content row__content--width200">
<div class="row__label row__label--width130">{{dateFormatByAppearance(getMillisecond(security.startTime)) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
<div>{{security.securityType}}</div>
</div>
<div class="cn-detection__header">
<i class="cn-icon cn-icon-attacker"></i>
<span>{{ security.offenderIp }}</span>
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
<span class="line">-------</span>
<span class="circle"></span>
<i class="cn-icon cn-icon-attacked"></i>
<span>{{ security.victimIp }}</span>
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
</div>
<div class="row__desc"></div>
</div>
@@ -218,7 +197,6 @@
</template>
<script>
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import { api } from '@/utils/api'
import entityDetailMixin from './entityDetailMixin'
import { unitTypes } from '@/utils/constants'
@@ -227,13 +205,13 @@ import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import { get } from '@/utils/http'
import relatedServer from '@/mixins/relatedServer'
import { getSecond, getMillisecond } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { ref } from 'vue'
export default {
name: 'Domain',
components: {
ChartSingleValue,
Loading,
Chart
},
@@ -242,16 +220,21 @@ export default {
return {
// entityData: {},
entityType: 'domain',
trafficUrl: api.entityDomainDetailTraffic,
// trafficUrl: api.entityDomainDetailTraffic,
trafficUrl: api.entity.entityList.domainThroughput,
relationUrl: api.entityDomainDetailRelation,
networkQuantityUrl: api.entityDomainDetailNetworkQuantity,
networkQuantityUrl: api.entity.entityList.domainPerformance,
// networkQuantityUrl: api.entityDomainDetailNetworkQuantity,
linkInUrl: api.entityDomainDetailLinkIn,
linkOutUrl: api.entityDomainDetailLinkOut,
performanceUrl: api.entityDomainDetailPerformance,
securityUrl: api.entityDomainDetailSecurity,
trafficUrlMap: api.entityDomainDetailTrafficMap,
relatedServerIpUrl: api.entityDomainRelatedServerIp,
relatedServerAppUrl: api.entityDomainRelatedServerApp,
// performanceUrl: api.entityDomainDetailPerformance,
performanceUrl: api.entity.entityList.domainEventPerformance,
// securityUrl: api.entityDomainDetailSecurity,
securityUrl: api.entity.entityList.domainSecurity,
// trafficUrlMap: api.entityDomainDetailTrafficMap,
trafficUrlMap: api.entity.entityList.domainTrafficMap,
relatedServerIpUrl: api.entity.entityList.domainRelatedIp,
relatedServerAppUrl: api.entity.entityList.domainRelatedApp,
basicProperties: api.entityDomainDetailBasic,
chartData: null,
listMode: 'list',
@@ -308,34 +291,34 @@ export default {
i18n: 'entities.pktRetransPercent'
}
],
chartDatas: [null, null, null, null, null],
loadingTraffic: false,
loadingRelationshipOne: false,
loadingRelationshipTwo: false,
loadingNetworkQuality: false,
loadingOut: false,
loadingIn: false,
loadingAlert: false,
loadingSecurityEvents: false,
loadingMap: false
}
chartDatas: [null, null, null, null, null]
},
loadingTraffic: false,
loadingRelationshipOne: false,
loadingRelationshipTwo: false,
loadingNetworkQuality: false,
loadingOut: false,
loadingIn: false,
loadingAlert: false,
loadingSecurityEvents: false,
loadingMap: false
}
},
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams () {
const queryParams = {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
domain: this.entity.domainName
resource: this.entity.entityValue,
domain: this.entity.entityValue
}
return queryParams
},
getPerformanceQueryParams () {
const queryParams = {
domain: this.entity.domainName
return {
domain: this.entity.entityValue
}
return queryParams
},
handleRelationData (result) {
this.entityData.appCount = result.appCount
@@ -383,9 +366,10 @@ export default {
})
},
setup (props) {
const entityData = ref({ ...props.entity })
const entityCopy = {
..._.cloneDeep(props.entity),
domain: props.entity.domainName
domain: props.entity.entityValue
}
return {
chart: {
@@ -398,7 +382,8 @@ export default {
},
entityCopy,
unitTypes,
unitConvert
unitConvert,
entityData
}
}
}

View File

@@ -4,11 +4,15 @@
<div class="overview__content">
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('overall.location')}}</div>
<div class="row__content">{{ipLocationRegion(entity)}}</div>
<div class="row__content">{{ipLocationRegion(entity.location)}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">ASN</div>
<div class="row__content">{{entity.ipAsn || '-'}}</div>
<div class="row__content">{{entity.asn ? entity.asn.asn : '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.openPort')}}</div>
<div class="row__content">{{ openPort }}</div>
</div>
</div>
</div>
@@ -44,7 +48,7 @@
<!-- 曲线-->
<div class="row__content-loading">
<loading :loading="!loadingDns && loading" size="small"></loading>
<div class="row__charts" :id="`entityDnsServerInfo${entity.ipAddr}`"></div>
<div class="row__charts" :id="`entityDnsServerInfo${entity.entityValue}`"></div>
</div>
</div>
</div>
@@ -70,103 +74,77 @@
<div class="row__charts-msg">{{$t('overall.sent')}}{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailSend${entity.ipAddr}`"></div>
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`"></div>
</div>
</div>
<div class="row__content">
<div class="row__content row__content-accept">
<div class="row__charts-msg">{{$t('overall.received')}}{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
<!-- 曲线-->
<div class="row__content-loading">
<div class="row__charts" :id="`entityDetailReceived${entity.ipAddr}`"></div>
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`"></div>
</div>
</div>
</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
<loading :loading="loadingNetworkQuality" size="small" inner-style="left: 1rem;"></loading>
<div class="entity-score" v-if="!loadingNetworkQuality">
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
Score:{{score}}
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.relationship')}}</div>
<div class="overview__content domain__content">
<div class="overview__tags domain__tags" ref="relationship">
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataOne.length}}</span>
<span class="tag__desc">{{$t('entities.relatedDomains')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<span class="tag__desc">{{item.domain}}</span>
</div>
<div class="overview__tags domain__tags" ref="relationship"></div>
<div class="overview__row overview__row-related">
<div class="row__label row__label--width130">{{$t('entities.tab.relatedApp')}}</div>
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
<span v-if="item.domain" :title="item.domain">{{item.domain}}</span>
</div>
</div>
<div v-if="relationshipShowOne">
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div class="popover-content" v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
<div class="overview__domain-tabs overview__domain-tabs-loading">
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="overview__domain-tab">
<div class="overview__tag domain__tag">
<span class="tag__value">{{relationshipDataTwo.length}}</span>
<span class="tag__desc">{{$t('entities.relatedApp')}}</span>
</div>
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<span class="tag__desc">{{item.appName}}</span>
</div>
</div>
<div class="overview__row overview__row-related">
<div class="row__label row__label--width130">{{$t('entities.relatedDomain')}}</div>
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
<div class="row__content">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div class="overview__domain-btn">
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
<span v-if="item.appName" :title="item.appName">{{item.appName}}</span>
</div>
</div>
<div v-if="relationshipShowTwo">
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
<template #reference>
<div class="data-item show-more-related">...</div>
</template>
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
</el-popover>
</div>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
<div class="overview__content overview__content-loading-net">
<loading :loading="loadingNetworkQuality" size="small"></loading>
<div class="overview__row overview__row--single-value">
<chart-single-value
v-for="(chartInfo, i) in singleValues.chartInfos"
:chart-info="chartInfo"
:chart-data="singleValues.chartDatas[i]"
:key="i"
class="cn-chart__single-value--detail-overview"
></chart-single-value>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('entities.accessLink')}}</div>
<div class="overview__content">
<div class="overview__tags">
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingOut" size="small"></loading>
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}},&nbsp;</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
<div class="overview__tag overview__tag-loading">
<loading :loading="loadingIn" size="small"></loading>
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}},&nbsp;</span>
<span class="tag__desc">{{$t('entities.percentage')}}</span>
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
</div>
</div>
</div>
</div>
<div class="overview-item">
<div class="overview__title">{{$t('overall.alert')}}</div>
<div class="overview__content overview__content-loading">
@@ -175,18 +153,16 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="performanceData.length > 0">
<div class="row__label">{{$t('entities.recentAlert')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
<div class="row__content">{{entityData.performanceNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content">
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
<div>{{performance.eventType}}</div>
</div>
<div class="row__content-loading" style="position: relative; padding-left: 10px;">
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
<div class="row__charts" :id="`entityPerformanceChart${entity.ipAddr}_${index}`"></div>
<div class="row__content-loading" style="position: relative;">
<div class="performance-event-remark">{{performance.eventType}}</div>
</div>
<div class="row__desc"></div>
</div>
@@ -203,15 +179,26 @@
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
</div>
<div class="overview__row" v-if="securityData.length > 0">
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
<div class="row__content">{{entityData.securityNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
<div class="row__label row__label--width160">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width200">
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
<div>{{security.securityType}}</div>
</div>
<div class="cn-detection__header" >
<i class="cn-icon cn-icon-attacker"></i>
<span>{{ security.offenderIp }}</span>
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
<span class="line">-------</span>
<span class="circle"></span>
<i class="cn-icon cn-icon-attacked"></i>
<span>{{ security.victimIp }}</span>
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
</div>
<div class="row__desc"></div>
</div>
<div class="overview__row overview__row--small-font" v-if="securityData && securityData.length > 5">
@@ -234,7 +221,6 @@
<script>
import entityDetailMixin from './entityDetailMixin'
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import { api } from '@/utils/api'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
@@ -242,30 +228,35 @@ import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import { get } from '@/utils/http'
import relatedServer from '@/mixins/relatedServer'
import { getSecond, getMillisecond } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import axios from 'axios'
export default {
name: 'Ip',
mixins: [entityDetailMixin, relatedServer],
components: {
Loading,
Chart,
ChartSingleValue
Chart
},
data () {
return {
entityType: 'ip',
trafficUrl: api.entityIpDetailTraffic,
trafficUrlMap: api.entityIpDetailTrafficMap,
// trafficUrl: api.entityIpDetailTraffic,
trafficUrl: api.entity.entityList.ipThroughput,
// trafficUrlMap: api.entityIpDetailTrafficMap,
trafficUrlMap: api.entity.entityList.ipTrafficMap,
relationUrl: api.entityIpDetailRelation,
networkQuantityUrl: api.entityIpDetailNetworkQuantity,
// networkQuantityUrl: api.entityIpDetailNetworkQuantity,
networkQuantityUrl: api.entity.entityList.ipPerformance,
linkInUrl: api.entityIpDetailLinkIn,
linkOutUrl: api.entityIpDetailLinkOut,
performanceUrl: api.entityIpDetailPerformance,
securityUrl: api.entityIpDetailSecurity,
relatedServerDomainUrl: api.entityIpRelatedServerDomain,
relatedServerAppUrl: api.entityIpRelatedServerApp,
performanceUrl: api.entity.entityList.ipEventPerformance,
// performanceUrl: api.entityIpDetailPerformance,
// securityUrl: api.entityIpDetailSecurity,
securityUrl: api.entity.entityList.ipSecurity,
relatedServerDomainUrl: api.entity.entityList.ipRelatedDomain,
relatedServerAppUrl: api.entity.entityList.ipRelatedApp,
entityDetectionsIpUrl: api.entityDetectionsIp,
entityDetectionsIpQueryRateUrl: api.entityDetectionsIpQueryRate,
listMode: 'list',
@@ -336,21 +327,22 @@ export default {
loadingIn: false,
loadingAlert: false,
loadingSecurityEvents: false,
loadingMap: false
loadingMap: false,
openPort: '-'
}
},
computed: {
ipLocationRegion () {
return function (entityData) {
let result = ''
if (entityData.ipLocationCountry) {
result += `${entityData.ipLocationCountry},`
if (entityData.country) {
result += `${entityData.country},`
}
if (entityData.ipLocationProvince) {
result += `${entityData.ipLocationProvince},`
if (entityData.province) {
result += `${entityData.province},`
}
if (entityData.ipLocationCity) {
result += `${entityData.ipLocationCity},`
if (entityData.city) {
result += `${entityData.city},`
}
result = result.substr(0, result.length - 1)
if (!result) {
@@ -381,19 +373,19 @@ export default {
},
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams () {
const queryParams = {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
ip: this.entity.ipAddr
resource: this.entity.entityValue,
ip: this.entity.entityValue
}
return queryParams
},
getPerformanceQueryParams () {
const queryParams = {
serverIp: this.entity.ipAddr
return {
serverIp: this.entity.entityValue
}
return queryParams
},
handleRelationData (result) {
this.entityData.appCount = result.appCount
@@ -411,11 +403,29 @@ export default {
queryRelated () {
this.getRelatedServerDataOne(this.relatedServerDomainUrl)
this.getRelatedServerDataTwo(this.relatedServerAppUrl)
},
getOpenPort () {
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
resource: this.entity.entityValue
}
axios.get(api.entity.entityList.ipRelatedPort, { params: params }).then(res => {
if (res.data.code === 200 && res.data.data.result.length) {
this.openPort = ''
res.data.data.result.forEach(item => {
this.openPort += item.port + '/' + item.l7Protocol + ','
})
this.openPort = this.openPort.slice(0, -1)
}
})
}
},
mounted () {
this.queryParams = this.getQueryParams()
this.chartGetMap()
this.getOpenPort()
this.$nextTick(() => {
setTimeout(() => {
this.queryRelated()
@@ -425,7 +435,7 @@ export default {
setup (props) {
const entityCopy = {
..._.cloneDeep(props.entity),
ip: props.entity.ipAddr
ip: props.entity.entityValue
}
return {
chart: {
@@ -434,7 +444,7 @@ export default {
unitType: 'number',
valueColumn: 'sessions'
},
id: props.entity.ipAddr,
id: props.entity.entityValue,
type: 2
},
entityCopy,
@@ -444,3 +454,110 @@ export default {
}
}
</script>
<style lang="scss">
//.type-content {
// margin-bottom:15px;
// display:flex;
// flex-flow: row wrap;
// width:100%;
.data-item {
display: flex;
justify-content: center;
align-items: center;
background: rgba(119,131,145,0.06);
border: 1px solid rgba(119,131,145,0.36);
border-radius: 2px;
height:28px;
padding:8px 15px;
margin-right:10px;
//margin-bottom:15px;
font-size: 12px;
color: #353636;
font-weight: 400;
white-space: nowrap;
}
.show-more-related {
height: 28px;
line-height: 28px;
padding-bottom: 12px;
cursor: pointer;
}
//}
.entity-score {
.circle-icon {
border-radius: 3px;
width: 6px;
height: 6px;
margin-right: 4px;
}
.data-score-red {
background: #E26154;
}
.data-score-yellow {
background: #E5A219;
}
.data-score-green {
background: #749F4D;
}
height:24px;
font-size: 14px;
color: #046ECA;
font-weight: 500;
display:flex;
align-items: center;
justify-content: center;
}
.cn-detection__header {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding-bottom: 3px;
color: #333333;
align-items: center;
font-size: 12px;
i {
color: #7b8fa2;
margin-right: 5px;
font-size: 18px;
}
.line {
color: #da5656;
margin-left: 12px;
font-size: xx-small;
font-weight: bold;
}
.circle {
width: 10px;
height: 10px;
border: 2px solid #da5656;
border-radius: 10px;
margin-top: 4px;
margin-right: 12px;
}
.domain {
background: #EFF2F5;
border-radius: 2px;
font-size: 14px;
color: #333333;
letter-spacing: 0;
line-height: 14px;
margin-left: 5px;
font-style: italic;
padding: 0 2px;
font-weight: 500;
}
}
.el-popper {
min-width: 90px !important;
width: auto !important;
max-width: 300px !important;
max-height: 180px !important;
overflow: scroll !important;
line-height: 24px !important;
}
</style>

View File

@@ -6,7 +6,7 @@ import { riskLevelMapping, unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import { shallowRef, markRaw } from 'vue'
import { metricOption } from '@/views/detections/options/detectionOptions'
import { sortBy, reverseSortBy } from '@/utils/tools'
import { sortBy, reverseSortBy, computeScore } from '@/utils/tools'
import { getSecond } from '@/utils/date-util'
import { api } from '@/utils/api'
@@ -45,29 +45,13 @@ export default {
metricChart: null,
performanceChartList: [],
loadingPerformance: [],
score: '-', // 网络质量评分
performanceMetricEndTimeInterval: 3600 // 服务质量事件指标的结束时间与开始时间的秒间隔
}
},
computed: {
entityName () {
let name
switch (this.entity.entityType) {
case ('ip'): {
name = this.entity.ipAddr
break
}
case ('domain'): {
name = this.entity.domainName
break
}
case ('app'): {
name = this.entity.appName
break
}
default: break
}
return name
return this.entity.entityValue
},
appRisk () {
return function (level) {
@@ -234,7 +218,7 @@ export default {
this.performanceChartList.push(metricChart)
this.echartsArray.push(shallowRef(metricChart))
} else {
const chartDom = document.getElementById(`entityPerformanceChart${this.entityName}${index}`)
const chartDom = document.getElementById(`entityPerformanceChart${this.entityName}_${index}`)
chartDom.innerHTML = '<span style="padding-left:5px;">-</span>'
}
})
@@ -272,6 +256,14 @@ export default {
if (this.networkQuantityUrl) {
get(this.networkQuantityUrl, this.getQueryParams()).then(response => {
if (response.code === 200) {
const data = {
establishLatencyMs: response.data.result.establishLatencyValue || null,
httpResponseLatency: response.data.result.httpResponseLatencyValue || null,
sslConLatency: response.data.result.sslConLatencyValue || null,
tcpLostlenPercent: response.data.result.sequenceGapLossPercentValue || null,
pktRetransPercent: response.data.result.pktRetransPercentValue || null
}
this.score = computeScore(data)
this.entityData.establishLatencyValue = response.data.result.establishLatencyValue
this.entityData.establishLatencyP50 = response.data.result.establishLatencyP50
this.entityData.establishLatencyP90 = response.data.result.establishLatencyP90
@@ -389,11 +381,6 @@ export default {
this.entityData.performanceNum = response.data.result.length
this.performanceData = response.data.result
this.entityData.performanceList = this.getTargetPageData(1, this.showMore.performancePageSize, this.performanceData)
this.$nextTick(() => {
setTimeout(() => {
this.queryEntityDetailPerformanceChart(this.entityData.performanceList, 0)
}, 200)
})
}
this.loadingAlert = false
})
@@ -412,16 +399,16 @@ export default {
},
performanceShowMore (num) {
const startIndex = this.showMore.performancePageSize
// const startIndex = this.showMore.performancePageSize
this.showMore.performancePageSize += num
this.entityData.performanceList = this.getTargetPageData(this.showMore.pageNo, this.showMore.performancePageSize, this.performanceData)
this.$nextTick(() => {
setTimeout(() => {
if (this.entityData.performanceList && this.entityData.performanceList.length > 0) {
this.queryEntityDetailPerformanceChart(this.entityData.performanceList.slice(startIndex, this.entityData.performanceList.length), startIndex)
}
}, 200)
})
// this.$nextTick(() => {
// setTimeout(() => lltext
// if (this.entityData.performanceList && this.entityData.performanceList.length > 0) {
// this.queryEntityDetailPerformanceChart(this.entityData.performanceList.slice(startIndex, this.entityData.performanceList.length), startIndex)
// }
// }, 200)
// })
},
securityShowMore (num) {
@@ -520,6 +507,7 @@ export default {
this.chartOption = _.cloneDeep(entityListLineOption)
setTimeout(() => { this.queryEntityDetail() })
const _this = this
this.entityData = { ...this.entityData, ...this.entity }
this.emitter.on('switch-collapse', function () {
setTimeout(() => { _this.queryEntityDetail() }, 200)
})

View File

@@ -45,43 +45,10 @@ export default {
return className
},
entityType () {
let type
switch (this.entityData.entityType) {
case 'ip': {
type = this.entityData.ipAddr
break
}
case 'domain': {
type = this.entityData.domainName
break
}
case 'app': {
type = this.entityData.appName
break
}
default:
break
}
return type
return this.entity.entityValue
},
entityName () {
let name
switch (this.entityData.entityType) {
case ('ip'): {
name = this.entity.ipAddr
break
}
case ('domain'): {
name = this.entity.domainName
break
}
case ('app'): {
name = this.entity.appName
break
}
default: break
}
return name
return this.entity.entityValue
},
appRisk () {
return function (level) {
@@ -94,32 +61,11 @@ export default {
queryParams () {
let params
const now = window.$dayJs.tz().valueOf()
switch (this.entityData.entityType) {
case ('ip'): {
params = {
startTime: this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : Math.floor(now / 1000 - 3600),
endTime: this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : Math.floor(now / 1000),
ip: this.entityData.ipAddr
}
break
}
case ('domain'): {
params = {
startTime: this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : Math.floor(now / 1000 - 3600),
endTime: this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : Math.floor(now / 1000),
domain: this.entityData.domainName
}
break
}
case ('app'): {
params = {
startTime: this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : Math.floor(now / 1000 - 3600),
endTime: this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : Math.floor(now / 1000),
appName: this.entityData.appName
}
break
}
default: break
// eslint-disable-next-line prefer-const
params = {
startTime: this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : Math.floor(now / 1000 - 3600),
endTime: this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : Math.floor(now / 1000),
resource: this.entityData.entityValue
}
return params
}
@@ -130,7 +76,7 @@ export default {
path: '/entityDetail',
query: {
entityType: this.entityData.entityType,
entityName: this.entityData.ipAddr || this.entityData.domainName || this.entityData.appName
entityName: this.entityData.entityValue
}
})
window.open(href, '_blank')
@@ -140,7 +86,7 @@ export default {
path: '/entityGraph',
query: {
entityType: this.entityData.entityType,
entityName: this.entityData.ipAddr || this.entityData.domainName || this.entityData.appName
entityName: this.entityData.entityValue
}
})
window.open(href, '_blank')
@@ -209,9 +155,7 @@ export default {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
appName: this.entityType,
domain: this.entityType,
ip: this.entityType
resource: this.entityType
}
},
queryEntityDetailTraffic () {
@@ -295,30 +239,36 @@ export default {
},
resize () {
this.echartsArray.forEach(item => { item.value.resize() })
},
initUrl () {
if (this.entity.entityType) {
switch (this.entity.entityType) {
case 'ip': {
// this.trafficUrl = api.entityIpDetailTraffic
this.trafficUrl = api.entity.entityList.ipThroughput
break
}
case 'domain': {
// this.trafficUrl = api.entityDomainDetailTraffic
this.trafficUrl = api.entity.entityList.domainThroughput
break
}
case 'app': {
// this.trafficUrl = api.entityAppDetailTraffic
this.trafficUrl = api.entity.entityList.appThroughput
break
}
default:
break
}
}
}
},
watch: {
entityData: {
deep: true,
handler (n) {
if (n.entityType) {
switch (n.entityType) {
case 'ip': {
this.trafficUrl = api.entityIpDetailTraffic
break
}
case 'domain': {
this.trafficUrl = api.entityDomainDetailTraffic
break
}
case 'app': {
this.trafficUrl = api.entityAppDetailTraffic
break
}
default:
break
}
}
this.initUrl()
}
}
},
@@ -326,7 +276,9 @@ export default {
this.debounceFunc = this.$_.debounce(this.resize, 200)
window.addEventListener('resize', this.debounceFunc)
this.chartOption = _.cloneDeep(entityListLineOption)
this.entityData = _.cloneDeep(this.entity)
// this.entityData = _.cloneDeep(this.entity)
this.entityData = { ...this.entityData, ...this.entity }
this.initUrl()
setTimeout(() => {
this.querySecurity()
this.queryEntityDetailTraffic()

View File

@@ -2,9 +2,7 @@
<div class="explorer-search">
<div class="explorer-search__title" v-show="!showList">{{$t('search.title')}}</div>
<div class="explorer-search__input-case" :class="{'explorer-search__input-case--question-mark-in-line': showList}">
<div class="explorer-search__input">
<!--新版实体列表改版后续记得解开-->
<!--<div class="explorer-search__input" style="border: 1px #DEDEDE solid;height: 42px;">-->
<div class="explorer-search__input" style="border: 1px #DEDEDE solid;height: 42px;">
<advanced-search
ref="search"
:column-list="columnList"