1093: 实体关系探索--右侧详情信息静态页面开发
This commit is contained in:
@@ -85,3 +85,6 @@
|
||||
@import 'views/charts2/entityDetailTabs';
|
||||
@import 'views/charts2/digitalCertificate';
|
||||
@import 'views/charts2/entityDetailBasicInfo';
|
||||
|
||||
@import "views/charts2/graphRightListBlock";
|
||||
@import "views/charts2/graphRightDetailBlock";
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
$font-size: 14px;
|
||||
.graph-detail-basic-info {
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
//height: 100%;
|
||||
|
||||
.entity-type {
|
||||
color: #717171;
|
||||
}
|
||||
|
||||
.graph-basic-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.graph-basic-info-name__block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.graph-basic-info-name {
|
||||
padding-right: 10px;
|
||||
font-family: Helvetica-Bold;
|
||||
font-size: 20px;
|
||||
color: #353636;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.graph-basic-info-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
border-radius: 50%;
|
||||
background-color: #EFF1F4;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
i {
|
||||
color: #717171;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-detail__icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: #e5edf3;
|
||||
|
||||
i {
|
||||
font-size: 26px;
|
||||
color: #4E84B4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-close {
|
||||
color: #575757;
|
||||
font-size: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.graph-basic-info__block {
|
||||
margin: 10px 0;
|
||||
|
||||
.graph-header__icon {
|
||||
width: 3px !important;
|
||||
height: 14px !important;
|
||||
}
|
||||
|
||||
.graph-basic-info__block-content {
|
||||
|
||||
.graph-content-item, .graph-content-relationship-item {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.graph-content-item {
|
||||
|
||||
.graph-content-item-label, .graph-content-item-value {
|
||||
width: 100px;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
padding-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.graph-content-item-value {
|
||||
width: 230px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-content-relationship-item {
|
||||
justify-content: space-between;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: rgba(135, 135, 135, 0.1);
|
||||
}
|
||||
|
||||
.graph-relationship-item-label, .graph-relationship-item-value {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size; // 原型上为12px,呈现效果不好,后续再调节
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
//height: 40px;
|
||||
display: flex;
|
||||
align-items: center !important;
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
.graph-relationship-item-value {
|
||||
color: #717171;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-tag-list {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
margin: 6px 0;
|
||||
|
||||
.graph-tag-item {
|
||||
margin-bottom: 10px;
|
||||
margin-right: 9px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.padding-b-10 {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
//修改popover样式
|
||||
.graph-popover {
|
||||
width: auto !important;
|
||||
background: #303133 !important;
|
||||
color: #fff !important;
|
||||
font-size: 12px !important;
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.graph-popover .el-popper__arrow::before {
|
||||
background: #303133 !important;
|
||||
}
|
||||
|
||||
.graph-expand-relationship__icon:hover {
|
||||
color: #D80000 !important;
|
||||
}
|
||||
131
src/assets/css/components/views/charts2/graphRightListBlock.scss
Normal file
131
src/assets/css/components/views/charts2/graphRightListBlock.scss
Normal file
@@ -0,0 +1,131 @@
|
||||
$font-size: 14px;
|
||||
.graph-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.graph-list-header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
|
||||
span {
|
||||
font-family: PingFangSC-Semibold;
|
||||
font-size: 16px;
|
||||
color: #353636;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.graph-list-header-icon {
|
||||
font-size: 21px;
|
||||
color: #717171;
|
||||
margin-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-header-number {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 14px;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-expand-btn-block {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.graph-list-expand-btn {
|
||||
background: #38ACD2;
|
||||
border: 1px solid rgba(46, 136, 166, 0.85);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-content-header {
|
||||
font-family: NotoSansHans-Medium;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.graph-list-content {
|
||||
padding: 0 10px;
|
||||
|
||||
.graph-list-item-ip {
|
||||
margin-bottom: 12px;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size;
|
||||
color: #353636;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #D80000;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-item-block {
|
||||
width: 300px;
|
||||
background: rgba(247, 247, 247, 1);
|
||||
border: 1px solid rgba(226, 229, 236, 1);
|
||||
border-radius: 2px;
|
||||
padding: 15px;
|
||||
|
||||
.graph-list-item, .graph-list-item__app {
|
||||
display: flex;
|
||||
|
||||
.graph-list-item-label, .graph-list-item-label__app {
|
||||
width: 62px;
|
||||
margin-right: 15px;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size; // 原型上为12px,但页面呈现效果不好
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.graph-list-item-label__app {
|
||||
width: 78px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.graph-list-country-flag {
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.graph-list-item-value {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.graph-list-item-value1 {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-item {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.padding-b-20 {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.graph-list-dividing-line {
|
||||
width: 300px;
|
||||
height: 1px;
|
||||
background: #ECECEC;
|
||||
margin: 12px 0;
|
||||
}
|
||||
@@ -140,7 +140,6 @@
|
||||
.row__charts {
|
||||
height: 19px;
|
||||
width: 60px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,29 +163,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
.show-detail {
|
||||
flex-shrink: 0;
|
||||
padding: 0 30px;
|
||||
font-size: 12px;
|
||||
color: #3976CB;
|
||||
//color: #2C72C6;
|
||||
//font-weight: 400;
|
||||
//margin-top: -17px;
|
||||
// 新版实体列表改版,后续记得解开
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
//i {
|
||||
// font-size: 12px;
|
||||
// margin-right: 5px;
|
||||
//}
|
||||
}
|
||||
//.show-detail {
|
||||
// flex-shrink: 0;
|
||||
// padding: 0 30px;
|
||||
// font-size: 12px;
|
||||
// color: #3976CB;
|
||||
// //color: #2C72C6;
|
||||
// //font-weight: 400;
|
||||
// //margin-top: -17px;
|
||||
// // 新版实体列表改版,后续记得解开
|
||||
//
|
||||
// &:hover {
|
||||
// cursor: pointer;
|
||||
// }
|
||||
//
|
||||
// //i {
|
||||
// // font-size: 12px;
|
||||
// // margin-right: 5px;
|
||||
// //}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-show-detail {
|
||||
flex-shrink: 0;
|
||||
padding: 0 30px;
|
||||
font-size: 12px;
|
||||
color: #2C72C6;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cn-entity__detail-overview {
|
||||
flex-basis: 100%;
|
||||
padding: 0 10px;
|
||||
|
||||
@@ -1,22 +1,81 @@
|
||||
<template>
|
||||
<div class="entity-graph">
|
||||
<div class="entity-graph__chart"></div>
|
||||
<div class="entity-graph__detail">
|
||||
<ip-list v-if="mode === 'ipList'"></ip-list>
|
||||
<div class="entity-graph__detail" v-if="mode !== ''">
|
||||
<ip-list
|
||||
v-if="mode === 'ipList'"
|
||||
:entity="entity"
|
||||
@closeBlock="onCloseBlock"
|
||||
@mouseenter="onMouseenter"
|
||||
@expandDetail="onExpandDetail">
|
||||
</ip-list>
|
||||
<app-or-domain-list
|
||||
v-if="mode === 'appList' || mode === 'domainList'"
|
||||
:entity="entity"
|
||||
@expandDetail="onExpandDetail"
|
||||
@mouseenter="onMouseenter"
|
||||
@closeBlock="onCloseBlock">
|
||||
</app-or-domain-list>
|
||||
<graph-detail
|
||||
v-if="mode === 'appDetail' || mode === 'ipDetail' || mode === 'domainDetail'"
|
||||
:entity="entity"
|
||||
@expand="onExpand"
|
||||
@closeBlock="onCloseBlock">
|
||||
</graph-detail>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IpList from '@/views/entityExplorer/entityGraphDetail/IpList'
|
||||
import GraphDetail from '@/views/entityExplorer/entityGraphDetail/GraphDetail'
|
||||
import AppOrDomainList from '@/views/entityExplorer/entityGraphDetail/AppOrDomainList'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'EntityRelationship',
|
||||
components: {
|
||||
IpList
|
||||
IpList,
|
||||
GraphDetail,
|
||||
AppOrDomainList
|
||||
},
|
||||
setup () {
|
||||
const route = useRoute()
|
||||
const { entityType, name } = route.query
|
||||
const entity = ref({
|
||||
entityType: entityType,
|
||||
entityName: name
|
||||
})
|
||||
const mode = ref('')
|
||||
mode.value = 'appList'
|
||||
|
||||
return {
|
||||
entity,
|
||||
mode
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mode: 'ipList' // ipList, ipDetail, domainList, domainDetail, appList, appDetail
|
||||
// mode: 'appList' // ipList, ipDetail, domainList, domainDetail, appList, appDetail
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCloseBlock () {
|
||||
// todo 关闭右侧graph面板
|
||||
this.mode = ''
|
||||
},
|
||||
onExpandDetail (mode) {
|
||||
this.mode = mode
|
||||
},
|
||||
onExpand (val) {
|
||||
// todo 调用接口,拓展关系
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// todo 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
if (!val.isTrusted) {
|
||||
// 鼠标移动反馈
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +92,7 @@ export default {
|
||||
width: 360px;
|
||||
border-left: 1px solid #E2E5EC;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
155
src/views/entityExplorer/entityGraphDetail/AppOrDomainList.vue
Normal file
155
src/views/entityExplorer/entityGraphDetail/AppOrDomainList.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="graph-list-header">
|
||||
<div>
|
||||
<div class="graph-list-header-title">
|
||||
<i class="graph-list-header-icon" :class="entityIcon"></i>
|
||||
<span>{{ $t(entityName) }}</span>
|
||||
</div>
|
||||
<div class="graph-list-header-number" style="margin-bottom: 30px">
|
||||
{{ $t('entity.graph.associatedQuantity') }}:<span>2</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="digital-certificate">
|
||||
<div class="digital-certificate-header padding-b-20">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-list-content-header ">
|
||||
{{ $t('entity.graph.expandedEntityQuantity') }}:
|
||||
<span>{{ cardData.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-content">
|
||||
<div v-for="(item, index) in cardData" :key="index" @mouseenter="onMouseenter(item)">
|
||||
<div class="graph-list-item-ip" @click="expandDetail">{{ item.name }}</div>
|
||||
<div class="graph-list-item-block">
|
||||
<div v-for="card in item.data" :key="card.name">
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{ card.label }}:</div>
|
||||
<div class="graph-list-item-value">{{ card.value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-dividing-line" v-if="index !== cardData.length - 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import i18n from '@/i18n'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'AppOrDomainList',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initData()
|
||||
},
|
||||
setup (props) {
|
||||
const cardData = ref([]) // 列表数据
|
||||
const entityIcon = ref('') // 顶部icon
|
||||
const entityName = ref('') // 顶部名称,非实体名
|
||||
|
||||
switch (props.entity.entityType) {
|
||||
case 'app': {
|
||||
entityIcon.value = 'cn-icon cn-icon-app-name'
|
||||
entityName.value = 'entities.tab.relatedApp'
|
||||
|
||||
cardData.value = [
|
||||
{
|
||||
name: 'Wechat',
|
||||
data: [
|
||||
{ name: 'appId', label: i18n.global.t('entities.domainDetail.appid'), value: '2376' },
|
||||
{ name: 'appCategory', label: i18n.global.t('entities.category'), value: 'Sensitive' },
|
||||
{ name: 'appSubcategory', label: i18n.global.t('entities.subcategory'), value: 'Parked Domain' },
|
||||
{ name: 'appRisk', label: i18n.global.t('entities.riskLevel'), value: 'Moderate Risk' },
|
||||
{ name: 'appDescription', label: i18n.global.t('config.dataSource.description'), value: 'Wechat is a Chinese multinational networking and services company.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Wechat',
|
||||
data: [
|
||||
{ name: 'appId', label: i18n.global.t('entities.domainDetail.appid'), value: '2376' },
|
||||
{ name: 'appCategory', label: i18n.global.t('entities.category'), value: 'Sensitive' },
|
||||
{ name: 'appSubcategory', label: i18n.global.t('entities.subcategory'), value: 'Parked Domain' },
|
||||
{ name: 'appRisk', label: i18n.global.t('entities.riskLevel'), value: 'Moderate Risk' },
|
||||
{ name: 'appDescription', label: i18n.global.t('config.dataSource.description'), value: 'Wechat is a Chinese multinational networking and services company.' }
|
||||
]
|
||||
}
|
||||
]
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
entityIcon.value = 'cn-icon cn-icon-subdomain'
|
||||
entityName.value = 'entities.subdomain'
|
||||
|
||||
cardData.value = [
|
||||
{
|
||||
name: '-*.webproxy.at.1.baidu.com',
|
||||
data: [
|
||||
{ name: 'categoryName', label: i18n.global.t('entities.category'), value: 'Business and Economy' },
|
||||
{ name: 'categoryGroup', label: i18n.global.t('entities.group'), value: 'Productivity' },
|
||||
{ name: 'registration', label: i18n.global.t('entities.registration'), value: 'China' },
|
||||
{ name: 'registrantOrg', label: i18n.global.t('entities.registry'), value: 'Beijing Baidu Netcom Science Technology Co, Ltd' },
|
||||
{ name: 'icpLicense', label: i18n.global.t('entities.icpLicense'), value: '京ICP备24537号' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '-*.webproxy.at.1.baidu.com',
|
||||
data: [
|
||||
{ name: 'categoryName', label: i18n.global.t('entities.category'), value: 'Business and Economy' },
|
||||
{ name: 'categoryGroup', label: i18n.global.t('entities.group'), value: 'Productivity' },
|
||||
{ name: 'registration', label: i18n.global.t('entities.registration'), value: 'China' },
|
||||
{ name: 'registrantOrg', label: i18n.global.t('entities.registry'), value: 'Beijing Baidu Netcom Science Technology Co, Ltd' },
|
||||
{ name: 'icpLicense', label: i18n.global.t('entities.icpLicense'), value: '京ICP备24537号' }
|
||||
]
|
||||
}
|
||||
]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
entityIcon,
|
||||
entityName,
|
||||
cardData
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData () {
|
||||
// 此处请求接口
|
||||
},
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
expandDetail () {
|
||||
if (this.entity.entityType === 'app') {
|
||||
this.$emit('expandDetail', 'appDetail')
|
||||
} else if (this.entity.entityType === 'domain') {
|
||||
this.$emit('expandDetail', 'domainDetail')
|
||||
}
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
this.$emit('mouseenter', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
366
src/views/entityExplorer/entityGraphDetail/GraphDetail.vue
Normal file
366
src/views/entityExplorer/entityGraphDetail/GraphDetail.vue
Normal file
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<!--title-->
|
||||
<div class="graph-detail-basic-info">
|
||||
<div style="display: flex">
|
||||
<div class="graph-detail__icon"><i :class="iconClass"></i></div>
|
||||
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<div class="entity-graph-type">{{ entityType[entity.entityType] }}</div>
|
||||
<div class="graph-basic-info">
|
||||
<div class="graph-basic-info-name__block">
|
||||
<div class="graph-basic-info-name" id="entityName">{{ entity.entityName }}</div>
|
||||
<div class="graph-basic-info-icon" @click="copyEntityName">
|
||||
<i class="cn-icon cn-icon-copy"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
|
||||
<!--basic info-->
|
||||
<div class="digital-certificate graph-basic-info__block">
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="digital-certificate-header-name">
|
||||
{{ $t('overall.basicInfo') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-basic-info__block-content">
|
||||
<div class="graph-content-item" v-for="item in detailCards" :key="item.name">
|
||||
<div class="graph-content-item-label">{{ item.label }}:</div>
|
||||
<div class="graph-content-item-value">{{ item.value || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--关系拓展-->
|
||||
<div class="digital-certificate graph-basic-info__block">
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="digital-certificate-header-name">
|
||||
{{ $t('entity.graph.relationshipExpansion') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-basic-info__block-content">
|
||||
<div v-for="item in relationList" :key="item.name" @click="expandRelation(item.name)">
|
||||
<el-popover
|
||||
v-if="item.value.length === item.total"
|
||||
placement="top"
|
||||
auto-close="2000"
|
||||
trigger="click"
|
||||
:content="$t('entity.graph.completed')"
|
||||
popper-class="graph-popover"
|
||||
>
|
||||
<template #reference>
|
||||
<div class="graph-content-item graph-content-relationship-item">
|
||||
<div class="graph-relationship-item-label">
|
||||
<i class="margin-r-6" :class="item.icon"></i>
|
||||
<span>{{ item.label }}:</span>
|
||||
</div>
|
||||
<div class="graph-relationship-item-value">
|
||||
<span class="margin-r-6">{{ item.value.length }}/{{ item.total }}</span>
|
||||
<i class="cn-icon cn-icon-expand-relationship" :style="{color: iconColor(item.value.length, item.total)}"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
|
||||
<div v-else class="graph-content-item graph-content-relationship-item">
|
||||
<div class="graph-relationship-item-label">
|
||||
<i class="margin-r-6" :class="item.icon"></i>
|
||||
<span>{{ item.label }}:</span>
|
||||
</div>
|
||||
<div class="graph-relationship-item-value">
|
||||
<span class="margin-r-6">{{ item.value.length }}/{{ item.total }}</span>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('entity.graph.expandDownward')"
|
||||
placement="top-end"
|
||||
>
|
||||
<i class="cn-icon cn-icon-expand-relationship graph-expand-relationship__icon" :style="{color: iconColor(item.value.length, item.total)}"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--标签-->
|
||||
<div class="digital-certificate graph-basic-info__block">
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="digital-certificate-header-name">
|
||||
{{ $t('entity.graph.labels') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="entity-detail graph-basic-info__block-content">
|
||||
<div class="graph-tag-list">
|
||||
<div v-for="ic in tagList" :key="ic.key">
|
||||
<div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import i18n from '@/i18n'
|
||||
import { copySelectionText, selectElementText } from '@/utils/tools'
|
||||
import { entityType, riskLevelMapping } from '@/utils/constants'
|
||||
import axios from '_axios@0.21.4@axios'
|
||||
import { api } from '@/utils/api'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'DomainDetail',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
mixins: [chartMixin],
|
||||
data () {
|
||||
return {
|
||||
entityType
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iconClass () {
|
||||
let className
|
||||
switch (this.entity.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
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initData()
|
||||
},
|
||||
setup (props) {
|
||||
const detailCards = ref([])
|
||||
const relationList = ref([])
|
||||
const tagList = ref([])
|
||||
// 标签列表,后续请求接口时处理
|
||||
tagList.value = [
|
||||
{ key: 'isp', value: '信息技术', type: 'positive' },
|
||||
{ key: 'malwareName', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName1', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName2', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName3', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName4', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName5', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName6', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName7', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName8', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName9', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName10', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName11', value: '互联网', type: 'normal' },
|
||||
{ key: 'malwareName12', value: '互联网', type: 'normal' }
|
||||
]
|
||||
|
||||
switch (props.entity.entityType) {
|
||||
case 'ip': {
|
||||
detailCards.value = _.concat(detailCards.value,
|
||||
{ name: 'asn', label: 'ASN', value: '' },
|
||||
{ name: 'asOrg', label: i18n.global.t('entities.asOrg'), value: '' },
|
||||
// { name: 'asSubnet', label: i18n.global.t('entities.asSubnet'), value: '' },
|
||||
{ name: 'isp', label: 'ISP', value: '' },
|
||||
{ name: 'location', label: i18n.global.t('entities.geographicLocation'), value: '' }
|
||||
// { name: 'dnsPtr', label: 'DNS PTR', value: '' }
|
||||
)
|
||||
|
||||
relationList.value = _.concat(relationList.value,
|
||||
{ icon: 'cn-icon cn-icon-subdomain', name: 'resolveIp', label: i18n.global.t('entity.graph.resolveDomain'), value: [], total: 12 },
|
||||
{ icon: 'cn-icon cn-icon-app-name', name: 'relatedApp', label: i18n.global.t('entities.tab.relatedApp'), value: [], total: 6 }
|
||||
)
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
detailCards.value = _.concat(detailCards.value,
|
||||
{ name: 'categoryName', label: i18n.global.t('entities.category'), value: '' },
|
||||
{ name: 'categoryGroup', label: i18n.global.t('entities.domainDetail.subcategory'), value: '' },
|
||||
{ name: 'reputationLevel', label: i18n.global.t('entities.creditLevel2'), value: '' },
|
||||
{ name: 'expireDate', label: i18n.global.t('entities.graph.expirationDate'), value: '' },
|
||||
{ name: 'registrarName', label: i18n.global.t('entities.registrar'), value: '' },
|
||||
{ name: 'registrantOrg', label: i18n.global.t('entities.registry'), value: '' },
|
||||
{ name: 'registrantCountry', label: i18n.global.t('entities.registrationCountry'), value: '' },
|
||||
{ name: 'createDate', label: i18n.global.t('entities.registrationDate'), value: '' },
|
||||
{ name: 'email', label: i18n.global.t('entities.registryEmail'), value: '' }
|
||||
)
|
||||
|
||||
relationList.value = _.concat(relationList.value,
|
||||
{ icon: 'cn-icon cn-icon-resolve-ip', name: 'resolveIp', label: i18n.global.t('entities.graph.resolveIp'), value: [], total: 12 },
|
||||
{ icon: 'cn-icon cn-icon-subdomain', name: 'subdomain', label: i18n.global.t('entities.subdomain'), value: [1, 2], total: 2 },
|
||||
{ icon: 'cn-icon cn-icon-app-name', name: 'relatedApp', label: i18n.global.t('entities.tab.relatedApp'), value: [], total: 6 }
|
||||
)
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
detailCards.value = _.concat(detailCards.value,
|
||||
{ name: 'appCategory', label: i18n.global.t('entities.category'), value: '' },
|
||||
{ name: 'appSubcategory', label: i18n.global.t('entities.subcategory'), value: '' },
|
||||
{ name: 'appRisk', label: i18n.global.t('entities.riskLevel'), value: '' },
|
||||
{ name: 'appTechnology', label: i18n.global.t('overall.technology'), value: '' },
|
||||
{ name: 'appName', label: i18n.global.t('overall.appName2'), value: '' },
|
||||
{ name: 'appLongname', label: i18n.global.t('overall.appFullName'), value: '' },
|
||||
{ name: 'appDescription', label: i18n.global.t('config.dataSource.description'), value: '' }
|
||||
)
|
||||
|
||||
relationList.value = _.concat(relationList.value,
|
||||
{ icon: 'cn-icon cn-icon-resolve-ip', name: 'resolveIp', label: i18n.global.t('entities.graph.resolveIp'), value: [], total: 12 },
|
||||
{ icon: 'cn-icon cn-icon-subdomain', name: 'resolveDomain', label: i18n.global.t('entity.graph.resolveDomain'), value: [], total: 12 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
detailCards,
|
||||
relationList,
|
||||
tagList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData () {
|
||||
axios.get(`${api.entity.basicInfo}/${this.entity.entityType}?resource=${this.entity.entityName}`).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 200) {
|
||||
switch (this.entity.entityType) {
|
||||
case 'ip': {
|
||||
if (res.data.asn) {
|
||||
this.detailCards.find(c => c.name === 'asn').value = res.data.asn.asn
|
||||
this.detailCards.find(c => c.name === 'asOrg').value = res.data.asn.organization
|
||||
// AS子网接口未返回
|
||||
}
|
||||
if (res.data.location) {
|
||||
this.detailCards.find(c => c.name === 'isp').value = res.data.location.isp
|
||||
this.detailCards.find(c => c.name === 'location').value = this.handleLocation(res.data.location)
|
||||
// DNS PTR接口未返回
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
if (res.data.category) {
|
||||
this.detailCards.find(c => c.name === 'categoryName').value = res.data.category.categoryName
|
||||
this.detailCards.find(c => c.name === 'categoryGroup').value = res.data.category.categoryGroup
|
||||
this.detailCards.find(c => c.name === 'reputationLevel').value = res.data.category.reputationLevel
|
||||
}
|
||||
|
||||
if (res.data.whois) {
|
||||
this.detailCards.find(c => c.name === 'expireDate').value = dateFormatByAppearance(res.data.whois.expireDate)
|
||||
this.detailCards.find(c => c.name === 'registrarName').value = res.data.whois.registrarName
|
||||
this.detailCards.find(c => c.name === 'registrantOrg').value = res.data.whois.registrantOrg
|
||||
this.detailCards.find(c => c.name === 'registrantCountry').value = res.data.whois.registrantCountry
|
||||
this.detailCards.find(c => c.name === 'createDate').value = dateFormatByAppearance(res.data.whois.createDate)
|
||||
this.detailCards.find(c => c.name === 'email').value = res.data.whois.email
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
if (res.data.category) {
|
||||
this.detailCards.find(c => c.name === 'appCategory').value = res.data.category.appCategory
|
||||
this.detailCards.find(c => c.name === 'appSubcategory').value = res.data.category.appSubcategory
|
||||
this.detailCards.find(c => c.name === 'appRisk').value = this.appRisk(res.data.category.appRisk)
|
||||
this.detailCards.find(c => c.name === 'appTechnology').value = res.data.category.appTechnology
|
||||
this.detailCards.find(c => c.name === 'appName').value = res.data.category.appName
|
||||
this.detailCards.find(c => c.name === 'appLongname').value = res.data.category.appLongname
|
||||
this.detailCards.find(c => c.name === 'appDescription').value = res.data.category.appDescription
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.httpError(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
},
|
||||
/** 复制实体名称 */
|
||||
copyEntityName () {
|
||||
selectElementText(document.getElementById('entityName'))
|
||||
if (copySelectionText()) {
|
||||
this.$message.success(this.$t('tip.copySuccess'))
|
||||
} else {
|
||||
this.$message.error('Unknown error')
|
||||
}
|
||||
},
|
||||
/** 修改关系拓展图标颜色,全部拓展浅灰色,否则深灰色 */
|
||||
iconColor (length, total) {
|
||||
if (length < total) {
|
||||
return 'rgba(57, 57, 57, 1)'
|
||||
} else {
|
||||
return 'rgba(57, 57, 57, 0.5)'
|
||||
}
|
||||
},
|
||||
// 关闭右侧详情栏
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
/** 构造地址,国-省市-市 */
|
||||
handleLocation (data) {
|
||||
const location = []
|
||||
if (data.country) {
|
||||
location.push(data.country)
|
||||
}
|
||||
if (data.province) {
|
||||
location.push(data.province)
|
||||
}
|
||||
if (data.city) {
|
||||
location.push(data.city)
|
||||
}
|
||||
return location.join(' - ')
|
||||
},
|
||||
appRisk (level) {
|
||||
const m = riskLevelMapping.find(mapping => {
|
||||
return mapping.value === level
|
||||
})
|
||||
return (m && m.name) || level
|
||||
},
|
||||
/** 关系拓展 */
|
||||
expandRelation (name) {
|
||||
// todo 模拟效果,后续修改
|
||||
const obj = this.relationList.find(item => item.name === name)
|
||||
if (obj) {
|
||||
const num = obj.total - obj.value.length
|
||||
if (num > 0) {
|
||||
const len = num < 10 ? num : 10
|
||||
for (let i = 0; i < len; i++) {
|
||||
obj.value.push(i)
|
||||
}
|
||||
this.$emit('expand')
|
||||
}
|
||||
}
|
||||
},
|
||||
httpError (e) {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +1,95 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="graph-list-header">
|
||||
<div>
|
||||
<div class="graph-list-header-title">
|
||||
<i class="cn-icon cn-icon-resolve-ip graph-list-header-icon"></i>
|
||||
<span>{{ $t('entities.graph.resolveIp') }}</span>
|
||||
</div>
|
||||
<div class="graph-list-header-number">
|
||||
{{ $t('entity.graph.associatedQuantity') }}:<span>12</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-expand-btn-block">
|
||||
<el-button type="primary" class="graph-list-expand-btn">
|
||||
{{ $t('entity.graph.continueToExpand') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="digital-certificate">
|
||||
<div class="digital-certificate-header padding-b-20">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-list-content-header ">
|
||||
{{ $t('entity.graph.expandedEntityQuantity') }}:
|
||||
<span>{{ ipList.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-content">
|
||||
<div v-for="(item, index) in ipList" :key="index" @mouseenter="onMouseenter(item)">
|
||||
<div class="graph-list-item-ip"><span @click="expandDetail">{{ item.ip }}</span></div>
|
||||
<div class="graph-list-item-block">
|
||||
<div class="graph-list-item padding-b-10">
|
||||
<div class="graph-list-item-label">{{ $t('overall.location') }}:</div>
|
||||
<div class="graph-list-item-value graph-list-item-value1">
|
||||
<img :src="require(`../../../../public/images/flag/${item.flag}.svg`)" class="graph-list-country-flag"/>
|
||||
<span>{{ item.city }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-item">
|
||||
<div class="graph-list-item-label">ASN:</div>
|
||||
<div class="graph-list-item-value">{{ item.asn }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-dividing-line" v-if="index !== ipList.length - 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'IpList'
|
||||
name: 'IpList',
|
||||
data () {
|
||||
return {
|
||||
ipList: [
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' },
|
||||
{ ip: '192.168.22.11', flag: '011-china', city: 'China, Beijing', asn: 'Sensitive' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
expandDetail () {
|
||||
this.$emit('expandDetail', 'ipDetail')
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
this.$emit('mouseenter', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
@@ -146,17 +146,17 @@
|
||||
</div>
|
||||
<!--新版实体列表改版,去除这一段-->
|
||||
</div>
|
||||
<div class="show-detail" @click="showDetail">
|
||||
{{ $t('overall.detail') }}>
|
||||
</div>
|
||||
<!-- 新版实体列表改版,后续记得解开-->
|
||||
<!-- <div class="show-detail">-->
|
||||
<!-- <div @click="showDetail"><i class="cn-icon cn-icon-detail"></i>{{ $t('overall.detail') }} ></div>-->
|
||||
<!-- <div><i class="cn-icon cn-icon-graph"></i>{{ $t('entities.graph') }} ></div>-->
|
||||
<!-- <div class="show-detail" @click="showDetail">-->
|
||||
<!-- {{ $t('overall.detail') }}>-->
|
||||
<!-- </div>-->
|
||||
<!-- 新版实体列表改版,后续记得解开-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-show-detail">
|
||||
<div @click="showDetail"><i class="cn-icon cn-icon-detail"></i>{{ $t('overall.detail') }} ></div>
|
||||
<div @click="showGraph"><i class="cn-icon cn-icon-graph"></i>{{ $t('entities.graph') }} ></div>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div class="cn-entity__detail-overview" v-if="!isCollapse">
|
||||
<el-divider></el-divider>
|
||||
|
||||
@@ -135,6 +135,16 @@ export default {
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
},
|
||||
showGraph () {
|
||||
const { href } = this.$router.resolve({
|
||||
path: '/entityGraph',
|
||||
query: {
|
||||
entityType: this.entityData.entityType,
|
||||
name: this.entityData.ipAddr || this.entityData.domainName || this.entityData.appName
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
},
|
||||
querySecurity () {
|
||||
const queryParams = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
|
||||
Reference in New Issue
Block a user