fix: 无用代码、文件清理

This commit is contained in:
chenjinsong
2022-02-14 17:40:29 +08:00
parent c27891dc21
commit 88b1fa3bcd
32 changed files with 344 additions and 5688 deletions

View File

@@ -1,974 +0,0 @@
.entity-detail-tool {
display: flex;
justify-content: space-between;
align-items: center;
margin: 10px 20px 10px 0;
padding: 0 20px;
height: 60px;
background-color: #FFFFFF;
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.06);
border-radius: 2px;
.cn-icon-arrow-left-circle {
color: $--color-primary;
font-size: 20px;
}
}
.chart-error-popper{
word-wrap:break-word;
word-break:break-word;
border: 1px solid #e02f44;
min-width: 180px !important;
max-width: 280px !important;
}
.chart-header-position{
position: relative;
}
.chart-error-popper.el-popper.is-light {
background: #e02f44;
border: 1px solid #e02f44;
}
.chart-error-popper.el-popover.el-popper {
color:white;
}
.chart-error-popper.el-popper.is-light[data-popper-placement^='top'] .el-popper__arrow::before {
border-color: #e02f44;
background: #e02f44;
bottom:0px;
}
.chart-error-popper.el-popper.is-light[data-popper-placement^='bottom'] .el-popper__arrow::before {
border-color: #e02f44;
background: #e02f44;
}
.chart-info-corner {
color: #767980;
cursor: pointer;
position: absolute;
display: none;
left: 0;
width: 28px;
height: 28px;
z-index: 2;
top: 0;
}
.chart-info-corner--error {
display: block;
color: #fff;
}
.chart-info-corner--error .chart-info-corner-inner {
border-left: 28px solid #e02f44;
border-right: none;
border-bottom: 28px solid rgba(0,0,0,0);
}
.chart-info-corner-inner {
width: 0;
height: 0;
position: absolute;
left: 0;
bottom: 0;
}
.chart-info-corner .fa {
position: absolute;
top: 2px;
left: 6px;
font-size: 65%;
z-index: 3;
font-style: normal;
}
.cn-chart-icon-warning:before {
content: "!";
font-weight:normal;
}
.cn-chart:not(.cn-chart__group):not(.cn-chart__block) {
&>.cn-chart__body {
height: 100%;
width: 100%;
}
}
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body, .cn-chart__block .cn-chart__body {
display: grid;
grid-template-columns: repeat(30, 1fr);
grid-auto-flow: row;
grid-gap: 10px;
overflow: auto;
padding-right: 20px;
position: relative;
.panel__time {
position: absolute;
right: 20px;
top: 10px;
z-index: 1;
display: flex;
&>div {
margin-left: 10px;
}
}
&>.cn-chart {
position: relative;
background-color: #FFFFFF;
border: 1px solid #E7EAED;
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
border-radius: 2px;
height: calc(100% - 47px);
width: 100%;
.chart-drawing {
height: 100%;
width: 100%;
}
}
&>.cn-chart__whois>.cn-chart__body {
overflow: auto;
}
&>.cn-chart__echarts, &>.cn-chart__table, &>.cn-chart__map, &>.cn-chart__group, &>.cn-chart__block, &>.cn-chart__whois, &>.cn-chart__dns-record, &>.cn-chart__app-basic {
display: flex;
flex-direction: column;
.cn-chart__header {
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
padding: 10px 20px 10px 18px;
height: 47px;
.cn-chart__title {
font-size: 16px;
color: #333333;
font-weight: bold;
}
.header__operations {
color: #999;
}
}
.cn-chart__body {
flex: auto;
display: flex;
.el-descriptions {
padding-top: 30px;
}
&>.el-descriptions {
flex: 0 0 350px;
padding: 30px 36px;
}
.chart-location {
display: flex;
flex: 1;
flex-direction: column;
padding: 0 20px 20px 0;
}
.el-descriptions__content {
color: #3976CB;
}
}
}
&>.cn-chart__block {
&>.cn-chart__header {
height: 60px;
border-bottom: none !important;
}
&>.cn-chart__body {
display: grid !important;
grid-template-columns: repeat(30, 1fr);
grid-auto-flow: row;
grid-gap: 10px;
padding: 0 20px;
&>.cn-chart {
border: 1px solid #E7EAED;
}
/* detail页面block下的五连图的标题样式改变 */
.cn-chart__group .cn-chart__echarts {
.cn-chart__header {
border-bottom: none !important;
.header__title {
font-size: 14px !important;
color: #3976CB !important;
}
}
}
}
}
.cn-chart__group {
.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
}
&>.cn-chart__body {
display: grid !important;
grid-gap: 10px;
padding: 0 20px;
.cn-chart {
border: none;
box-shadow: none;
}
}
}
&>.cn-chart__title {
display: flex;
align-items: center;
font-size: 20px;
padding-left: 10px;
color: #333;
background-color: transparent;
box-shadow: none;
border: none;
}
&>.cn-chart__tabs {
padding: 10px 25px 10px 15px;
.el-tabs__nav-wrap::after {
height: 1px;
}
&>.el-tabs__header {
margin-bottom: 10px;
}
&>.el-tabs__content {
height: calc(100% - 40px);
}
}
&>.cn-chart__table {
.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
.header__operations {
display: flex;
justify-content: end;
align-items: center;
.header__operation.header__operation--table {
display: flex;
align-items: center;
height: 22px;
margin-left: 10px;
color: $--color-primary;
border: 1px solid $--color-primary;
border-radius: $--border-radius-primary;
.option__button {
display: flex;
align-items: center;
height: 100%;
padding: 0 5px;
cursor: pointer;
background-color: white;
transition: all linear .2s;
}
.option__button:hover {
background-color: #EFF2F5;
}
.option__button.icon-group-item:first-of-type:not(:last-of-type) {
padding: 0 5px 0 0;
}
.option__button.icon-group-item:last-of-type:not(:first-of-type) {
padding: 0 0 0 5px;
}
.option__select {
.el-input__inner {
width: 80px;
padding-right: 20px;
border: none;
height: 100%;
line-height: 20px;
color: $--color-primary;
}
.el-input__prefix > div {
font-weight: normal;
line-height: 19px;
color: $--color-primary;
}
.el-input__suffix {
display: flex;
.el-input__suffix-inner {
line-height: 14px;
.el-select__caret {
line-height: 14px;
width: 16px;
color: $--color-primary;
}
}
}
}
.option__select.select-column {
.el-input__inner {
width: 86px;
padding-left: 8px;
}
}
.icon-group-divide {
height: 14px;
width: 1px;
background-color: $--color-primary;
}
i {
font-size: 12px;
}
}
}
}
.cn-chart__body {
flex: auto;
overflow-y: auto;
.el-table {
padding: 0 10px;
&:before {
height: 0;
}
thead {
color: #333;
}
th.is-leaf, td {
border-bottom: none;
}
th {
padding-bottom: 5px;
}
td {
padding: 4px 0;
color: #333;
}
}
}
}
&>.cn-chart__echarts {
.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
.header__operations {
display: flex;
justify-content: end;
align-items: center;
.header__operation.header__operation--echarts {
display: flex;
align-items: center;
height: 22px;
margin-left: 10px;
color: $--color-primary;
border: 1px solid $--color-primary;
border-radius: $--border-radius-primary;
.option__button {
display: flex;
align-items: center;
height: 100%;
padding: 0 5px;
cursor: pointer;
background-color: white;
transition: all linear .2s;
}
.option__button:hover {
background-color: #EFF2F5;
}
.option__button.icon-group-item:first-of-type:not(:last-of-type) {
padding: 0 5px 0 0;
}
.option__button.icon-group-item:last-of-type:not(:first-of-type) {
padding: 0 0 0 5px;
}
.option__select {
.el-input__inner {
width: 120px;
padding-right: 20px;
border: none;
height: 100%;
line-height: 20px;
color: $--color-primary;
}
.el-input__prefix > div {
font-weight: normal;
line-height: 19px;
color: $--color-primary;
}
.el-input__suffix {
display: flex;
.el-input__suffix-inner {
line-height: 14px;
.el-select__caret {
line-height: 14px;
width: 16px;
color: $--color-primary;
}
}
}
}
.option__select.select-column {
.el-input__inner {
width: 86px;
padding-left: 8px;
}
}
.icon-group-divide {
height: 14px;
width: 1px;
background-color: $--color-primary;
}
i {
font-size: 12px;
}
}
}
}
.cn-chart__body {
overflow: hidden auto;
.el-table {
padding: 0 10px;
&:before {
height: 0;
}
thead {
color: #333;
}
th.is-leaf, td {
border-bottom: none;
}
th {
padding-bottom: 5px;
}
td {
padding: 4px 0;
color: #333;
}
}
}
.cn-chart__body.pie-with-table {
flex-basis: 40%;
}
.cn-chart__footer.pie-with-table {
flex-basis: 60%;
padding: 10px 30px 30px;
}
}
.pie-table {
font-size: 14px;
color: #333333;
font-weight: 500;
.el-table__header-wrapper {
.cell {
color: #333;
}
}
.el-table__expanded-cell[class*=cell] {
padding: 0;
}
.expand-table .el-table__body .el-table__row:last-of-type td {
border: none;
}
.expand-table {
font-weight: 400;
color: #606266;
.el-table__body-wrapper {
height: auto !important;
}
}
}
.chart__legend {
width: calc(100% - 40px);
border: 1px solid #E7EAED;
color: #5f6368;
margin: auto;
margin-bottom: 15px;
.chart__table-top {
width: 100%;
height: 30px;
border-bottom: #E7EAED 1px solid;
display: flex;
div {
font-size: 13px;
line-height: 28px;
color: $--color-primary;
}
}
.chart__table-below {
height: 240px;
width: 100%;
font-size: 13px;
}
.table-below-box {
width: 100%;
display: flex;
align-items: center;
line-height: 24px;
}
.table-below-box:hover {
background-color: #f9f9f9;
border: 0;
color: #383838;
}
.table__below-color {
width: 27px;
height: 7px;
flex-shrink: 0;
padding-left: 10px;
div {
height: 100%;
width: 100%;
border-radius: 24%;
}
}
.table__below-title {
padding: 0 6px;
flex-shrink: 1;
flex-grow: 1;
overflow: hidden;
min-width: 200px;
text-overflow: ellipsis;
white-space: nowrap;
}
.table__below-statistics {
width: 80px;
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.table-below-box:not(.chart__table-top) {
cursor: pointer;
}
.table-below-box.table-below-box--inactivated {
color: #ccc;
.table__below-color div {
background-color: #ccc !important;
}
}
}
}
@media only screen and (min-width : 10px) {
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
.cn-chart__body {
grid-auto-rows: 25px;
}
}
@media only screen and (min-width : 1224px) {
.cn-panel,
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
.cn-chart__body {
grid-auto-rows: 30px;
}
}
@media only screen and (min-width : 1824px) {
.cn-panel,
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
.cn-chart__body {
grid-auto-rows: 40px;
}
}
@media only screen and (min-width : 2424px) {
.cn-panel,
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
.cn-chart__body {
grid-auto-rows: 55px;
}
}
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane>.cn-chart {
border: none;
box-shadow: none;
.cn-chart__header {
border-bottom: none;
}
}
.cn-entity-detail {
height: 100%;
width: 100%;
overflow: hidden;
.entity-detail__header {
display: flex;
justify-content: space-between;
height: 70px;
padding-right: 20px;
background-color: #F7F9FB;
.detail-header__title {
display: flex;
align-items: center;
padding-left: 20px;
font-size: 20px;
.title__icon-circle {
display: flex;
justify-content: center;
align-items: center;
height: 38px;
width: 38px;
border-radius: 50%;
background-color: #B8C1D1;
i {
color: white;
font-size: 20px;
}
}
.title__name {
text-overflow: ellipsis;
max-width: 400px;
overflow: hidden;
white-space: nowrap;
padding-left: 10px;
color: #333;
}
}
.detail-header__operation {
display: flex;
align-items: flex-end;
.panel__time {
display: flex;
padding: 0 30px 10px 0;
}
& > .el-tabs > .el-tabs__header { // header背景色
margin: 0 0 -1px 0;
& > .el-tabs__nav-wrap > .el-tabs__nav-scroll > .el-tabs__nav {
& > .el-tabs__item {
height: 35px;
line-height: 35px;
}
& > .el-tabs__item.is-active { // 激活的tab上边框和背景色
background-color: white;
border-top: 2px solid #0091ff;
}
& > .el-tabs__active-bar {
display: none;
}
& > div:last-of-type {
padding-right: 20px;
}
& > div:nth-of-type(2) {
padding-left: 20px;
}
}
}
& > .el-tabs > .el-tabs__header > .el-tabs__nav-wrap::after { // 去掉tabs下方边框
height: 0 !important;
}
&>.el-tabs { // 底部对齐
display: flex;
align-items: flex-end;
}
}
}
.entity-detail__body {
height: 100%;
width: 100%;
overflow: auto;
/*&>div {
display: grid;
grid-template-columns: repeat(30, 1fr);
grid-auto-flow: row;
grid-gap: 10px;
height: 100%;
}
.cn-panel {
padding: 20px;
grid-gap: 10px;
&>.cn-chart>.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
.header__title>span {
color: #1890FF;
font-weight: bold;
font-size: 16px;
}
}
&>.cn-chart>.cn-chart__body {
.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
.header__title {
color: #666;
font-size: 16px;
}
}
}
}*/
}
}
.el-overlay {
overflow: hidden !important;
}
.entity-detail__dialog {
height: 90vh;
overflow: hidden;
.el-dialog__header {
display: none;
}
.el-dialog__body {
height: 100%;
padding: 0;
}
}
.option-popper {
.el-select-dropdown__item {
height: 24px;
line-height: 24px;
font-size: 12px;
}
}
.header__operation-btn {
margin-left: 12px;
cursor: pointer;
color: #999;
}
.ip-detail-as {
color: #999;
font-size: 12px;
padding-left: 10px;
}
//.cn-chart-select{
// display: flex;
// align-items: center;
// height: 22px;
// margin-left: 10px;
// color: #0091ff;
// border: 1px solid #0091ff;
// border-radius: 2px;
//}
.cn-chart__single-value.cn-chart__single-value--detail-overview.cn-chart__single-value--icon-left {
.single-value__icon {
width: 38px;
height: 38px;
i {
font-size: 15px;
}
}
.single-value__content {
.content__data {
font-size: 14px;
}
.content__title {
font-size: 12px;
}
}
}
.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--icon-right--color {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
.single-value__content {
display: flex;
height: 100%;
width: 100%;
flex-direction: row-reverse;
justify-content: space-between;
align-items: center;
.single-value-icon__box {
padding-right: 30px;
.single-value__icon {
border-radius: 50%;
position: relative;
margin-right: 7.5%;
margin-top: 30%;
.cn-icon-svg {
width: 50px;
height: 50px;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 24px;
}
}
}
.single-value__data{
display: flex;
height: 100%;
flex-direction: column;
padding-left: 20px;
.content__title {
display: flex;
align-items: end;
height: 50%;
font-size: 16px;
color: #666666;
padding-bottom: 5px;
}
.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
}
}
}
.chart-table-pagination.el-pagination {
padding: 12px 0 9px 0;
text-align: center;
.el-pagination__jump {
margin-left: 10px;
}
}

