CN-148 feat: app详情开发

This commit is contained in:
chenjinsong
2021-09-22 23:05:18 +08:00
parent c55747fefc
commit 56d32ce8ca
4 changed files with 418 additions and 144 deletions

View File

@@ -467,6 +467,22 @@ export function isIpOpenPort (type) {
export function isIpHostedDomain (type) { export function isIpHostedDomain (type) {
return type === 33 return type === 33
} }
/* APP实体托管域名 */
export function isAppRelatedDomain (type) {
return type === 34
}
/* APP实体基本信息 */
export function isAppBasicInfo (type) {
return type === 82
}
/* DOMAIN实体Whois */
export function isDomainWhois (type) {
return type === 83
}
/* DOMAIN实体DNS记录 */
export function isDomainDnsRecord (type) {
return type === 84
}
/* 组 */ /* 组 */
export function isGroup (type) { export function isGroup (type) {
return type === 94 return type === 94

View File

@@ -121,7 +121,7 @@
} }
} }
&>.cn-chart__echarts, &>.cn-chart__table, &>.cn-chart__map, &>.cn-chart__group { &>.cn-chart__echarts, &>.cn-chart__table, &>.cn-chart__map, &>.cn-chart__group, &>.cn-chart__whois, &>.cn-chart__dns-record, &>.cn-chart__app-basic {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.cn-chart__header { .cn-chart__header {
@@ -165,7 +165,8 @@
.cn-chart__header { .cn-chart__header {
border-bottom: 1px solid $--content-right-background-color; border-bottom: 1px solid $--content-right-background-color;
} }
.cn-chart__body { &>.cn-chart__body {
display: grid !important;
padding: 0 20px; padding: 0 20px;
.cn-chart { .cn-chart {
border: none; border: none;
@@ -173,143 +174,6 @@
} }
} }
} }
&>.cn-chart__single-value.cn-chart__single-value--icon-left {
display: flex;
align-items: center;
.single-value-icon__box {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 40%;
}
.single-value__icon {
display: flex;
justify-content: center;
width: 72px;
height: 72px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
display: flex;
align-items: center;
font-size: 28px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
max-width: 60%;
padding-right: 10px;
.content__data {
padding-bottom: 7%;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 16px;
color: #666666;
}
&.single-value__content--with-chart {
.content__title {
border-bottom: 1px solid $--content-right-background-color;
}
}
.single-value__unit {
font-weight: normal;
padding-left: 10px;
color: #666;
font-size: 20px;
}
}
}
&>.cn-chart__single-value.cn-chart__single-value--icon-right {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
.single-value__icon {
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
position: relative;
margin-right: 7.5%;
margin-bottom: 6%;
width: 56px;
height: 56px;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 24px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
height: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
height: 50%;
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
padding-top: 5%;
height: 50%;
flex: auto;
font-size: 24px;
color: #333333;
font-weight: bold;
}
}
}
&>.cn-chart__single-value.cn-chart__single-value--chart {
display: flex;
padding: 13px 20px;
.single-value__content {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
height: 30%;
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
align-items: center;
height: 25%;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__chart {
flex: auto
}
}
}
&>.cn-chart__title { &>.cn-chart__title {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -581,6 +445,10 @@
} }
} }
.title__name { .title__name {
text-overflow: ellipsis;
max-width: 400px;
overflow: hidden;
white-space: nowrap;
padding-left: 10px; padding-left: 10px;
color: #333; color: #333;
} }
@@ -697,3 +565,140 @@
// border: 1px solid #0091ff; // border: 1px solid #0091ff;
// border-radius: 2px; // border-radius: 2px;
//} //}
.cn-chart__single-value.cn-chart__single-value--icon-left {
display: flex;
align-items: center;
.single-value-icon__box {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 40%;
}
.single-value__icon {
display: flex;
justify-content: center;
width: 72px;
height: 72px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
display: flex;
align-items: center;
font-size: 28px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
max-width: 60%;
padding-right: 10px;
.content__data {
padding-bottom: 7%;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 16px;
color: #666666;
}
&.single-value__content--with-chart {
.content__title {
border-bottom: 1px solid $--content-right-background-color;
}
}
.single-value__unit {
font-weight: normal;
padding-left: 10px;
color: #666;
font-size: 20px;
}
}
}
.cn-chart__single-value.cn-chart__single-value--icon-right {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
.single-value__icon {
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
position: relative;
margin-right: 7.5%;
margin-bottom: 6%;
width: 56px;
height: 56px;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 24px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
height: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
height: 50%;
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
padding-top: 5%;
height: 50%;
flex: auto;
font-size: 24px;
color: #333333;
font-weight: bold;
}
}
}
.cn-chart__single-value.cn-chart__single-value--chart {
display: flex;
padding: 13px 20px;
.single-value__content {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
height: 30%;
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
align-items: center;
height: 25%;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__chart {
flex: auto
}
}
}

