diff options
| author | chenjinsong <[email protected]> | 2021-09-22 23:05:18 +0800 |
|---|---|---|
| committer | chenjinsong <[email protected]> | 2021-09-22 23:05:18 +0800 |
| commit | 56d32ce8ca40f0b3e005312c3c67767aa8a86431 (patch) | |
| tree | ee6b0bae50ae90aa83bf26db62ccdee5568e6d89 | |
| parent | c55747fefca0e76e76715d88593eb8968b4c6639 (diff) | |
CN-148 feat: app详情开发
| -rw-r--r-- | src/components/charts/chart-options.js | 16 | ||||
| -rw-r--r-- | src/components/charts/panel.scss | 283 | ||||
| -rw-r--r-- | src/views/charts/Chart.vue | 259 | ||||
| -rw-r--r-- | src/views/charts/Panel.vue | 4 |
4 files changed, 418 insertions, 144 deletions
diff --git a/src/components/charts/chart-options.js b/src/components/charts/chart-options.js index de2f5f60..2cd48723 100644 --- a/src/components/charts/chart-options.js +++ b/src/components/charts/chart-options.js @@ -467,6 +467,22 @@ export function isIpOpenPort (type) { export function isIpHostedDomain (type) { 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) { return type === 94 diff --git a/src/components/charts/panel.scss b/src/components/charts/panel.scss index 54fae7bb..fca58565 100644 --- a/src/components/charts/panel.scss +++ b/src/components/charts/panel.scss @@ -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; flex-direction: column; .cn-chart__header { @@ -165,7 +165,8 @@ .cn-chart__header { border-bottom: 1px solid $--content-right-background-color; } - .cn-chart__body { + &>.cn-chart__body { + display: grid !important; padding: 0 20px; .cn-chart { 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 { display: flex; align-items: center; @@ -581,6 +445,10 @@ } } .title__name { + text-overflow: ellipsis; + max-width: 400px; + overflow: hidden; + white-space: nowrap; padding-left: 10px; color: #333; } @@ -697,3 +565,140 @@ // border: 1px solid #0091ff; // 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 + } + } +}
\ No newline at end of file diff --git a/src/views/charts/Chart.vue b/src/views/charts/Chart.vue index 16e31a62..2b37b858 100644 --- a/src/views/charts/Chart.vue +++ b/src/views/charts/Chart.vue @@ -139,7 +139,7 @@ </div> <div class="hosted-domain__chart"> <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> <div> @@ -289,7 +289,185 @@ </template> </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> <script> @@ -320,6 +498,10 @@ import { isIpBasicInfo, isIpOpenPort, isIpHostedDomain, + isDomainWhois, + isDomainDnsRecord, + isAppBasicInfo, + isAppRelatedDomain, getChartColor } from '@/components/charts/chart-options' import ChartError from '@/components/charts/ChartError' @@ -514,6 +696,20 @@ export default { this.isError = true 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) { console.error(e) @@ -1331,6 +1527,10 @@ export default { isIpBasicInfo: isIpBasicInfo(props.chart.type), isIpHostedDomain: isIpHostedDomain(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), myChart: shallowRef(null) } @@ -1364,7 +1564,7 @@ export default { } .open-port__table-cell { display: table-cell; - vertical-align: 30px; + vertical-align: middle; 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> diff --git a/src/views/charts/Panel.vue b/src/views/charts/Panel.vue index 0c682d0c..f26c8261 100644 --- a/src/views/charts/Panel.vue +++ b/src/views/charts/Panel.vue @@ -30,9 +30,9 @@ <div class="entity-detail__header"> <div class="detail-header__title"> <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 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="panel__time"> <DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/> |