View File

@@ -1,39 +0,0 @@
<template>
<div class="cn-chart__map">
<div class="cn-chart__header chart-header-position" >
<slot name="chartErrorInfo"></slot>
<div class="header__title" v-if="!hideHeader">
<slot name="title"></slot>
</div>
<div class="header__operations" v-if="!hideHeader">
<slot name="operations"></slot>
</div>
</div>
<div class="cn-chart__body">
<slot></slot>
</div>
<div class="chart__loading" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<div class="cn-chart__footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'ChartMap',
props: {
loading: Boolean,
hideHeader: Boolean
},
data () {
return {
errorContent: '出错了。。。',
isError: true
}
}
}
</script>

View File

@@ -1,95 +0,0 @@
<template>
<div class="cn-chart cn-chart__single-value chart-header-position" :class="singleValueClass(type)" :style="{backgroundColor:color}">
<slot name="chartErrorInfo"></slot>
<div class="single-value-icon__box" v-if="type != 54">
<div class="single-value__icon"><i :class="icon"></i></div>
</div>
<div class="chart__loading" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<div class="single-value__content" v-if="type === 51">
<div class="content__data">
<slot name="data"></slot>
</div>
<div class="content__title">
<slot name="title"></slot>
</div>
</div>
<div class="single-value__content single-value__content--with-chart" v-if="type === 52 || type === 55">
<div class="content__title">
<slot name="title"></slot>
</div>
<div class="content__data">
<slot name="data"></slot>
</div>
<div class="content__chart">
<slot name="chart"></slot>
</div>
</div>
<div class="single-value__content" v-if="type === 53">
<div class="content__title"></div>
<div class="content__data"></div>
</div>
<div class="single-value__content" v-if="type === 54" >
<div class="single-value-icon__box" >
<div class="single-value__icon">
<!-- 使用图标-->
<svg class="cn-icon-svg" aria-hidden="true">
<use :xlink:href="icon"></use>
</svg>
</div>
</div>
<div class="single-value__data">
<div class="content__title">
<slot name="title"></slot>
</div>
<div class="content__data">
<slot name="data"></slot>
</div>
</div>
</div>
</div>
</template>
<script>
import '@/assets/css/font/iconfont.js'
export default {
name: 'ChartSingleValue',
props: {
type: Number,
icon: String,
loading: Boolean,
color: String
},
computed: {
singleValueClass () {
return function (type) {
let c
switch (type) {
case 51: {
c = 'cn-chart__single-value--icon-left'
break
}
case 55:
case 52: {
c = 'cn-chart__single-value--chart'
break
}
case 53: {
c = 'cn-chart__single-value--icon-right'
break
}
case 54: {
c = 'cn-chart__single-value--icon-right--color'
break
}
default: break
}
return c
}
}
}
}
</script>

View File

@@ -1,72 +0,0 @@
<template>
<div class="cn-chart cn-chart__table">
<div class="cn-chart__header chart-header-position" >
<slot name="chartErrorInfo"></slot>
<div class="header__title">
<slot name="title"></slot>
</div>
<div class="header__operations">
<slot name="operations"></slot>
</div>
</div>
<div class="chart__loading" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<div class="cn-chart__body" v-no-data="noData">
<el-table
style="width: 100%"
tooltip-effect="light"
:data="tableData"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
v-for="(c, i) in tableColumns"
show-overflow-tooltip
:key="i"
:label="c.label"
:prop="c.prop"
>
<template #header>{{c.label}}</template>
<template #default="{ row }">{{}}
<span v-if="c.prop === 'bytes'">
{{unitConvert(row[c.prop], unitTypes.byte).join(' ')}}
</span>
<span v-else-if="c.prop === 'packets' || c.prop === 'sessions'">
{{unitConvert(row[c.prop], unitTypes.number).join(' ')}}
</span>
<span v-else>
{{row[c.prop]}}
</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="cn-chart__footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
export default {
name: 'ChartTable',
props: {
tableColumns: Array,
tableData: Array,
loading: Boolean,
noData: Boolean
},
setup () {
return {
unitTypes,
unitConvert
}
}
}
</script>