View File

@@ -139,7 +139,7 @@
</div> </div>
<div class="hosted-domain__chart"> <div class="hosted-domain__chart">
<div> <div>
<div class="hosted-domain__chart-title">{{$t('entities.byType')}}</div> <div class="hosted-domain__chart-title">{{$t('entities.byCategory')}}</div>
<div class="chart-drawing" :id="`chart${chartInfo.id}-0`"></div> <div class="chart-drawing" :id="`chart${chartInfo.id}-0`"></div>
</div> </div>
<div> <div>
@@ -289,7 +289,185 @@
</template> </template>
</div> </div>
</div> </div>
<!-- IP详情-基本信息 --> <!-- Domain详情-whois -->
<div
v-else-if="isDomainWhois"
class="cn-chart cn-chart__whois"
:style="computePosition"
>
<div class="cn-chart__header">
<chart-error
:isError="isError"
:errorInfo="errorInfo"
>
</chart-error>
<div class="header__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
</div>
<div class="cn-chart__body">
<div class="domain-detail-list">
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">{{$t('entities.sponsor')}}</div>
<div class="domain-detail-list__content">{{detailData.sponsor || '-'}}</div>
</div>
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">{{$t('entities.org')}}</div>
<div class="domain-detail-list__content">{{detailData.org || '-'}}</div>
</div>
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">Email</div>
<div class="domain-detail-list__content">{{detailData.email || '-'}}</div>
</div>
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">{{$t('overall.country')}}</div>
<div class="domain-detail-list__content">{{detailData.orgCountry || '-'}}</div>
</div>
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">{{$t('entities.creationDate')}}</div>
<div class="domain-detail-list__content">{{detailData.creationDate || '-'}}</div>
</div>
<div class="domain-detail-list__row">
<div class="domain-detail-list__label">{{$t('entities.expirationDate')}}</div>
<div class="domain-detail-list__content">{{detailData.expirationDate || '-'}}</div>
</div>
</div>
</div>
</div>
<!-- Domain详情-DNS记录 -->
<div
v-else-if="isDomainDnsRecord"
class="cn-chart cn-chart__dns-record"
:style="computePosition"
>
<div class="cn-chart__header">
<chart-error
:isError="isError"
:errorInfo="errorInfo"
>
</chart-error>
<div class="header__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
</div>
<div class="cn-chart__body">
<div class="entity-detail__dns-record">
<div class="dns-record__table">
<div style="height: 100%; overflow: hidden auto;">
<div class="dns-record__table-row dns-record__table-row--header">
<div class="dns-record__table-cell" style="min-width: 200px;">Type</div>
<div class="dns-record__table-cell" style="width: 100%;">Value</div>
</div>
<div class="dns-record__table-row" v-for="(data, index) in detailData" :key="index">
<div class="dns-record__table-cell">{{data.type || '-'}}</div>
<div class="dns-record__table-cell">{{data.value || '-'}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- APP详情-基本信息 -->
<div
v-else-if="isAppBasicInfo"
class="cn-chart cn-chart__app-basic"
:style="computePosition"
>
<div class="cn-chart__header">
<chart-error
:isError="isError"
:errorInfo="errorInfo"
>
</chart-error>
<div class="header__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
</div>
<div class="cn-chart__body">
<div style="display: flex; justify-content: space-between; width: 100%;">
<el-descriptions :column="1" style="padding: 20px 30px;">
<el-descriptions-item :label="$t('overall.appName')">{{detailData ? detailData.name : '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.appFullName') + ':'">{{detailData.fullName || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.technology')">{{detailData.technology || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.remark')">{{detailData.remark || '-'}}</el-descriptions-item>
</el-descriptions>
<div style="display: flex;">
<single-value
:type="51"
icon="cn-icon cn-icon-category"
:loading="false"
style="width: 250px;"
>
<template #title>
<span>{{$t('entities.category')}}</span>
</template>
<template #data>
<span>test</span>
</template>
</single-value>
<single-value
:type="51"
icon="cn-icon cn-icon-sub-category"
:loading="false"
style="width: 250px;"
>
<template #title>
<span>{{$t('entities.subcategory')}}</span>
</template>
<template #data>
<span>test2</span>
</template>
</single-value>
<single-value
:type="51"
icon="cn-icon cn-icon-credit"
:loading="false"
style="width: 250px;"
>
<template #title>
<span>{{$t('entities.reputationLevel')}}</span>
</template>
<template #data>
<span>test3</span>
</template>
</single-value>
</div>
</div>
</div>
</div>
<!-- APP详情-相关域名 -->
<div
v-else-if="isAppRelatedDomain"
class="cn-chart cn-chart__dns-record"
:style="computePosition"
>
<div class="cn-chart__header">
<chart-error
:isError="isError"
:errorInfo="errorInfo"
>
</chart-error>
<div class="header__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
</div>
<div class="cn-chart__body">
<div class="entity-detail__dns-record">
<div class="dns-record__table">
<div style="height: 100%; overflow: hidden auto;">
<div class="dns-record__table-row dns-record__table-row--header">
<div class="dns-record__table-cell" style="min-width: 200px;">Type</div>
<div class="dns-record__table-cell" style="width: 100%;">Value</div>
</div>
<div class="dns-record__table-row" v-for="(data, index) in detailData" :key="index">
<div class="dns-record__table-cell">{{data.type || '-'}}</div>
<div class="dns-record__table-cell">{{data.value || '-'}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
@@ -320,6 +498,10 @@ import {
isIpBasicInfo, isIpBasicInfo,
isIpOpenPort, isIpOpenPort,
isIpHostedDomain, isIpHostedDomain,
isDomainWhois,
isDomainDnsRecord,
isAppBasicInfo,
isAppRelatedDomain,
getChartColor getChartColor
} from '@/components/charts/chart-options' } from '@/components/charts/chart-options'
import ChartError from '@/components/charts/ChartError' import ChartError from '@/components/charts/ChartError'
@@ -514,6 +696,20 @@ export default {
this.isError = true this.isError = true
this.errorInfo = e this.errorInfo = e
}) })
} else if (this.isDomainWhois || this.isDomainDnsRecord) {
const queryParams = { domain: this.entity.domain }
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
if (response.code === 200) {
this.detailData = response.data.result
} else {
this.isError = true
this.noData = true
this.errorInfo = response.msg || response.message || 'Unknown'
}
}).catch(e => {
this.isError = true
this.errorInfo = e
})
} }
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@@ -1331,6 +1527,10 @@ export default {
isIpBasicInfo: isIpBasicInfo(props.chart.type), isIpBasicInfo: isIpBasicInfo(props.chart.type),
isIpHostedDomain: isIpHostedDomain(props.chart.type), isIpHostedDomain: isIpHostedDomain(props.chart.type),
isIpOpenPort: isIpOpenPort(props.chart.type), isIpOpenPort: isIpOpenPort(props.chart.type),
isDomainWhois: isDomainWhois(props.chart.type),
isDomainDnsRecord: isDomainDnsRecord(props.chart.type),
isAppBasicInfo: isAppBasicInfo(props.chart.type),
isAppRelatedDomain: isAppRelatedDomain(props.chart.type),
layout: getLayout(props.chart.type), layout: getLayout(props.chart.type),
myChart: shallowRef(null) myChart: shallowRef(null)
} }
@@ -1364,7 +1564,7 @@ export default {
} }
.open-port__table-cell { .open-port__table-cell {
display: table-cell; display: table-cell;
vertical-align: 30px; vertical-align: middle;
padding: 13px 30px; padding: 13px 30px;
} }
} }
@@ -1435,4 +1635,57 @@ export default {
} }
} }
} }
.domain-detail-list {
display: table;
width: 100%;
.domain-detail-list__row {
display: table-row;
.domain-detail-list__label {
display: table-cell;
padding: 15px 30px;
border-bottom: 1px solid $--content-right-background-color;
width: 170px;
color: #6B717B;
}
.domain-detail-list__content {
display: table-cell;
padding: 15px 0 ;
border-bottom: 1px solid $--content-right-background-color;
color: #3976CB;
}
}
}
.entity-detail__dns-record {
display: flex;
height: 100%;
width: 100%;
.dns-record__table {
display: table;
height: 100%;
width: 100%;
.dns-record__table-row {
display: table-row;
font-size: 14px;
color: #333333;
}
.dns-record__table-row.dns-record__table-row--header {
padding: 13px 30px 0;
height: 40px;
color: #6B717B;
}
.dns-record__table-cell {
display: table-cell;
border-bottom: 1px solid $--content-right-background-color;
vertical-align: middle;
padding: 13px 30px;
}
.dns-record__table-row:not(.dns-record__table-row--header) .dns-record__table-cell:last-of-type {
color: #3976CB;
}
}
}
</style> </style>

View File

@@ -30,9 +30,9 @@
<div class="entity-detail__header"> <div class="entity-detail__header">
<div class="detail-header__title"> <div class="detail-header__title">
<span class="title__icon-circle"> <span class="title__icon-circle">
<i class="cn-icon cn-icon-ip"></i> <i class="cn-icon" :class="{'cn-icon-ip': entity.ip, 'cn-icon-domain': entity.domain, 'cn-icon-app': entity.appId}"></i>
</span> </span>
<span class="title__name">{{entity.name}}</span></div> <div class="title__name" :title="entity.ip || entity.domain || entity.appId || '-'">{{entity.ip || entity.domain || entity.appId || '-'}}</div></div>
<div class="detail-header__operation"> <div class="detail-header__operation">
<div class="panel__time"> <div class="panel__time">
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/> <DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>