View File

@@ -1,112 +0,0 @@
<template>
<div class="cn-chart cn-chart__table">
<div class="cn-chart__header chart-header-position" >
<slot name="chartErrorInfo"></slot>
<div class="header__title ">
<slot name="title"></slot>
</div>
<div class="header__operations">
<slot name="operations"></slot>
</div>
</div>
<div class="chart__loading" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<div class="cn-chart__body" v-no-data="noData">
<el-table
style="width: 100%"
tooltip-effect="light"
:data="tableData"
:show-header="false"
:cell-style="{padding:'7px 0'}"
>
<el-table-column>
<template #default="{ row }">
<div class="active-ip__icon"><i class="cn-icon cn-icon-ip ip-green"></i></div>
<div class="active-ip__content" >
{{row['name']}}
</div>
</template>
</el-table-column>
<el-table-column align="center">
<template #default="{ row }">
<span>
{{row['num']}}
</span>
</template>
</el-table-column>
<el-table-column
v-for="(c, i) in tableColumns"
show-overflow-tooltip
:key="i"
:label="c.label"
:prop="c.prop"
>
<template #default="{ row }">
<span v-if="c.prop === 'bytes'">
{{unitConvert(row[c.prop], unitTypes.byte).join(' ')}}
</span>
<span v-else-if="c.prop === 'packets' || c.prop === 'sessions'">
{{unitConvert(row[c.prop], unitTypes.number).join(' ')}}
</span>
<span v-else>
{{row[c.prop]}}
</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="cn-chart__footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
export default {
name: 'ChartTableActiveIp',
props: {
tableColumns: Array,
tableData: Array,
loading: Boolean,
noData: Boolean
},
setup () {
return {
unitTypes,
unitConvert
}
}
}
</script>
<style>
.active-ip__icon {
overflow: hidden;
position: absolute;
top: 8px;
left: 6px;
display: flex;
justify-content: center;
justify-items: center;
align-items: center;
width: 23px;
height: 23px;
border-radius: 50%;
background: #e8fbf9;
border: 2px solid #e8fbf9;
}
.ip-green {
color: #23BF9A;
}
.active-ip__content {
position: absolute;
top: 7px;
left: 35px;
overflow: hidden;
}
</style>

View File

@@ -1,55 +0,0 @@
<template>
<el-pagination
small
ref="pagination"
layout="prev,jumper,slot,next"
class="chart-table-pagination"
:total="total"
:page-size="pageSize"
v-model:currentPage="pageNo"
@current-change="current"
>
<span>/&nbsp;{{totalPage}}</span>
</el-pagination>
</template>
<script>
import { chartTableDefaultPageSize } from '@/utils/constants'
export default {
name: 'ChartTablePagination',
props: {
total: Number
},
data () {
return {
pageSize: chartTableDefaultPageSize,
pageNo: 1
}
},
computed: {
totalPage () {
const remainder = this.total % this.pageSize
if (remainder) {
return parseInt(this.total / this.pageSize) + 1
} else {
return parseInt(this.total / this.pageSize)
}
}
},
methods: {
current (val) {
this.$emit('pageJump', val)
},
resetPageNo () {
this.pageNo = 1
}
},
mounted () {
const _this = this
this.emitter.on('chart-pageNo', function () {
_this.resetPageNo()
})
this.$el.querySelector('.el-pagination__jump').childNodes[0].nodeValue = ''
}
}
</script>

View File

@@ -1,9 +0,0 @@
<template>
<div class="cn-chart cn-chart__title"></div>
</template>
<script>
export default {
name: 'ChartTitle'
}
</script>

View File

@@ -1,44 +0,0 @@
<template>
<div class="cn-chart cn-chart__echarts" :class="{'cn-chart__echarts--statistics': isEchartsWithStatistics}">
<div class="cn-chart__header chart-header-position" v-if="layout.indexOf(layoutConstant.HEADER) > -1" >
<slot name="chartErrorInfo"></slot>
<div class="header__title">
<slot name="title"></slot>
</div>
<div class="header__operations">
<slot name="operations"></slot>
</div>
</div>
<div class="cn-chart__body" :class="{'pie-with-table': isPieWithTable}" v-no-data="noData">
<slot></slot>
</div>
<div class="chart__loading" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1 && !noData" :class="{'pie-with-table': isPieWithTable}">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
import { layoutConstant, isEchartsWithTable, isEchartsWithStatistics } from '@/components/charts/chart-options'
export default {
name: 'EchartsFrame',
props: {
layout: Array,
chartInfo: Object,
loading: Boolean,
noData: Boolean
},
setup (props) {
return {
layoutConstant,
isPieWithTable: isEchartsWithTable(props.chartInfo.type),
isEchartsWithStatistics: isEchartsWithStatistics(props.chartInfo.type)
}
},
mounted () {
}
}
</script>

View File

@@ -1,258 +0,0 @@
<template>
<el-table
ref="table"
class="pie-table"
:data="pieTableData"
style="width: 100%;border: 1px solid #E7EAED"
:row-key="getRowKey"
@expand-change="currentChange"
:current-row-key="tableNameColumn"
tooltip-effect="light"
:expand-row-keys="expandRowKeys"
size="mini"
height="100%">
<el-table-column type="expand" min-width="5%">
<template #default="props">
<div style="position: relative">
<div class="chart__loading" style="top: 0; height: 100%; z-index: 1;" v-show="loading">
<i class="el-icon-loading"></i>
</div>
<el-table
tooltip-effect="light"
class="expand-table"
:data="childrenTableData"
style="width: 100%;"
:show-header="false"
:size="'mini'"
:height="'100%'">
<el-table-column
width="48">
</el-table-column>
<el-table-column
v-for="(item, index) in tableTitlesOther"
:key="index"
show-overflow-tooltip
:min-width="item.width"
:label="item.label"
:prop="item.prop"
#default="{row}">
<span v-if="item.prop === 'nameColumn'">
{{ nameColumn === 'domainCategoryName' ? row['categoryName'] :(nameColumn === 'domainReputationLevel'? row['reputationLevel']:(nameColumn==='appCategory'?row['appCategoryName']:appRisk(row['appRiskLevel'])))}}
</span>
<span v-else-if="item.prop === 'tableNameColumn'">
{{ tableNameColumn === 'appName' ? row['appName'] : row['domain']}}
</span>
<span v-else-if="item.prop === 'bytes'">
{{unitConvert(row[item.prop], unitTypes.byte).join(' ')}}
</span>
<span v-else-if="item.prop === 'packets' || item.prop === 'sessions'">
{{unitConvert(row[item.prop], unitTypes.number).join(' ')}}
</span>
<span v-else>
{{ row[item.prop] }}
</span>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column
v-for="(item, index) in tableTitles"
:key="index"
show-overflow-tooltip
:min-width="item.width"
:label="(tableNameColumn === 'appName'&& item.prop === 'tableNameColumn')? $t('overall.appName'):item.label"
:prop="item.prop"
#default="{row}">
<span v-if="item.prop === 'nameColumn'">
{{ nameColumn === 'domainCategoryName' ? row['categoryName'] :(nameColumn === 'domainReputationLevel'? row['reputationLevel']:(nameColumn==='appCategory'?row['appCategoryName']:appRisk(row['appRiskLevel'])))}}
</span>
<span v-else-if="item.prop === 'tableNameColumn'">
{{ tableNameColumn === 'appName' ? row['appName'] : row['domain']}}
</span>
<span v-else-if="item.prop === 'bytes'">
{{unitConvert(row[item.prop], unitTypes.byte).join(' ')}}
</span>
<span v-else-if="item.prop === 'packets' || item.prop === 'sessions'">
{{unitConvert(row[item.prop], unitTypes.number).join(' ')}}
</span>
<span v-else>
{{ row[item.prop] }}
</span>
</el-table-column>
</el-table>
</template>
<script>
import unitConvert from '@/utils/unit-convert'
import { get } from '@/utils/http'
import { replaceUrlPlaceholder } from '@/utils/tools'
import { unitTypes, riskLevelMapping } from '@/utils/constants'
export default {
name: 'PieTable',
props: {
tableData: Array,
chartInfo: Object,
order: String,
timeFilter: Object
},
watch: {
tableData: {
deep: true,
immediate: true,
handler (n) {
this.pieTableData = JSON.parse((JSON.stringify(n)))
this.pieTableData.forEach(item => {
item.children = []
})
}
},
chartInfo: {
deep: true,
immediate: true,
handler (n) {
if (n && n.params) {
this.nameColumn = n.params.nameColumn
this.tableNameColumn = n.params.tableNameColumn
}
}
}
},
computed: {
appRisk () {
return function (level) {
const m = riskLevelMapping.find(mapping => {
return mapping.value == level
})
return (m && m.name) || level
}
}
},
data () {
return {
nameColumn: '',
tableNameColumn: '',
pieTableData: [],
childrenTableData: [],
expandRowKeys: [],
tableTitles: [
{
label: this.$t('overall.domain'),
prop: 'tableNameColumn', // 'domain'
width: '20%'
},
{
label: this.$t(this.chartInfo.params.tableTypeColumnLabel),
prop: 'nameColumn',
width: '22%'
},
{
label: this.$t('overall.sessions'),
prop: 'sessions',
width: '18%'
},
{
label: this.$t('overall.packets'),
prop: 'packets',
width: '18%'
},
{
label: this.$t('overall.bytes'),
prop: 'bytes',
width: '18%'
}
],
tableTitlesOther: [
{
label: this.$t('overall.serverIp'),
prop: 'serverIp',
width: '20%'
},
{
label: this.$t('overall.reputation'),
prop: 'nameColumn',
width: '22%'
},
{
label: this.$t('overall.sessions'),
prop: 'sessions',
width: '18%'
},
{
label: this.$t('overall.packets'),
prop: 'packets',
width: '18%'
},
{
label: this.$t('overall.bytes'),
prop: 'bytes',
width: '18%'
}
],
loading: true
}
},
methods: {
currentChange (row, expandedRows) {
this.loading = true
this.childrenTableData = []
if (this.tableNameColumn === 'appName') {
if (this.expandRowKeys[0] && (row.appName === this.expandRowKeys[0])) {
this.expandRowKeys = []
} else {
this.expandRowKeys = [row.appName]
}
} else {
if (this.expandRowKeys[0] && (row.domain === this.expandRowKeys[0])) {
this.expandRowKeys = []
} else {
this.expandRowKeys = [row.domain]
}
}
const url = this.chartInfo.params.urlChildrenTable
let queryParams = {
startTime: parseInt(this.timeFilter.startTime / 1000),
endTime: parseInt(this.timeFilter.endTime / 1000),
order: this.order,
domain: row.domain,
limit: 10
}
if (this.tableNameColumn === 'appName') {
queryParams = {
startTime: parseInt(this.timeFilter.startTime / 1000),
endTime: parseInt(this.timeFilter.endTime / 1000),
order: this.order,
appName: row.appName,
limit: 10
}
}
setTimeout(() => {
get(replaceUrlPlaceholder(url, queryParams)).then(response2 => {
if (response2.code === 200) {
this.childrenTableData = response2.data.result
}
}).finally(() => {
this.loading = false
})
}, 500)
},
getRowKey (row) {
if (this.tableNameColumn === 'appName') {
return row.appName
} else {
return row.domain
}
}
},
setup () {
return {
unitTypes,
unitConvert
}
}
}
</script>

View File

@@ -1,828 +0,0 @@
/**
* @author 陈劲松
* @date 2021/6/16
* @description chart option和一些工具
*/
import { format } from 'echarts'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import _ from 'lodash'
export const chartColor = ['#5370C6', '#90CC74', '#FAC858', '#EE6666',
'#73BFDE', '#3BA172', '#FC8452', '#9960B4',
'#E97CCC', '#FEA69E', '#0F8AB2', '#57CBAC',
'#5888BC', '#63B6AC', '#EDC6B2', '#D5746B']
export const chartBarColor = ['#0F8AB2', '#57CBAC']
export function getChartColor (index) {
return chartColor[index % chartColor.length]
}
export function getCharBartColor (index) {
return chartBarColor[index % chartBarColor.length]
}
const line = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: axiosFormatter,
show: true,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'time'
},
yAxis: {
type: 'value',
axisLabel: {
formatter: function (value, index, a, b) {
return unitConvert(value, unitTypes.number).join(' ')
}
},
minInterval: 1
},
animation: false,
grid: {
left: 55,
bottom: 30,
top: 100,
right: 25
},
color: chartColor,
legend: {
tooltip: {
show: true,
formatter: '{a}'
},
show: true,
right: 23,
top: 8,
padding: 2,
orient: 'horizontal',
icon: 'circle',
itemGap: 10,
itemWidth: 10,
textStyle: {
padding: [0, 0, 0, 2],
fontSize: 14
},
formatter: tooLongFormatter
},
axisLabel: {
fontSize: 14
},
series: [
{
name: '',
type: 'line',
smooth: false,
symbol: 'none',
data: []
}
]
}
const lineWithStatistics = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: axiosFormatter,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'time'
},
animation: false,
yAxis: {
type: 'value',
axisLabel: {
formatter: function (value, index) {
return unitConvert(value, unitTypes.number).join(' ')
}
},
minInterval: 1
},
color: chartColor,
grid: {
left: 55,
bottom: 30,
top: 20,
right: 20
},
legend: {
show: false
},
axisLabel: {
fontSize: 14
},
series: [
{
name: '',
type: 'line',
smooth: false,
symbol: 'none',
data: []
}
]
}
const lineStack = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: axiosFormatter,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'time'
},
color: chartColor,
yAxis: {
type: 'value',
axisLabel: {
formatter: function (value, index) {
return unitConvert(value, unitTypes.number).join(' ')
}
},
minInterval: 1
},
grid: {
left: 55,
bottom: 45,
top: 10,
right: 180
},
legend: {
show: true,
right: 30,
top: 'middle',
orient: 'vertical',
icon: 'circle',
itemGap: 20,
itemWidth: 10,
formatter: tooLongFormatter,
textStyle: {
padding: [0, 0, 0, 5],
fontSize: 14
}
},
axisLabel: {
fontSize: 14
},
series: [
{
name: '',
type: 'line',
stack: 'value',
areaStyle: {},
symbol: 'none',
data: []
}
]
}
const pieWithTable = {
tooltip: {
appendToBody: true
},
color: chartColor,
animation: false,
legend: {
orient: 'vertical',
type: 'plain',
left: '60%',
top: 'middle',
icon: 'circle',
itemWidth: 10, // 设置宽度
itemHeight: 10, // 设置高度
itemGap: 20,
formatter: tooLongFormatter,
tooltip: {
show: true
}
},
series: [
{
type: 'pie',
selectedMode: 'single',
radius: ['42%', '65%'],
center: ['30%', '50%'],
data: [],
label: {
formatter: '{d}%'
},
tooltip: {
formatter: function (param, index, callback) {
return `${param.name}: ${unitConvert(param.value, param.data.unitType).join(' ')}`
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
const ipHostedDomain = {
color: chartColor,
animation: false,
tooltip: {
show: true
},
legend: {
orient: 'vertical',
type: 'plain',
right: '8%',
top: 'middle',
icon: 'circle',
itemWidth: 10, // 设置宽度
itemHeight: 10, // 设置高度
itemGap: 20,
tooltip: {
show: true
}
},
series: [
{
type: 'pie',
selectedMode: 'single',
radius: ['42%', '65%'],
center: ['36%', '50%'],
data: [],
label: {
formatter: '{d}%'
},
tooltip: {
formatter: function (param, index, callback) {
return `${param.name}: ${unitConvert(param.value, param.data.unitType).join(' ')}`
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
const singleValueLine = {
tooltip: {
show: true,
enterable: true,
showContent: true,
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
}
},
xAxis: {
type: 'time',
show: false
},
yAxis: {
type: 'value',
show: false
},
animation: false,
grid: {
left: 0,
bottom: 2,
top: 5,
right: 0
},
color: chartColor,
legend: {
show: false
},
series: [
{
type: 'line',
legendHoverLink: false,
itemStyle: {
normal: {
color: '#81C9FF',
lineStyle: {
width: 2
}
}
},
data: [],
showSymbol: false,
areaStyle: { color: '#C9EAFF' }
}
]
}
export const entityListLineOption = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: axiosFormatter,
show: true,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'time',
show: false
},
yAxis: {
type: 'value',
show: false
},
animation: false,
grid: {
left: 0,
bottom: 2,
top: 5,
right: 0
},
color: chartColor,
legend: {
show: false
},
series: [
{
type: 'line',
legendHoverLink: false,
itemStyle: {
normal: {
lineStyle: {
width: 2
}
}
},
data: [],
showSymbol: false
}
]
}
const relationShip = {
grid: {
left: 0,
bottom: 50,
top: 80,
right: 0
},
series: [
{
type: 'graph',
layout: 'force',
symbolSize: 40,
roam: true,
force: {
repulsion: 350
},
draggable: true,
label: { show: true },
edgeSymbol: ['none', 'arrow'],
edgeSymbolSize: 7,
data: [],
links: []
}
]
}
const sankey = {
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [
{
type: 'sankey',
data: [],
links: [],
right: '5%',
top: 50,
bottom: 100,
levels: [
{
depth: 0,
itemStyle: {
color: '#47D49C'
},
lineStyle: {
color: '#999'
}
}, {
depth: 1,
itemStyle: {
color: '#A69BF5'
},
lineStyle: {
color: '#999'
}
}, {
depth: 2,
itemStyle: {
color: '#73A0FA'
},
lineStyle: {
color: '#999'
}
}
]
}
]
}
const ipOpenPortBar = {
xAxis: {
type: 'category',
axisTick: { show: false },
axisLine: { show: false }
},
grid: {
top: 30,
left: 60,
right: 50,
bottom: 50
},
yAxis: {
type: 'value',
show: false
},
series: [{
barWidth: 38,
data: [],
type: 'bar',
label: { show: true, position: 'top' },
barCategoryGap: '10%'
}]
}
const categoryBar = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: categoryVerticalFormatter,
show: true,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'category',
axisTick: { show: false },
axisLine: { show: false }
},
grid: {
top: 20,
left: 10,
right: 25,
bottom: 20,
containLabel: true
},
yAxis: {
type: 'value',
axisTick: { show: false },
axisLine: { show: false }
},
color: chartColor,
series: [{
barWidth: 15,
data: [],
type: 'bar',
label: { show: false },
barCategoryGap: '10%',
itemStyle: {
color: function (params) {
return getCharBartColor([params.dataIndex])
}
}
}]
}
const timeBar = {
tooltip: {
appendToBody: true,
trigger: 'axis',
textStyle: {
width: '20px',
overflow: 'truncate'
},
formatter: timeVerticalFormatter,
show: true,
className: 'nz-chart-tooltip',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);max-width: 300px !important'
},
xAxis: {
type: 'time',
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
interval: 0,
// rotate: -40, //设置日期显示样式(倾斜度)
formatter: function (value) { // 在这里写你需要的时间格式
const t_date = new Date(value)
return [t_date.getMonth() + 1, t_date.getDate()].join('/') + ' ' + [t_date.getHours(), t_date.getMinutes()].join(':')
}
}
},
grid: {
top: 20,
left: 25,
right: 25,
bottom: 20,
containLabel: true
},
yAxis: {
type: 'value',
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
formatter: function (value, index, a, b) {
return unitConvert(value, unitTypes.number).join(' ')
}
},
minInterval: 1
},
color: chartColor,
series: [{
barWidth: 15,
data: [],
type: 'bar',
label: { show: false },
barCategoryGap: '10%',
itemStyle: {
color: function (params) {
return getCharBartColor([params.dataIndex])
}
}
}]
}
const typeOptionMappings = [
{ value: 11, option: line }, // 常规折线图
{ value: 12, option: lineWithStatistics }, // 带统计表格的折线图
{ value: 13, option: lineStack }, // 折线堆叠图
{ value: 22, option: ipOpenPortBar }, // ip详情--开放端口的柱状图
{ value: 23, option: timeBar }, // 矿机所属单位
{ value: 24, option: categoryBar }, // 挖矿事件统计
{ value: 31, option: pieWithTable }, // 常规折线图
{ value: 33, option: ipHostedDomain }, // ip详情--托管域名
{ value: 34, option: ipHostedDomain }, // app详情--相关域名
{ value: 42, option: relationShip }, // 关系图
{ value: 43, option: sankey }, // 桑基图
{ value: 52, option: singleValueLine }
]
const typeCategory = {
MAP: 'map',
TABLE: 'table',
ECHARTS: 'echarts',
TITLE: 'title',
SINGLE: 'singleValue',
TABS: 'tabs'
}
export function getTypeCategory (type) {
if (isMap(type)) {
return typeCategory.MAP
} else if (isEcharts(type)) {
return typeCategory.ECHARTS
} else if (isTable(type)) {
return typeCategory.TABLE
} else if (isSingleValue(type)) {
return typeCategory.SINGLE
} else if (isTitle(type)) {
return typeCategory.TITLE
} else if (isTabs(type)) {
return typeCategory.TABS
}
}
/* 柱状图:挖矿事件统计(time类型柱状图) */
export function isEchartsTimeBar (type) {
return type == 23
}
/* 柱状图:矿机所属单位(category类型柱状图) */
export function isEchartsCategoryBar (type) {
return type == 24
}
/* 饼图柱状图等 */
export function isEcharts (type) {
return type >= 11 && type <= 50
}
/* 地图 */
export function isMap (type) {
return type >= 1 && type <= 10
}
/* 连线地图 */
export function isMapLine (type) {
return type === 1
}
/* 色块地图 */
export function isMapBlock (type) {
return type === 2
}
/* 带统计的折线图 */
export function isEchartsWithStatistics (type) {
return type === 12
}
/* 关系图 */
export function isRelationShip (type) {
return type === 42
}
/* 桑基图 */
export function isSankey (type) {
return type === 43
}
/* 单值 */
export function isSingleValue (type) {
return type >= 51 && type <= 60
}
/* 带折线图的单值 */
export function isSingleValueWithEcharts (type) {
return type === 52
}
/* 带折线图的单值 */
export function isSingleValueWithEchartsTemp (type) {
return type === 55
}
/* 带Table的饼图 */
export function isEchartsWithTable (type) {
return type === 31
}
/* table */
export function isTable (type) {
return type >= 61 && type <= 70
}
/* table */
export function isActiveIpTable (type) {
return type == 63
}
/* title */
export function isTitle (type) {
return type === 93
}
/* tabs */
export function isTabs (type) {
return type === 91
}
/* IP实体基本信息 */
export function isIpBasicInfo (type) {
return type === 4
}
/* IP实体开放端口 */
export function isIpOpenPort (type) {
return type === 22
}
/* IP实体托管域名 */
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 isCryptocurrencyEventList (type) {
return type === 85
}
/* 组 */
export function isGroup (type) {
return type === 94
}
/* 实体详情块 */
export function isBlock (type) {
return type === 95
}
export function getOption (type) {
const mapping = typeOptionMappings.find(m => m.value === type)
return mapping && mapping.option ? _.cloneDeep(mapping.option) : null
}
export const layoutConstant = {
HEADER: 'header',
FOOTER: 'footer'
}
export function getLayout (type) {
const layout = []
if (!isSingleValue(type) && !isTitle(type)) {
layout.push(layoutConstant.HEADER)
}
if (type === 12 || type === 31) {
layout.push(layoutConstant.FOOTER)
}
return layout
}
function tooLongFormatter (name) {
return format.truncateText(name, 110, '12')
}
function axiosFormatter (params) {
let str = '<div>'
params.forEach((item, i) => {
const tData = item.data[0]
if (i === 0) {
str += '<div style="margin-bottom: 5px">'
str += window.$dayJs.tz(tData).format('YYYY-MM-DD HH:mm:ss')
str += '</div>'
}
str += '<div class="cn-chart-tooltip-box">'
str += item.marker
str += `<span class="cn-chart-tooltip-content">
${item.seriesName}
</span>`
str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[1], item.data[2]).join(' ')}
</span>`
str += '</div>'
})
str += '</div>'
return str
}
export function timeVerticalFormatter (params) {
let str = '<div>'
params.forEach((item, i) => {
const tData = item.data[0]
if (i === 0) {
str += '<div style="margin-bottom: 5px">'
str += window.$dayJs.tz(tData).format('YYYY-MM-DD HH:mm:ss')
str += '</div>'
}
str += '<div class="cn-chart-tooltip-box">'
str += item.marker
str += `<span class="cn-chart-tooltip-content">
${item.seriesName}
</span>`
str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[1], item.data[2]).join(' ')}
</span>`
str += '</div>'
})
str += '</div>'
return str
}
export function timeHorizontalFormatter (params) {
let str = '<div>'
params.forEach((item, i) => {
const tData = item.data[1]
if (i === 0) {
str += '<div style="margin-bottom: 5px">'
str += window.$dayJs.tz(tData).format('YYYY-MM-DD HH:mm:ss')
str += '</div>'
}
str += '<div class="cn-chart-tooltip-box">'
str += item.marker
str += `<span class="cn-chart-tooltip-content">
${item.seriesName}
</span>`
str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[0], item.data[2]).join(' ')}
</span>`
str += '</div>'
})
str += '</div>'
return str
}
export function categoryHorizontalFormatter (params) {
let str = '<div>'
params.forEach((item, i) => {
str += '<div class="cn-chart-tooltip-box">'
str += item.data[1] + ': ' + item.data[0]
str += '</div>'
})
str += '</div>'
return str
}
export function categoryVerticalFormatter (params) {
let str = '<div>'
params.forEach((item, i) => {
str += '<div class="cn-chart-tooltip-box">'
str += item.data[0] + ': ' + item.data[1]
str += '</div>'
})
str += '</div>'
return str
}

View File

@@ -126,8 +126,8 @@
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import * as echarts from 'echarts'
import { getChartColor, entityListLineOption } from '@/components/charts/chart-options'
import { legendMapping } from '@/components/charts/chart-table-title'
import { getChartColor, entityListLineOption } from '@/views/charts/charts/chart-options'
import { legendMapping } from '@/views/charts/charts/chart-table-title'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'

View File

@@ -10,6 +10,10 @@ const routes = [
path: '/entityDetail',
component: () => import('@/views/entityExplorer/EntityDetail')
},
{
path: '/detections',
component: () => import('@/views/detections/Index')
},
{
path: '/',
component: () => import('@/components/layout/Home'),

File diff suppressed because it is too large Load Diff

View File

@@ -1,358 +0,0 @@
<template>
<div class="cn-chart">
<loading :loading="loading && !isTabs && !isBlock && !isGroup"></loading>
<chart-no-data v-if="isNoData"></chart-no-data>
<template v-else>
<chart-tabs
v-if="isTabs"
:chart-info="chartInfo"
:query-params="queryParams"
:entity="entity"
></chart-tabs>
<chart-map
v-else-if="isMap && !isIpBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:entity="entity"
@showLoading="showLoading"
></chart-map>
<chart-single-value
v-else-if="isSingleValue"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
@showLoading="showLoading"
></chart-single-value>
<chart-block
v-else-if="isBlock"
ref="chart"
:timeFilter="queryParams"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></chart-block>
<chart-group
v-else-if="isGroup"
:timeFilter="queryParams"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></chart-group>
<ip-basic-info
v-else-if="isIpBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></ip-basic-info>
<chart-time-bar
v-else-if="isEchartsTimeBar"
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:query-params="queryParams"
@showLoading="showLoading"
></chart-time-bar>
<chart-category-bar
v-else-if="isEchartsCategoryBar"
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:query-params="queryParams"
@showLoading="showLoading"
></chart-category-bar>
<chart-ip-open-port-bar
v-else-if="isIpOpenPortBar"
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:query-params="queryParams"
@showLoading="showLoading"
></chart-ip-open-port-bar>
<chart-table
v-else-if="isTable && isCurrentTable"
:chart-info="chartInfo"
:chart-data="chartData"
:table="table"
:query-params="queryParams"
@showLoading="showLoading"
></chart-table>
<chart-active-ip-table
v-else-if="isActiveIpTable"
:chart-info="chartInfo"
:chart-data="chartData"
:table="table"
:query-params="queryParams"
></chart-active-ip-table>
<chart-app-basic-info
v-else-if="isAppBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
></chart-app-basic-info>
<chart-domain-whois
v-else-if="isDomainWhois"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
></chart-domain-whois>
<chart-domain-dns-record
v-else-if="isDomainDnsRecord"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
></chart-domain-dns-record>
<chart-cryptocurrency-event-list
v-else-if="isCryptocurrencyEventList"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
></chart-cryptocurrency-event-list>
<chart-relation-ship
v-else-if="isRelationShip"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
></chart-relation-ship>
<chart-san-key
v-else-if="isSankey"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:entity="entity"
></chart-san-key>
<chart-echart
v-else-if="isEchartsLine || isEchartsPie"
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
@showLoading="showLoading"
></chart-echart>
<chart-echart-with-statistics
v-else-if="isEchartsWithStatistics"
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
@showLoading="showLoading"
></chart-echart-with-statistics>
<chart-echart-with-table
v-else-if="isEchartsWithTable"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:result-type="resultType"
:order-pie-table="orderPieTable"
@showLoading="showLoading"
></chart-echart-with-table>
<chart-echart-ip-hosted-domain
v-else-if="isIpHostedDomain"
:chart-info="chartInfo"
:chart-data="chartData"
@showLoading="showLoading"
:entity="entity"
></chart-echart-ip-hosted-domain>
<chart-echart-app-relate-domain
v-else-if="isAppRelatedDomain"
:chart-info="chartInfo"
:chart-data="chartData"
@showLoading="showLoading"
:entity="entity"
></chart-echart-app-relate-domain>
</template>
</div>
</template>
<script>
import Loading from '@/components/common/Loading'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import ChartTabs from '@/views/charts/charts/ChartTabs'
import ChartMap from '@/views/charts/charts/ChartMap'
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import ChartBlock from '@/views/charts/charts/ChartBlock'
import ChartGroup from '@/views/charts/charts/ChartGroup'
import IpBasicInfo from '@/views/charts/charts/IpBasicInfo'
import ChartEchart from '@/views/charts/charts/ChartEchart'
import ChartEchartWithStatistics from '@/views/charts/charts/ChartEchartWithStatistics'
import ChartEchartWithTable from '@/views/charts/charts/ChartEchartWithTable'
import ChartEchartIpHostedDomain from '@/views/charts/charts/ChartEchartIpHostedDomain'
import ChartEchartAppRelateDomain from '@/views/charts/charts/ChartEchartAppRelateDomain'
import ChartActiveIpTable from '@/views/charts/charts/ChartActiveIpTable'
import ChartTimeBar from './charts/ChartTimeBar'
import ChartCategoryBar from './charts/ChartCategoryBar'
import ChartIpOpenPortBar from './charts/ChartIpOpenPortBar'
import ChartTable from './charts/ChartTable'
import ChartAppBasicInfo from '@/views/charts/charts/ChartAppBasicInfo'
import ChartDomainWhois from '@/views/charts/charts/ChartDomainWhois'
import ChartDomainDnsRecord from '@/views/charts/charts/ChartDomainDnsRecord'
import ChartCryptocurrencyEventList from '@/views/charts/charts/ChartCryptocurrencyEventList'
import ChartRelationShip from '@/views/charts/charts/ChartRelationShip'
import ChartSanKey from '@/views/charts/charts/ChartSanKey'
import {
isEcharts,
isEchartsLine,
isSingleValue,
isTable,
isCurrentTable,
isActiveIpTable,
isTitle,
isMap,
getOption,
isEchartsPie,
isEchartsWithTable,
isEchartsWithStatistics,
isEchartsTimeBar,
isEchartsCategoryBar,
isIpOpenPortBar,
isMapLine,
isMapBlock,
isSingleValueWithEcharts,
isSingleValueWithEchartsTemp,
isRelationShip,
isTabs,
isGroup,
isSankey,
isIpBasicInfo,
isIpOpenPort,
isIpHostedDomain,
isDomainWhois,
isDomainDnsRecord,
isCryptocurrencyEventList,
isAppBasicInfo,
isAppRelatedDomain,
isBlock
} from './charts/tools'
import _ from 'lodash'
export default {
name: 'chart',
components: {
ChartSanKey,
ChartCryptocurrencyEventList,
ChartDomainDnsRecord,
ChartDomainWhois,
ChartAppBasicInfo,
ChartActiveIpTable,
ChartTable,
IpBasicInfo,
ChartSingleValue,
Loading,
ChartNoData,
ChartTabs,
ChartMap,
ChartBlock,
ChartTimeBar,
ChartCategoryBar,
ChartIpOpenPortBar,
ChartRelationShip,
ChartGroup,
ChartEchartWithStatistics,
ChartEchart,
ChartEchartWithTable,
ChartEchartIpHostedDomain,
ChartEchartAppRelateDomain
},
props: {
chartInfo: Object,
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
resultType: Object, // 返回数据的类型
queryParams: Object, // 接口请求参数
customChartOption: Object, // 需要自定义echarts的option时传入非必须传入该值时仍需传对应格式的chartData
isFullscreen: Boolean,
loading: Boolean,
panelLock: Boolean,
entity: Object,
isError: Boolean,
table: Object,
orderPieTable: Object
},
computed: {
isNoData () {
return !this.loading && (_.isEmpty(this.chartData) || this.isError) && !this.isSingleValue && !this.isTabs && !this.isDomainDnsRecord && !this.isCryptocurrencyEventList && !this.isActiveIpTable && !this.isMap
},
chartOption () {
if (this.customChartOption) {
return _.cloneDeep(this.customChartOption)
} else {
return getOption(this.chartInfo.type)
}
}
},
methods: {
resize () {
this.$refs['chart' + this.chartInfo.id] && this.$refs['chart' + this.chartInfo.id].resize()
},
showLoading (show) {
this.$emit('showLoading', show)
},
initEchartsWithTable () {
this.$refs['chart' + this.chartInfo.id] && this.$refs['chart' + this.chartInfo.id].initEchartsWithTable(`chart${this.chartInfo.id}`)
}
},
watch: {
chartData: {
deep: true,
handler (n) {
}
}
},
setup (props) {
return {
isEcharts: isEcharts(props.chartInfo.type),
isEchartsLine: isEchartsLine(props.chartInfo.type),
isEchartsTimeBar: isEchartsTimeBar(props.chartInfo.type),
isEchartsCategoryBar: isEchartsCategoryBar(props.chartInfo.type),
isIpOpenPortBar: isIpOpenPortBar(props.chartInfo.type),
isEchartsPie: isEchartsPie(props.chartInfo.type),
isEchartsWithTable: isEchartsWithTable(props.chartInfo.type),
isEchartsWithStatistics: isEchartsWithStatistics(props.chartInfo.type),
isSingleValue: isSingleValue(props.chartInfo.type),
isSingleValueWithEcharts: isSingleValueWithEcharts(props.chartInfo.type),
isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(props.chartInfo.type),
isRelationShip: isRelationShip(props.chartInfo.type),
isTable: isTable(props.chartInfo.type),
isCurrentTable: isCurrentTable(props.chartInfo.type),
isActiveIpTable: isActiveIpTable(props.chartInfo.type),
isMap: isMap(props.chartInfo.type),
isTitle: isTitle(props.chartInfo.type),
isMapLine: isMapLine(props.chartInfo.type),
isMapBlock: isMapBlock(props.chartInfo.type),
isTabs: isTabs(props.chartInfo.type),
isGroup: isGroup(props.chartInfo.type),
isBlock: isBlock(props.chartInfo.type),
isSankey: isSankey(props.chartInfo.type),
isIpBasicInfo: isIpBasicInfo(props.chartInfo.type),
isIpHostedDomain: isIpHostedDomain(props.chartInfo.type),
isIpOpenPort: isIpOpenPort(props.chartInfo.type),
isDomainWhois: isDomainWhois(props.chartInfo.type),
isDomainDnsRecord: isDomainDnsRecord(props.chartInfo.type),
isCryptocurrencyEventList: isCryptocurrencyEventList(props.chartInfo.type),
isAppBasicInfo: isAppBasicInfo(props.chartInfo.type),
isAppRelatedDomain: isAppRelatedDomain(props.chartInfo.type)
}
}
}
</script>

View File

@@ -115,7 +115,7 @@
<script>
import { isTitle, isTabs, isBlock, isTable, isActiveIpTable, isCurrentTable, isGroup, isEchartsWithTable } from './charts/tools'
import ChartError from '@/components/charts/ChartError'
import ChartError from '@/views/charts/ChartError'
import { getNowTime } from '@/utils/date-util'
import { ref } from 'vue'
import { chartTableTopOptions, chartActiveIpTableOrderOptions, chartPieTableTopOptions } from '@/utils/constants'

View File

@@ -44,7 +44,7 @@
<script>
import ChartHeader from './ChartHeader'
import Chart from '@/views/charts/Chart2'
import Chart from '@/views/charts/Chart'
import testData from './charts/testData'
import {
isEcharts,
@@ -75,7 +75,7 @@ import {
isAppRelatedDomain,
isBlock
} from './charts/tools'
import { tableTitleMapping, legendMapping } from '@/components/charts/chart-table-title'
import { tableTitleMapping, legendMapping } from '@/views/charts/charts/chart-table-title'
import { replaceUrlPlaceholder } from '@/utils/tools'
import { getNowTime, getSecond } from '@/utils/date-util'
import { chartPieTableTopOptions, chartTableDefaultPageSize, chartTableTopOptions } from '@/utils/constants'

View File

@@ -7,7 +7,7 @@ import unitConvert from '@/utils/unit-convert'
import * as echarts from 'echarts'
import { lineToSpace } from '@/utils/tools'
import { unitTypes } from '@/utils/constants'
import { legendMapping } from '@/components/charts/chart-table-title'
import { legendMapping } from '@/views/charts/charts/chart-table-title'
import {
categoryBar
} from '@/views/charts/charts/options/bar'

View File

@@ -9,7 +9,7 @@ import { lineToSpace } from '@/utils/tools'
import { unitTypes } from '@/utils/constants'
import chartEchartMixin from './chart-echart-mixin'
import { getOption, isEchartsPie } from './tools'
import { legendMapping } from '@/components/charts/chart-table-title'
import { legendMapping } from '@/views/charts/charts/chart-table-title'
export default {
name: 'ChartEchart',

View File

@@ -7,7 +7,7 @@
<script>
import * as echarts from 'echarts'
import StatisticsLegend from '@/components/charts/StatisticsLegend'
import StatisticsLegend from '@/views/charts/charts/StatisticsLegend'
import {
lineWithStatistics
} from '@/views/charts/charts/options/line'

View File

@@ -36,7 +36,7 @@
<script>
import lodash from 'lodash'
import { ipOpenPortBar } from '@/views/charts/charts/options/bar'
import { getChartColor } from '@/components/charts/chart-options'
import { getChartColor } from '@/views/charts/charts/chart-options'
import * as echarts from 'echarts'
export default {
name: 'ChartIpOpenPortBar',

View File

@@ -67,7 +67,7 @@ import {
import { get } from '@/utils/http'
import { replaceUrlPlaceholder } from '@/utils/tools'
import * as echarts from 'echarts'
import { getOption, getChartColor } from '@/components/charts/chart-options'
import { getOption, getChartColor } from '@/views/charts/charts/chart-options'
export default {
name: 'chartSingleValue',
props: {

View File

@@ -7,7 +7,7 @@ import unitConvert from '@/utils/unit-convert'
import * as echarts from 'echarts'
import { lineToSpace } from '@/utils/tools'
import { unitTypes } from '@/utils/constants'
import { legendMapping } from '@/components/charts/chart-table-title'
import { legendMapping } from '@/views/charts/charts/chart-table-title'
import {
timeBar
} from '@/views/charts/charts/options/bar'

View File

@@ -19,7 +19,7 @@
</template>
<script>
import { getChartColor } from '@/components/charts/chart-options'
import { getChartColor } from '@/views/charts/charts/chart-options'
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
export default {
name: 'StatisticsLegend',

View File

@@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
name: 'Index'
}
</script>
<style scoped>
</style>

View File

@@ -1,487 +0,0 @@
<template>
<div class="outer-box">
<div class="cn-entities">
<el-input
v-model="searchContentTemp"
style="width: 100%; grid-area: 1 / 1 / 1 / 3;"
type="text"
@keyup.enter="enter"
>
<template #prefix>
<span style="padding-left: 4px"><i class="el-icon-search"></i></span>
</template>
</el-input>
<!-- 筛选区域 -->
<left-filter
:top-filter-data="topFilterData"
:bottom-filter-data="bottomFilterData"
@select="select"
@showMore="showMore"
style="grid-area: 2 / 1 / 3 / 2;"
></left-filter>
<!-- 内容区域 -->
<entity-list
:list-data="listData"
:from="from"
:loading="loading"
:page-obj="pageObjRight"
@showDetail="entityDetail"
@pageNo="pageNoRight"
style="grid-area: 2 / 2 / 3 / 3;"
></entity-list>
</div>
</div>
<entity-detail
v-model:show-detail="showDetail"
top="5vh"
:show-close="false"
:entity="currentEntity"></entity-detail>
</template>
<script>
import { entityType, entityFilterType } from '@/utils/constants'
import LeftFilter from '@/components/entities/LeftFilter'
import EntityList from '@/components/entities/EntityList'
import { getEntityFilter, getEntityList, getEntityCount } from '@/utils/api'
import { doubleQuotationToSingle } from '@/utils/tools'
import EntityDetail from '@/components/entities/EntityDetail'
export default {
name: 'EntityExplorer',
data () {
return {
searchContentTemp: '', // 搜索框内的文本内容按回车键后为searchContent赋值
searchContent: '', // 查询语句
searchParams: null, // 搜索参数,格式为[{ name: xxx, value: xxx }, ...]
filterObj: {}, // 被选中的左侧过滤条件
topFilterData: {}, // 左侧上方的过滤列表数据
bottomFilterData: {}, // 左侧下方的过滤列表数据
listData: [], // 右侧实体列表数据
pageObjLeftTop: {
pageNo: 1,
pageSize: 10,
total: 0
},
pageObjLeftBottom: {
pageNo: 1,
pageSize: 10,
total: 0
},
pageObjRight: {
pageNo: 1,
pageSize: 20,
total: 0
},
showDetail: false,
currentEntity: {},
loading: true
}
},
components: {
EntityDetail,
LeftFilter,
EntityList
},
methods: {
enter () {
if (!this.searchContentTemp) {
this.reset()
} else {
this.searchContent = this.searchContentTemp
}
},
async showMore (column) {
let index = 0
switch (column) {
case entityFilterType.ip.country:
case entityFilterType.domain.categoryGroup:
case entityFilterType.app.appCategory: {
this.pageObjLeftTop.pageNo++
break
}
case entityFilterType.ip.asn:
case entityFilterType.domain.reputationLevel:
case entityFilterType.app.appRisk: {
index = 1
this.pageObjLeftBottom.pageNo++
break
}
default: break
}
const { topFilterData, bottomFilterData } = await this.queryFilterData({ column, q: doubleQuotationToSingle(this.searchContent), from: this.from })
if (index === 1) {
this.bottomFilterData = {
...this.bottomFilterData,
data: this.$_.concat(this.bottomFilterData.data, bottomFilterData.data),
hasnotMore: bottomFilterData.length < 10
}
} else {
this.topFilterData = {
...this.topFilterData,
data: this.$_.concat(this.topFilterData.data, topFilterData.data),
hasnotMore: topFilterData.length < 10
}
}
},
async search () {
const vm = this
const params = { from: this.from, q: doubleQuotationToSingle(this.searchContent) }
this.loading = true
try {
this.listData = (await getEntityList({ ...this.pageObjRight, ...params })).map(d => {
return {
...d,
id: window.btoa(unescape(encodeURIComponent(d.ip || d.domainName || d.appName))),
latestSent: null,
latestReceived: null
}
})
this.pageObjRight.total = await getEntityCount(params)
const { topFilterData, bottomFilterData } = await this.queryFilterData(params)
this.topFilterData = topFilterData
this.bottomFilterData = bottomFilterData
} finally {
setTimeout(() => {
vm.loading = false
}, 250)
}
},
/* 重置条件 */
reset () {
this.pageObjLeftTop = {
pageNo: 1,
pageSize: 10
}
this.pageObjLeftBottom = {
pageNo: 1,
pageSize: 10
}
this.pageObjRight = {
pageNo: 1,
pageSize: 20
}
this.searchParams = null
this.searchParams = []
},
async queryFilterData (params) {
let topFilterParams = { ...params, ...this.pageObjLeftTop }
let bottomFilterParams = { ...params, ...this.pageObjLeftBottom }
const keys = Object.keys(this.filterObj)
if (!this.$_.isEmpty(keys)) {
let hasTopColumn = false
let hasBottomColumn = false
keys.forEach(key => {
switch (key) {
case entityFilterType.ip.country:
case entityFilterType.domain.categoryGroup:
case entityFilterType.app.appCategory: {
hasTopColumn = true
topFilterParams = { ...topFilterParams, column: key }
break
}
case entityFilterType.ip.asn:
case entityFilterType.domain.reputationLevel:
case entityFilterType.app.appRisk: {
hasBottomColumn = true
bottomFilterParams = { ...bottomFilterParams, column: key }
break
}
default: break
}
})
if (!hasTopColumn) {
topFilterParams = { ...topFilterParams, column: this.getDefaultTopColumn(this.from) }
}
if (!hasBottomColumn) {
bottomFilterParams = { ...bottomFilterParams, column: this.getDefaultBottomColumn(this.from) }
}
} else {
topFilterParams = { ...topFilterParams, column: this.getDefaultTopColumn(this.from) }
bottomFilterParams = { ...bottomFilterParams, column: this.getDefaultBottomColumn(this.from) }
}
const topFilterListData = await getEntityFilter(topFilterParams) || []
const bottomFilterListData = await getEntityFilter(bottomFilterParams) || []
let topFilterData = { data: topFilterListData, hasnotMore: topFilterListData.length < 10, column: topFilterParams.column }
let bottomFilterData = { data: bottomFilterListData, hasnotMore: bottomFilterListData.length < 10, column: bottomFilterParams.column }
switch (this.from) {
case 'ip': {
topFilterData = { ...topFilterData, icon: 'cn-icon cn-icon-country', title: this.$t('entities.countryOrRegion') }
bottomFilterData = { ...bottomFilterData, icon: 'cn-icon cn-icon-cloud', title: this.$t('entities.asn') }
break
}
case 'domain': {
topFilterData = { ...topFilterData, icon: 'cn-icon cn-icon-category', title: this.$t('entities.groupAndName') }
bottomFilterData = { ...bottomFilterData, icon: 'cn-icon cn-icon-risk', title: this.$t('entities.creditLevel') }
break
}
case 'app': {
topFilterData = { ...topFilterData, icon: 'cn-icon cn-icon-category', title: this.$t('entities.categoryAndSub') }
bottomFilterData = { ...bottomFilterData, icon: 'cn-icon cn-icon-risk', title: this.$t('entities.riskLevel') }
break
}
default: break
}
return { topFilterData, bottomFilterData }
},
getDefaultTopColumn (from) {
let column
switch (from) {
case 'ip': {
column = entityFilterType.ip.country
break
}
case 'domain': {
column = entityFilterType.domain.categoryGroup
break
}
case 'app': {
column = entityFilterType.app.appCategory
break
}
default: break
}
return column
},
getDefaultBottomColumn (from) {
let column = ''
switch (from) {
case 'ip': {
column = entityFilterType.ip.asn
break
}
case 'domain': {
column = entityFilterType.domain.reputationLevel
break
}
case 'app': {
column = entityFilterType.app.appRisk
break
}
default: break
}
return column
},
async select (data, node, index, column) {
if (index === 0) { // 上部过滤
if (node.level === 1) {
const columns = { ...this.filterObj, [column]: data.name }
// 清除二级条件
delete columns[entityFilterType.ip.region]
delete columns[entityFilterType.domain.categoryName]
delete columns[entityFilterType.app.appSubcategory]
this.filterObj = columns
} else if (node.level === 2) {
const columns = { ...this.filterObj, [column]: data.parentName }
// 清除一级条件
let childColumn
switch (column) {
case entityFilterType.ip.country: {
childColumn = entityFilterType.ip.region
break
}
case entityFilterType.domain.categoryGroup: {
childColumn = entityFilterType.domain.categoryName
break
}
case entityFilterType.app.appCategory: {
childColumn = entityFilterType.app.appSubcategory
break
}
default: break
}
columns[childColumn] = data.name
this.filterObj = columns
}
} else if (index === 1) { // 下部过滤
this.filterObj[column] = data.name
}
},
async loadLevel2FilterData (node, parentColumn) {
if (parentColumn) {
const where = {}
where[parentColumn] = node.data.name
let column
switch (parentColumn) {
case entityFilterType.ip.country: {
column = entityFilterType.ip.region
break
}
case entityFilterType.domain.categoryGroup: {
column = entityFilterType.domain.categoryName
break
}
case entityFilterType.app.appCategory: {
column = entityFilterType.app.appSubcategory
break
}
default: break
}
const params = {
q: doubleQuotationToSingle(this.searchContent),
from: this.from,
pageNo: 1,
where,
column
}
const result = await getEntityFilter(params)
return result.map(r => ({ ...r, leaf: true, parentName: node.data.name }))
} else {
return []
}
},
pageNoRight (val) {
this.pageObjRight.pageNo = val
this.search()
},
entityDetail (entity, tabs) {
this.typeName = `${this.from.toLowerCase()}EntityDetail`
this.currentEntity = entity
this.showDetail = true
}
},
watch: {
/* entity类型切换时分页、搜索信息重置 */
from (n) {
this.reset()
},
/* 搜索框searchContent、左侧过滤条件filterObj互相联动
* 监听filterObj改动将改动同步给searchParams
* 监听searchContent改动将改动同步给searchParams
* 监听searchParams将改动同步给filterObj、searchContent之一并重新请求接口获取左侧过滤条件和右侧entity列表
* */
filterObj: {
deep: true,
handler (n) {
if (n) {
const searchParams = this.$_.cloneDeep(this.searchParams)
let change = false
Object.keys(n).forEach(key => {
let containKey = false
searchParams.forEach(item => {
if (item.name === key) {
containKey = true
if (item.value !== n[key]) {
change = true
item.value !== n[key] && (item.value = n[key])
}
}
})
if (!containKey) {
change = true
const name = key
const value = n[key]
const param = { name, value }
searchParams.push(param)
}
})
if (change) {
this.searchParams = searchParams
}
}
}
},
searchContent (n) {
if (n) {
const paramsArr = n.split(/\s[aA][nN][dD]\s/)
const paramsObj = {}
let change = false
paramsArr.forEach(string => {
const param = string.split('=')
if (param.length > 1) {
let value = param[1].trim()
const valueArr = value.split('"')
if (valueArr.length > 2) {
value = valueArr[1].trim()
}
paramsObj[param[0].trim()] = value
}
})
const searchParams = this.$_.cloneDeep(this.searchParams)
const newSearchParams = []
const keys = Object.keys(paramsObj)
keys.forEach(key => {
newSearchParams.push({ name: key, value: paramsObj[key] })
let containKey = false
searchParams.forEach(item => {
if (item.name === key) {
containKey = true
if (item.value !== paramsObj[key]) {
change = true
item.value = paramsObj[key]
}
}
})
if (!containKey) {
change = true
searchParams.push({ name: key, value: paramsObj[key] })
}
})
if (newSearchParams.length !== searchParams.length) {
this.searchParams = newSearchParams
} else if (change) {
this.searchParams = searchParams
}
} else {
this.reset()
}
this.searchContentTemp !== n && (this.searchContentTemp = n)
},
searchParams: {
deep: true,
handler (n) {
if (n) {
let fromInput = false // input内容改变导致的变化
let fromFilter = false // 左侧filter过滤条件改变导致的变化
const filterKeys = Object.keys(this.filterObj)
if (n.length === 0) {
this.searchContentTemp = ''
this.searchContent = ''
this.filterObj = {}
} else if (filterKeys.length !== n.length) {
fromInput = true
} else {
fromFilter = true
}
if (fromInput) { // 是input导致的改变则同步给filter
const filterObj = {}
n.forEach(item => {
filterObj[item.name] = item.value
})
this.filterObj = filterObj
}
if (fromFilter) { // 是filter导致的改变则同步给input
let searchContent = ''
n.forEach(item => {
if (searchContent) {
searchContent += ' AND '
}
searchContent += `${item.name}="${item.value}"`
})
this.searchContent = searchContent
}
// 请求接口获取左侧过滤条件和右侧entity列表
this.search()
}
}
}
},
computed: {
from () {
return this.$store.getters.from
}
},
async mounted () {
this.$store.commit('showEntityTypeSelector', true)
this.searchParams = []
},
setup () {
return {
entityType // 所有entity类型用于header下拉框选择
}
},
beforeUnmount () {
this.$store.commit('entityTypeChange', Object.keys(entityType)[0])
this.$store.commit('showEntityTypeSelector', false)
}
}
</script>

View File

@@ -133,14 +133,14 @@
</div>
</div>
<div class="overview-map overview-map--app">
<chart2
<chart
:chart-info="chart"
:chart-data="chartData"
:entity="entityCopy"
:query-params="getQueryParams"
:hide-header="true"
@getCurrentTimeRange="getCurrentTimeRange"
></chart2>
></chart>
</div>
</template>
@@ -149,7 +149,7 @@ import { api } from '@/utils/api'
import entityDetailMixin from './entityDetailMixin'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import Chart2 from '@/views/charts/Chart2'
import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import { get } from '@/utils/http'
@@ -158,7 +158,7 @@ export default {
name: 'App',
mixins: [entityDetailMixin],
components: {
Chart2,
Chart,
ChartSingleValue
},
data () {

View File

@@ -127,7 +127,7 @@
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
<div class="row__content">{{entityData.securityNum || '-'}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="security in entityData.securityList">
<div class="overview__row overview__row--small-font" v-for="(security, i) in entityData.securityList" :key="i">
<div class="row__label row__label--width160">{{security.startTime}}</div>
<div class="row__content row__content--width200">
<div class="alert-level-tag alert-level-tag--high">{{security.securitySeverity}}</div>
@@ -141,14 +141,14 @@
</div>
</div>
<div class="overview-map">
<chart2
<chart
:chart-info="chart"
:chart-data="chartData"
:entity="entityCopy"
:query-params="getQueryParams"
:hide-header="true"
@getCurrentTimeRange="getCurrentTimeRange"
></chart2>
></chart>
</div>
</template>
@@ -158,14 +158,14 @@ import { api } from '@/utils/api'
import entityDetailMixin from './entityDetailMixin'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import Chart2 from '@/views/charts/Chart2'
import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import { get } from '@/utils/http'
export default {
name: 'Domain',
components: {
ChartSingleValue,
Chart2
Chart
},
mixins: [entityDetailMixin],
data () {

View File

@@ -125,14 +125,14 @@
</div>
</div>
<div class="overview-map overview-map--ip">
<chart2
<chart
:chart-info="chart"
:chart-data="chartData"
:entity="entityCopy"
:query-params="getQueryParams"
:hide-header="true"
@getCurrentTimeRange="getCurrentTimeRange"
></chart2>
></chart>
</div>
</template>
@@ -142,7 +142,7 @@ import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
import { api } from '@/utils/api'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import Chart2 from '@/views/charts/Chart2'
import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import { get } from '@/utils/http'
@@ -150,7 +150,7 @@ export default {
name: 'Ip',
mixins: [entityDetailMixin],
components: {
Chart2,
Chart,
ChartSingleValue
},
data () {

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'
import { get } from '@/utils/http'
import * as echarts from 'echarts'
import { entityListLineOption } from '@/components/charts/chart-options'
import { entityListLineOption } from '@/views/charts/charts/chart-options'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'

View File

@@ -2,7 +2,7 @@ import _ from 'lodash'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import * as echarts from 'echarts'
import { entityListLineOption } from '@/components/charts/chart-options'
import { entityListLineOption } from '@/views/charts/charts/chart-options'
import { riskLevelMapping, unitTypes } from '@/utils/constants'
export default {