diff options
| author | @changcode <[email protected]> | 2022-02-14 17:42:21 +0800 |
|---|---|---|
| committer | @changcode <[email protected]> | 2022-02-14 17:42:21 +0800 |
| commit | fa9b153bedee2da7b8e0941c9725f3bba1d9999f (patch) | |
| tree | 12c9a3d4f1eff3557930177c302b38541d372c13 | |
| parent | 83924a8a95082fb2dd0b3f38b3dd6eb527054148 (diff) | |
| parent | 88b1fa3bcdb394ec1d02927383393e005ba45dec (diff) | |
Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev22.01
32 files changed, 342 insertions, 5686 deletions
diff --git a/src/assets/css/components/components/charts/panel.scss b/src/assets/css/components/components/charts/panel.scss deleted file mode 100644 index 77c31ec6..00000000 --- a/src/assets/css/components/components/charts/panel.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/charts/ChartMap.vue b/src/components/charts/ChartMap.vue deleted file mode 100644 index 573f993b..00000000 --- a/src/components/charts/ChartMap.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/ChartSingleValue.vue b/src/components/charts/ChartSingleValue.vue deleted file mode 100644 index 5721bd84..00000000 --- a/src/components/charts/ChartSingleValue.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/ChartTable.vue b/src/components/charts/ChartTable.vue deleted file mode 100644 index 523e692b..00000000 --- a/src/components/charts/ChartTable.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/ChartTableActiveIp.vue b/src/components/charts/ChartTableActiveIp.vue deleted file mode 100644 index bde28488..00000000 --- a/src/components/charts/ChartTableActiveIp.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/ChartTablePagination.vue b/src/components/charts/ChartTablePagination.vue deleted file mode 100644 index 521d861c..00000000 --- a/src/components/charts/ChartTablePagination.vue +++ /dev/null @@ -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>/ {{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> diff --git a/src/components/charts/ChartTitle.vue b/src/components/charts/ChartTitle.vue deleted file mode 100644 index f790cfc5..00000000 --- a/src/components/charts/ChartTitle.vue +++ /dev/null @@ -1,9 +0,0 @@ -<template> - <div class="cn-chart cn-chart__title"></div> -</template> - -<script> -export default { - name: 'ChartTitle' -} -</script> diff --git a/src/components/charts/EchartsFrame.vue b/src/components/charts/EchartsFrame.vue deleted file mode 100644 index bc2acb6c..00000000 --- a/src/components/charts/EchartsFrame.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/PieTable.vue b/src/components/charts/PieTable.vue deleted file mode 100644 index 2615da28..00000000 --- a/src/components/charts/PieTable.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/chart-options.js b/src/components/charts/chart-options.js deleted file mode 100644 index 460c4e6d..00000000 --- a/src/components/charts/chart-options.js +++ /dev/null @@ -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 -} diff --git a/src/components/entities/EntityList.vue b/src/components/entities/EntityList.vue index 35bea4cb..1fa3c9bc 100644 --- a/src/components/entities/EntityList.vue +++ b/src/components/entities/EntityList.vue @@ -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' diff --git a/src/router/index.js b/src/router/index.js index 30bc4aba..580d0ec9 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -11,6 +11,10 @@ const routes = [ component: () => import('@/views/entityExplorer/EntityDetail') }, { + path: '/detections', + component: () => import('@/views/detections/Index') + }, + { path: '/', component: () => import('@/components/layout/Home'), children: [ diff --git a/src/views/charts/Chart.vue b/src/views/charts/Chart.vue index 48bdd627..5ce07b18 100644 --- a/src/views/charts/Chart.vue +++ b/src/views/charts/Chart.vue @@ -1,630 +1,231 @@ <template> - <!-- 标题 --> - <div - v-if="isTitle" - class="cn-chart cn-chart__title" - :style="computePosition">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</div> - <!-- Tabs --> - <el-tabs - class="cn-chart cn-chart__tabs" - v-else-if="isTabs" - v-model="activeTab" - @tab-click="changeTab" - :style="computePosition" - :ref="`chart-${chart.id}`" - > - <el-tab-pane - v-for="tab in chartInfo.children" - :label="tab.i18n ? $t(tab.i18n) : tab.name" :name="`${tab.id}`" - :key="tab.id" - :ref="`chart-${chart.id}`" - > - <template v-for="chart in tab.children"> - <chart - v-if="activeTab == tab.id" - :key="Chart.id" - :chart="Chart" - :time-filter="timeFilter" - :ref="`chart-${Chart.id}`" - :entity="entity" - @getCurrentTimeRange="getCurrentTimeRange" - ></chart> - </template> - </el-tab-pane> - </el-tabs> - <!-- 地图 --> - <chart-map - v-else-if="isMap" - :style="computePosition" - :loading="loading" - :hide-header="hideHeader" - > - <template #chartErrorInfo> - <chart-error - :isError="isError" - :errorInfo="errorInfo" - > - </chart-error> - </template> - <template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template> - <template #operations> - <span class="header__operation-btn" v-show="showMapBackButton" @click="mapBack"><i class="cn-icon el-icon-back"></i></span> - <el-popover trigger="hover" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark"> - <template #reference> - <span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span> - </template> - </el-popover> - <span class="header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span> - </template> - <template #default> - <template v-if="isIpBasicInfo"> - <el-descriptions :column="1"> - <el-descriptions-item label="ASN:">{{detailData.asn || '-'}}</el-descriptions-item> - <el-descriptions-item label="AS Org:">{{detailData.asOrganization || '-'}}</el-descriptions-item> - <el-descriptions-item :label="$t('entities.asSubnet') + ':'">{{detailData.asSubnet || '-'}}</el-descriptions-item> - <el-descriptions-item label="ISP:">{{detailData.isp || '-'}}</el-descriptions-item> - <el-descriptions-item label="DNS PTR:">{{detailData.dnsPtr || '-'}}</el-descriptions-item> - </el-descriptions> - <div class="chart-location"> - <el-descriptions :column="1"> - <el-descriptions-item :label="$t('overall.location') + ':'">{{location}}</el-descriptions-item> - </el-descriptions> - <div class="chart-drawing" style="padding: 0 36px 30px 0;" :id="`chart${chartInfo.id}`"></div> - </div> - </template> - <template v-else> - <div class="chart-drawing" :id="`chart${chartInfo.id}`"></div> - </template> - </template> - </chart-map> - <!-- echarts类的图,如饼图、柱状图、折线图等 --> - <echarts-frame - v-else-if="isEcharts" - :layout="layout" - :style="computePosition" - :chartInfo="chartInfo" - :loading="loading" - :no-data="noData" - > - <template #chartErrorInfo> - <chart-error - :isError="isError" - :errorInfo="errorInfo" - > - </chart-error> - </template> - <template #title v-if="layout.indexOf(layoutConstant.HEADER) > -1" > - {{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}} - </template> - <template #operations v-if="layout.indexOf(layoutConstant.HEADER) > -1"> - <div class="header__operation header__operation--echarts" v-if="chart.type === 31"> - <el-select - size="mini" - v-model="orderPieTable" - class="option__select select-column" - placeholder="" - popper-class="option-popper is-light" - @change="orderPieTableChange" - > - <el-option v-for="item in chartPieTableTopOptions" :key="item.value" :value="item.value"> {{item.name}}</el-option> - </el-select> - </div> - <el-popover trigger="hover" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark"> - <template #reference> - <span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span> - </template> - </el-popover> - <span class="header__operation-btn" @click="refresh" ><i class="cn-icon cn-icon-refresh"></i></span> - </template> - <template #default> - <!-- IP详情 开放端口 --> - <template v-if="isIpOpenPort"> - <div class="ip-detail__open-port"> - <div class="open-port__table"> - <div style="height: 100%; overflow: hidden auto;"> - <div class="open-port__table-row open-port__table-row--header"> - <div class="open-port__table-cell" style="min-width: 100px;">Port</div> - <div class="open-port__table-cell" style="min-width: 130px;">{{$t('overall.protocol')}}</div> - <div class="open-port__table-cell">Banner</div> - <div class="open-port__table-cell" style="min-width: 200px;">Update at</div> - </div> - <div class="open-port__table-row" v-for="(data, index) in detailData" :key="index"> - <div class="open-port__table-cell">{{data.port || '-'}}</div> - <div class="open-port__table-cell">{{data.protocol || '-'}}</div> - <div class="open-port__table-cell">{{data.banner || '-'}}</div> - <div class="open-port__table-cell">{{data.utime || '-'}}</div> - </div> - </div> - </div> - <div class="open-port__chart"> - <div class="open-port__chart-title">{{$t('overall.protocolsStatistics')}}</div> - <div class="open-port__chart-body chart-drawing" :id="`chart${chartInfo.id}`"></div> - </div> - </div> - </template> - <!-- IP详情 托管域名 --> - <template v-else-if="isIpHostedDomain"> - <div class="ip-detail__hosted-domain"> - <div class="hosted-domain__list"> - <div class="hosted-domain__list-title">{{$t('overall.domain')}}</div> - <div class="hosted-domain__list-body"> - <div class="hosted-domain__list-row" v-for="(data, i) in detailData" :key="i">{{data}}</div> - </div> - </div> - <div class="hosted-domain__chart"> - <div> - <div class="hosted-domain__chart-title">{{$t('entities.byCategory')}}</div> - <div class="chart-drawing" :id="`chart${chartInfo.id}-0`"></div> - </div> - <div> - <div class="hosted-domain__chart-title">{{$t('entities.byCredit')}}</div> - <div class="chart-drawing" :id="`chart${chartInfo.id}-1`"></div> - </div> - </div> - </div> - </template> - <!-- APP详情 关联域名 --> - <template v-else-if="isAppRelatedDomain"> - <div class="app-detail__related-domain"> - <div class="related-domain__list"> - <div class="related-domain__list-title">{{$t('overall.domain')}}</div> - <div class="related-domain__list-body"> - <div class="related-domain__list-row" v-for="(data, i) in detailData" :key="i"><i class="cn-icon cn-icon-domain"></i> {{data}}</div> - </div> - </div> - <div class="related-domain__chart"> - <div> - <div class="related-domain__chart-title">{{$t('entities.byCategory')}}</div> - <div class="chart-drawing" :id="`chart${chartInfo.id}-0`"></div> - </div> - <div> - <div class="related-domain__chart-title">{{$t('entities.byCredit')}}</div> - <div class="chart-drawing" :id="`chart${chartInfo.id}-1`"></div> - </div> - </div> - </div> - </template> - <template v-else-if="isSankey"> - <div class="sankey-box"> - <div class="chart-drawing" :id="`chart${chartInfo.id}`"></div> - <div class="sankey__label" style="left: 5%;">{{$t('entities.inboundLinkId')}}</div> - <div class="sankey__label" style="left: 50%;">{{entity.ip || entity.domain || entity.app}}</div> - <div class="sankey__label" style="right: 5%; transform: translateX(50%)">{{$t('entities.outboundLinkId')}}</div> - </div> - </template> - <div v-else class="chart-drawing" :id="`chart${chartInfo.id}`"></div> - </template> - <template #footer v-if="layout.indexOf(layoutConstant.FOOTER) > -1"> - <!-- 带Table的饼图,展示Table --> - <template v-if="isEchartsWithTable"> - <pie-table :tableData="pieTableData" ref="pieTable" :chartInfo="chartInfo" :time-filter="timeFilter" :order="orderPieTable"/> - </template> - <template v-else-if="isEchartsWithStatistics"> - <statistics-legend :data="statisticsData" :chart-info="chartInfo" @toggleLegend="toggleStatisticsLegend"></statistics-legend> - </template> - </template> - </echarts-frame> - <!-- 单值图 --> - <single-value - v-else-if="isSingleValue" - :type="chartInfo.type" - :style="computePosition" - :icon="singleValue.icon" - :color="singleValue.color" - :loading="loading" - > - <template #chartErrorInfo> - <chart-error - :isError="isError" - :errorInfo="errorInfo" - > - </chart-error> - </template> - <template #title> - <span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span> - <span - v-if="chartInfo.params && chartInfo.params.as" - class="ip-detail-as" - > - as <span style="text-transform: capitalize">{{chartInfo.params.as}}</span> - </span> - </template> - <template #data> - <span>{{handleSingleValue[0] || handleSingleValue[0] === 0 ? handleSingleValue[0] : '-'}}</span> - <span class="single-value__unit">{{handleSingleValue[1]}}</span> - </template> - <template #chart> - <div class="chart-drawing" :id="`chart${chartInfo.id}`"></div> - </template> - </single-value> - <!-- 表格:Cryptocurrency活跃IP --> - <chart-table-active-ip - v-else-if="isActiveIpTable" - :table-data="activeIpTable.tableData" - :style="computePosition" - :loading="loading" - :no-data="noData" - > - <template #chartErrorInfo> - <chart-error - :isError="isError" - :errorInfo="errorInfo" - > - </chart-error> - </template> - <template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template> - <template #operations> - <el-popover trigger="hover" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark"> - <template #reference> - <span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span> - </template> - </el-popover> - <div class="header__operation header__operation--table"> - <el-select - size="mini" - v-model="activeIpTable.orderBy" - class="option__select select-column" - :placeholder="$t('overall.field')" - popper-class="option-popper" - @change="activeIpTableLimitChange" - > - <template v-for="item in chartActiveIpTableOrderOptions" :key="item"> - <el-option :value="item">{{item}}</el-option> - </template> - </el-select> - </div> - <span class="header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span> - </template> - </chart-table-active-ip> - <!-- 表格 --> - <chart-table - v-else-if="isTable" - :table-columns="table.tableColumns" - :table-data="table.currentPageData" - :style="computePosition" - :loading="loading" - :no-data="noData" - > - <template #chartErrorInfo> - <chart-error - :isError="isError" - :errorInfo="errorInfo" - > - </chart-error> - </template> - <template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template> - <template #operations> - <el-popover trigger="hover" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark"> - <template #reference> - <span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span> - </template> - </el-popover> - <div class="header__operation header__operation--table"> - <el-select - size="mini" - v-model="table.limit" - class="option__select select-topn" - placeholder="" - popper-class="option-popper" - @change="tableLimitChange" - > - <el-option v-for="item in chartTableTopOptions" :key="item" :value="item">TOP {{item}}</el-option> - <template #prefix>TOP </template> - </el-select> - </div> - <div class="header__operation header__operation--table"> - <el-select - size="mini" - v-model="table.orderBy" - class="option__select select-column" - :placeholder="$t('overall.field')" - popper-class="option-popper" - @change="tableLimitChange" - > - <template v-for="(item, index) in table.tableColumns" :key="item.prop"> - <el-option v-if="index > 0" :value="item.prop">{{item.prop}}</el-option> - </template> - </el-select> - </div> - <span class="header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span> -<!-- <div class="header__operation header__operation--table"> - <span class="option__button"><i class="cn-icon cn-icon-style"></i></span> - <div class="icon-group-divide"></div> - <span class="option__button"><i class="cn-icon cn-icon-dropdown"></i></span> - </div> - <div class="header__operation header__operation--table"> - <span class="option__button"><i class="cn-icon cn-icon-full-screen"></i></span> - </div>--> - </template> - <template #footer> - <chart-table-pagination - ref="tablePagination" - :total="table.tableData.length" - @pageJump="pageJump" - ></chart-table-pagination> - </template> - </chart-table> - <!-- group --> - <div - v-else-if="isGroup" - class="cn-chart cn-chart__group" - :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> - <span - v-if="chartInfo.params && chartInfo.params.as" - class="ip-detail-as" - > - as <span style="text-transform: capitalize">{{chartInfo.params.as}}</span> - </span> - </div> - </div> - <div class="cn-chart__body"> - <template v-for="chart in chartInfo.children" :key="Chart.id"> - <chart - :chart="Chart" - :time-filter="timeFilter" - :ref="`chart-${Chart.id}`" - :entity="entity" - :parent-data="groupData" - :from-block="fromBlock" - @getChartCurrentTimeRange="getChartCurrentTimeRange" - ></chart> - </template> - </div> - </div> - <!-- block --> - <div - v-else-if="isBlock" - class="cn-chart cn-chart__block" - :style="computePosition" - :id="chartInfo.params && chartInfo.params.anchorPoint" - > - <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 style="top: 18px;" class="panel__time" v-if="chartInfo.params && chartInfo.params.showTimeTool"> - <DateTimeRange class="date-time-range" :start-time="chartTimeFilter.startTime" :end-time="chartTimeFilter.endTime" ref="dateTimeRange" @change="reload"/> - <TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="chartTimeFilter.endTime"/> - </div> - </div> - </div> - <div class="cn-chart__body"> - <template v-for="chart in chartInfo.children" :key="Chart.id"> - <chart - :chart="Chart" - :time-filter="chartTimeFilter" - :ref="`chart-${Chart.id}`" - :entity="entity" - :parent-data="groupData" - :from-block="true" - @getChartCurrentTimeRange="getChartCurrentTimeRange" - ></chart> - </template> - </div> - </div> - <!-- 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.registrar || '-'}}</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.postcode || '-'}}</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.country || '-'}}</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.createTime ? parseMsDate(detailData.createTime) : '-'}}</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.expirationTime ? parseMsDate(detailData.expirationTime) : '-'}}</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> - <!-- Cryptocurrency EventList :近期挖矿事件--> - <div v-else-if="isCryptocurrencyEventList" - class="cn-chart cn-chart__table" - :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> - - <span class="header__operations header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span> - </div> - <div class="chart__loading" v-show="loading"> - <i class="el-icon-loading"></i> - </div> - <div class="cn-chart__body" v-no-data="noData"> - <div class="crypto-eventList__record"> - <div class="record__table"> - <div style="height: 100%; overflow: hidden auto;"> - <div class="record__table-row" v-for="(data, index) in croptyEventList" :key="index"> - <div class="record__table-cell"> - <div class="circle1" style=""></div> - </div> - <div class="record__table-cell"> - {{data.message || '-'}}:{{data.serverIP || '-'}}<br/> - <span class="record_second" > {{data.time || '-'}} {{data.clientIP || '-'}} </span> - <div class="record_second arrow arrow-hor right"> </div> - <span class="record_second"> {{data.serverIP || '-'}}</span> - </div> + <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> - </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.name || '-'}}</el-descriptions-item> - <el-descriptions-item :label="$t('overall.appFullName') + ':'">{{detailData.allName || '-'}}</el-descriptions-item> - <el-descriptions-item :label="$t('overall.technology') + ':'">{{detailData.tech || '-'}}</el-descriptions-item> - <el-descriptions-item :label="$t('overall.remark') + ':'">{{detailData.description || '-'}}</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>{{detailData.category ? detailData.category : '-'}}</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>{{detailData.subcategory ? detailData.subcategory : '-'}}</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>{{detailData.risk ? detailData.risk : '-'}}</span> - </template> - </single-value> - </div> - </div> - </div> + </template> </div> </template> <script> -import * as echarts from 'echarts' -import * as am4Core from '@amcharts/amcharts4/core' -import * as am4Maps from '@amcharts/amcharts4/maps' -import { ref, shallowRef } from 'vue' -import { tableTitleMapping, legendMapping } from '@/components/charts/chart-table-title' +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, - getTypeCategory, - getLayout, - layoutConstant, + isEchartsPie, isEchartsWithTable, isEchartsWithStatistics, isEchartsTimeBar, isEchartsCategoryBar, + isIpOpenPortBar, isMapLine, isMapBlock, isSingleValueWithEcharts, @@ -641,1748 +242,117 @@ import { isCryptocurrencyEventList, isAppBasicInfo, isAppRelatedDomain, - getChartColor, chartBarColor, timeVerticalFormatter, timeHorizontalFormatter, - categoryHorizontalFormatter, categoryVerticalFormatter, getCharBartColor, isBlock -} from '@/components/charts/chart-options' -import ChartError from '@/components/charts/ChartError' -import EchartsFrame from '@/components/charts/EchartsFrame' -import SingleValue from '@/components/charts/ChartSingleValue' -import ChartTable from '@/components/charts/ChartTable' -import ChartTableActiveIp from '@/components/charts/ChartTableActiveIp' -import ChartMap from '@/components/charts/ChartMap' -import PieTable from '@/components/charts/PieTable' -import StatisticsLegend from '@/components/charts/StatisticsLegend' -import ChartTablePagination from '@/components/charts/ChartTablePagination' -import unitConvert, { getUnitType, valueToRangeValue } from '@/utils/unit-convert' -import { chartTableDefaultPageSize, chartTableTopOptions, chartActiveIpTableOrderOptions, storageKey, chartPieTableTopOptions, unitTypes } from '@/utils/constants' -import { get, post } from '@/utils/http' -import { replaceUrlPlaceholder, getCapitalGeo, getGeoData, lineToSpace } from '@/utils/tools' -import { HeatLegend } from '@/components/amcharts/heatLegend' -import DateTimeRange from '@/components/common/TimeRange/DateTimeRange' -import TimeRefresh from '@/components/common/TimeRange/TimeRefresh' - -import * as L from 'leaflet' -import 'leaflet/dist/leaflet.css' -import icon from 'leaflet/dist/images/marker-icon.png' -import iconShadow from 'leaflet/dist/images/marker-shadow.png' -import { getNowTime } from '@/utils/date-util' + isBlock +} from './charts/tools' +import _ from 'lodash' export default { - name: 'Chart', - props: { - chart: Object, // 图表对象,包括id、name、type等数据 - timeFilter: Object, - parentData: Object, - fromBlock: Boolean, - hideHeader: Boolean, - entity: { - type: Object, - default: () => {} - } - }, + name: 'chart', components: { - EchartsFrame, - SingleValue, - ChartTablePagination, + ChartSanKey, + ChartCryptocurrencyEventList, + ChartDomainDnsRecord, + ChartDomainWhois, + ChartAppBasicInfo, + ChartActiveIpTable, ChartTable, - ChartTableActiveIp, - PieTable, - StatisticsLegend, + IpBasicInfo, + ChartSingleValue, + Loading, + ChartNoData, + ChartTabs, ChartMap, - ChartError, - DateTimeRange, - TimeRefresh + ChartBlock, + ChartTimeBar, + ChartCategoryBar, + ChartIpOpenPortBar, + ChartRelationShip, + ChartGroup, + ChartEchartWithStatistics, + ChartEchart, + ChartEchartWithTable, + ChartEchartIpHostedDomain, + ChartEchartAppRelateDomain }, - data () { - return { - table: { - pageSize: chartTableDefaultPageSize, - limit: chartTableTopOptions[0], // top-n - orderBy: 'sessions', - tableColumns: [], // table字段 - tableData: [], // table的所有数据 - currentPageData: [] // table当前页的数据 - }, - - activeIpTable: { - orderBy: 'machine', - tableData: [ - { - name: '192.168.20.21', - num: 111 - - }, { - name: '192.168.20.22', - num: 345 - }, { - name: '192.168.20.23', - num: 111 - - }, { - name: '192.168.20.24', - num: 345 - }, { - name: '192.168.20.25', - num: 111 - - }, { - name: '192.168.20.26', - num: 345 - } - ] // table的所有数据 - }, - pieTableData: [], - singleValue: { - value: '-', - icon: '', - color: '' - }, - showMapBackButton: false, // 下钻之后控制是否显示返回上一层按钮 - standaloneTimeRange: { // 单个图表刷新时,重新获取时间范围,且不影响到其他图 - use: false, - startTime: '', - endTime: '' - }, - queryTimeRange: { // 实际查询接口时使用的时间 - startTime: '', - endTime: '' - }, - activeTab: '', - groupData: '', // group类型的查询数据,用于传递给子chart,子chart通过params.dataKey取值 - detailData: '', // 详情类型图表的数据 - croptyEventList: [], - statisticsData: [], - orderPieTable: chartPieTableTopOptions[0].value, - selectPieChartName: '', - allSelectPieChartName: [], - chartOption: null, - loading: true, - noData: false, // 查询结果为空 - noData0: false, // 单chart内含多图表时使用 - noData1: false, - throttle: null, // 节流器 - isError: false, // 接口响应是否报错 - errorInfo: '', // 接口具体错误信息 - polygonSeries: null, // 世界地图series - countrySeries: null, // 下钻国家series - baseMapSeriesName: ['Container', 'MapChart'], - mapPictureUrl: '/Tiles/{z}/{x}/{y}.png' - } + 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 }, - methods: { - initChart () { - this.loading = true - if (this.standaloneTimeRange.use) { - this.queryTimeRange = { startTime: parseInt(this.standaloneTimeRange.startTime / 1000), endTime: parseInt(this.standaloneTimeRange.endTime / 1000) } - } else if (this.timeFilter) { - this.queryTimeRange = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000) } - } else { - this.queryTimeRange = { startTime: parseInt(this.chartTimeFilter.startTime / 1000), endTime: parseInt(this.chartTimeFilter.endTime / 1000) } - } - try { - const chartParams = this.chartInfo.params - if (this.isMap) { - this.initMap(`chart${this.chartInfo.id}`) - if (chartParams) { - this.isIpBasicInfo ? this.loadLeafletMap() : this.loadAm4ChartMap(this.polygonSeries) - } - // TODO 优化:缓存地图,重新查询时只更改数据,不再次初始化 - } else if (this.isEcharts) { - if (this.isIpHostedDomain || this.isAppRelatedDomain) { - const dom = document.getElementById(`chart${this.chartInfo.id}-0`) - const dom2 = document.getElementById(`chart${this.chartInfo.id}-1`) - !this.myChart && (this.myChart = echarts.init(dom)) - !this.myChart2 && (this.myChart2 = echarts.init(dom2)) - } else { - const dom = document.getElementById(`chart${this.chartInfo.id}`) - !this.myChart && (this.myChart = echarts.init(dom)) - } - this.chartOption = this.$_.cloneDeep(getOption(this.chart.type)) - if (chartParams) { - if (this.isEchartsWithTable) { - this.initEchartsWithPieTable(chartParams) - } else if (this.isEchartsWithStatistics) { - this.initEchartsWithStatistics(chartParams) - } else if (this.isRelationShip) { - this.initRelationShip(chartParams) - } else if (this.isSankey) { - this.initSankey(chartParams) - } else if (this.isIpOpenPort) { - this.initIpOpenPort(chartParams) - } else if (this.isIpHostedDomain) { - this.initIpHostedDomain(chartParams) - } else if (this.isAppRelatedDomain) { - this.initAppRelatedDomain(chartParams) - } else if (this.isEchartsTimeBar) { - this.initEchartsTimeBar(chartParams) - } else if (this.isEchartsCategoryBar) { - this.initEchartsCategoryBar(chartParams) - } else { - this.initECharts(chartParams) - } - } - } else if (this.isActiveIpTable) { - this.initChartActiveIpTable(chartParams) - } else if (this.isTable) { - if (chartParams) { - this.initChartTable(chartParams) - } - } else if (this.isSingleValue) { - if (chartParams) { - this.singleValue.icon = chartParams.icon - if (chartParams.color) { - this.singleValue.color = chartParams.color - } - const gotData = new Promise(resolve => { - let result = '' - if (chartParams.dataKey) { - if (this.parentData && (this.parentData[chartParams.dataKey] || this.parentData[chartParams.dataKey] === 0)) { - result = this.parentData[chartParams.dataKey] - } else { - this.noData = true - } - resolve(result) - } else { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - result = response.data.result - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - resolve(result) - }) - } - }) - gotData.then(result => { - if (this.isSingleValueWithEcharts) { // 带曲线的单值图 - const dom = document.getElementById(`chart${this.chartInfo.id}`) - !this.myChart && (this.myChart = echarts.init(dom)) - this.chartOption = this.$_.cloneDeep(getOption(this.chart.type)) - const seriesTemplate = this.chartOption.series[0] - this.chartOption.series = result.map((r, i) => { - return { - ...seriesTemplate, - name: r.legend, - data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType]), - lineStyle: { - color: getChartColor[i] - } - } - }) - this.myChart.setOption(this.chartOption) - this.singleValue.value = result[0].values[result[0].values.length - 1][1] - - /* const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), ...this.entity } - const dom = document.getElementById(`chart${this.chartInfo.id}`) - !this.myChart && (this.myChart = echarts.init(dom)) - this.chartOption = this.$_.cloneDeep(getOption(this.chart.type)) - const seriesTemplate = this.chartOption.series[0] - - get(replaceUrlPlaceholder(chartParams.urlLine, queryParams)).then(response => { - if (response.code === 200) { - this.chartOption.series = response.data.result.map((r, i) => { - return { - ...seriesTemplate, - name: r.legend, - data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType]), - lineStyle: { - color: getChartColor[i] - } - } - }) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - this.myChart.setOption(this.chartOption) - }) */ - } else { - this.singleValue.value = result - this.loading = false - } - }).catch(() => { - this.singleValue.value = '' - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - } - } else if (this.isTabs) { - if (!this.$_.isEmpty(this.chartInfo.children)) { - this.activeTab = `${this.chartInfo.children[0].id}` - } - } else if (this.isGroup) { - if (chartParams && chartParams.url) { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - this.groupData = 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 - }) - } - } 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 - }) - } else if (this.isCryptocurrencyEventList) { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (response.data.result.length > 0) { - this.croptyEventList = response.data.result - } else { - this.noData = true - } - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - }).catch(e => { - this.isError = true - this.errorInfo = e - }).finally(() => { - setTimeout(() => { this.loading = false }, 250) - }) - } else if (this.isAppBasicInfo) { - const queryParams = { appName: this.entity.appName } - 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) - } - }, - - reloadChart () { - this.initChart() - this.$nextTick(() => { - if (!this.$_.isEmpty(this.chart.children)) { - this.chart.children.forEach(chart => { - this.$refs[`chart-${chart.id}`].reloadChart() - }) - } - }) - }, - timeRefreshChange () { - if (!this.$refs.dateTimeRange.isCustom) { - const value = this.chartTimeFilter.dateRangeValue - this.$refs.dateTimeRange.quickChange(value) - } - }, - reload (s, e, v) { - this.dateTimeRangeChange(s, e, v) - }, - dateTimeRangeChange (s, e, v) { - this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v } - }, - generateTooltipHTML () { - return ` - <div class="map-tooltip" style="padding-bottom: 10px;"> - <div class="map-tooltip__title">{name}</div> - <div class="map-tooltip__content"> - <span>{labelText}</span> - <span>{showValue}</span> - </div> - </div> - ` - }, - changeTab (tab) { - this.activeTab = tab.paneName - }, - initMap (id) { - if (this.isIpBasicInfo) { - L.Marker.prototype.options.icon = L.icon({ - iconUrl: icon, - shadowUrl: iconShadow - }) - const map = L.map(`chart${this.chartInfo.id}`, { - minZoom: 3, - maxZoom: 7, - zoom: 5, - attributionControl: false, - zoomControl: false, - maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180)) - }) - L.tileLayer( - this.mapPictureUrl, - { noWrap: true } - ).addTo(map) - - const attribution = L.control.attribution({ position: 'bottomright', prefix: '' }) - attribution.addAttribution(' © OpenStreetMap contributors') - attribution.addTo(map) - - /* L.control.zoom({ - position: 'bottomright', - zoomInText: '<i class="nz-icon nz-icon-enlarge"></i>', - zoomOutText: '<i class="nz-icon nz-icon-narrow"></i>', - zoomInTitle: '', - zoomOutTitle: '' - }).addTo(map) */ - - this.myChart = map - } else { - const chart = am4Core.create(id, am4Maps.MapChart) - chart.geodata = getGeoData(storageKey.iso36112WorldLow) - chart.projection = new am4Maps.projections.Miller() - this.myChart = chart - const polygonSeries = chart.series.push(new am4Maps.MapPolygonSeries()) - polygonSeries.useGeodata = true - polygonSeries.exclude = ['AQ'] // 排除南极洲 - polygonSeries.tooltip.getFillFromObject = false - polygonSeries.tooltip.background.fill = am4Core.color('#FFFFFF') - this.polygonSeries = polygonSeries - const polygonTemplate = polygonSeries.mapPolygons.template - polygonTemplate.tooltipHTML = this.generateTooltipHTML() - polygonTemplate.nonScalingStroke = true - polygonTemplate.strokeWidth = 0.5 - polygonTemplate.fill = am4Core.color('rgba(176,196,222,.5)') - polygonTemplate.events.on('hit', ev => { - let countryId = ev.target.dataItem.dataContext.id - countryId = countryId === 'Private IP' ? 'China' : countryId - if (countryId) { - ev.target.series.chart.zoomToMapObject(ev.target) - ev.target.isHover = false - this.countrySeries = chart.series.push(new am4Maps.MapPolygonSeries()) - this.countrySeries.tooltip.getFillFromObject = false - this.countrySeries.tooltip.background.fill = am4Core.color('#FFFFFF') - const countryTemplate = this.countrySeries.mapPolygons.template - countryTemplate.tooltipHTML = this.generateTooltipHTML() - countryTemplate.nonScalingStroke = true - countryTemplate.strokeWidth = 0.5 - countryTemplate.fill = am4Core.color('rgba(176,196,222,.5)') - const geoData = getGeoData(countryId) - if (geoData) { - this.countrySeries.geodata = geoData - this.polygonSeries.hide() - this.loadAm4ChartMap(this.countrySeries, ev.target.dataItem.dataContext.serverCountry) - } - } - }) - } - }, - loadAm4ChartMap (polygonSeries, country) { - this.loading = true - // 清除数据 - polygonSeries.data.splice(0) - // 清除legend - this.myChart.children.each((s, i) => { - if (s.className !== 'Container') { - this.myChart.children.removeIndex(i) - } - }) - - this.showMapBackButton = !!country - const chartParams = this.chartInfo.params - const queryParams = { ...this.queryTimeRange, country: country || '', region: '', ...this.entity } // 统计数据的查询参数 - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200 && !this.$_.isEmpty(response.data.result)) { - const data = response.data.result - data.forEach(r => { - const serverCountryCapital = r.serverId && getCapitalGeo(r.serverId) - const clientCountryCapital = r.clientId && getCapitalGeo(r.clientId) - serverCountryCapital && (r.serverLongitude = serverCountryCapital.capitalLongitude) - serverCountryCapital && (r.serverLatitude = serverCountryCapital.capitalLatitude) - clientCountryCapital && (r.clientLongitude = clientCountryCapital.capitalLongitude) - clientCountryCapital && (r.clientLatitude = clientCountryCapital.capitalLatitude) - }) - /* if (this.isMapLine) { - const lineSeries = this.myChart.series.push(new am4Maps.MapLineSeries()) - const lineTemplate = lineSeries.mapLines.template - lineTemplate.stroke = am4Core.color('#A258EC') - lineTemplate.line.nonScalingStroke = true - lineTemplate.line.strokeDasharray = '4 3' - lineTemplate.nonScalingStroke = true - lineTemplate.arrow.nonScaling = true - lineTemplate.arrow.width = 4 - lineTemplate.arrow.height = 6 - lineSeries.data = [ - { - multiGeoLine: data.map(d => { - return [ - { - latitude: parseFloat(d.serverLatitude), - longitude: parseFloat(d.serverLongitude) - }, - { - latitude: parseFloat(d.clientLatitude), - longitude: parseFloat(d.clientLongitude) - } - ] - }) - } - ] - const imageSeries = this.myChart.series.push(new am4Maps.MapImageSeries()) - imageSeries.dataFields.value = 'sessions' - const imageSeriesTemplate = imageSeries.mapImages.template - const circle = imageSeriesTemplate.createChild(am4Core.Circle) - - circle.fillOpacity = 0.7 - circle.nonScaling = true - const radiusHeat = imageSeries.heatRules.push({ - target: circle, - property: 'radius', - min: 8, - max: 30 - }) - const colorHeat = imageSeries.heatRules.push({ - target: circle, - property: 'fill', - min: am4Core.color('#D2A8FF'), - max: am4Core.color('#A258EC') - }) - imageSeriesTemplate.propertyFields.latitude = 'latitude' - imageSeriesTemplate.propertyFields.longitude = 'longitude' - - const pointData = [] - data.forEach(d => { - pointData.push({ - ...d, - latitude: parseFloat(d.serverLatitude), - longitude: parseFloat(d.serverLongitude) - }) - pointData.push({ - ...d, - latitude: parseFloat(d.clientLatitude), - longitude: parseFloat(d.clientLongitude) - }) - }) - imageSeries.data = pointData - } */ - if (this.isMapBlock) { - const sumData = [] - data.forEach(r => { - const hit = sumData.find(s => s.id === r.serverId) - const { key, labelText } = this.getDataKey(r) - const value = Number(r[key]) || 0 - if (hit) { - hit.value += value - } else { - sumData.push({ - id: r.serverId, - serverCountry: r.serverCountry, - key, - labelText, - value - }) - } - }) - const seriesData = sumData.map(r => ({ - ...r, - showValue: (r.value || r.value === 0) ? valueToRangeValue(r.value, chartParams.unitType).join(' ') : '' - })) - polygonSeries.data = [...seriesData] - const sorted = seriesData.sort((a, b) => b.value - a.value) - const allZero = this.$_.isEmpty(sorted) || Number(sorted[0].value) === 0 // 数据全为0的情况,legend只显示1个颜色 - - polygonSeries.heatRules.push({ - property: 'fill', - target: polygonSeries.mapPolygons.template, - min: this.myChart.colors.getIndex(1).brighten(1), - max: allZero ? this.myChart.colors.getIndex(1).brighten(1) : this.myChart.colors.getIndex(1).brighten(-0.3) - }) - const heatLegend = this.myChart.createChild(HeatLegend) - heatLegend.markerContainer.height = 6 - heatLegend.series = polygonSeries - heatLegend.align = 'left' - heatLegend.markerCount = allZero ? 1 : 3 - heatLegend.minValue = 0 - heatLegend.fontSize = 12 - heatLegend.maxValue = allZero ? 1 : Number(sorted[0].value) - heatLegend.width = allZero ? am4Core.percent(10) : am4Core.percent(25) - heatLegend.marginLeft = 15 - heatLegend.valign = 'bottom' - - const minRange = heatLegend.valueAxis.axisRanges.create() - minRange.value = heatLegend.minValue - minRange.label.text = minRange.value === 0 ? 0 : unitConvert(heatLegend.minValue, chartParams.unitType).join(' ') - const maxRange = heatLegend.valueAxis.axisRanges.create() - maxRange.value = heatLegend.maxValue - maxRange.label.text = maxRange.value === 0 ? 0 : unitConvert(heatLegend.maxValue, chartParams.unitType).join(' ') - - heatLegend.valueAxis.renderer.labels.template.adapter.add('text', function (labelText) { - return '' - }) - } - } else if (response.code !== 200) { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - }).finally(() => { - setTimeout(() => { this.loading = false }, 250) - }) - }, - loadLeafletMap () { - this.loading = true - const chartParams = this.chartInfo.params - get(replaceUrlPlaceholder(chartParams.url, this.entity)).then(response => { - if (response.code === 200 && !this.$_.isEmpty(response.data.result)) { - this.detailData = response.data.result - this.myChart.setView([this.detailData.latitude, this.detailData.longitude], 5) - const myIcon = L.divIcon({ - className: 'cn-icon cn-icon-position2 position-icon' - }) - L.marker([this.detailData.latitude, this.detailData.longitude], { icon: myIcon }).addTo(this.myChart) - } - }).finally(() => { - setTimeout(() => { this.loading = false }, 250) - }) - }, - pageJump (val) { - this.table.currentPageData = this.getTargetPageData(val, this.table.pageSize, this.table.tableData) - }, - getTargetPageData (pageNum, pageSize, tableData) { - return this.$_.slice(tableData, (pageNum - 1) * pageSize, pageNum * pageSize) - }, - refresh () { - const eventName = this.fromBlock ? 'getChartCurrentTimeRange' : 'getCurrentTimeRange' - this.$emit(eventName, ({ startTime, endTime }) => { - this.standaloneTimeRange.use = true - this.standaloneTimeRange.startTime = startTime - this.standaloneTimeRange.endTime = endTime - this.initChart() - }) - }, - mapBack () { - this.countrySeries.hide() - this.loadAm4ChartMap(this.polygonSeries) - this.polygonSeries.show() - this.myChart.goHome() - }, - // 获取最新时间 - getCurrentTimeRange (callback) { - this.$emit('getCurrentTimeRange', ({ startTime, endTime }) => { - callback({ startTime, endTime }) - }) - }, - // 获取最新时间 - getChartCurrentTimeRange (callback) { - if (this.isGroup) { - this.$emit('getChartCurrentTimeRange', ({ startTime, endTime }) => { - callback({ startTime, endTime }) - }) - } else { - const myEndTime = window.$dayJs.tz().valueOf() - const myStartTime = myEndTime - this.chartTimeFilter.dateRangeValue * 60 * 1000 - callback({ startTime: myStartTime, endTime: myEndTime }) - } - }, - getDataKey (r) { - let key = '' - let labelText = '' - if (r.establishLatency || r.establishLatency === 0) { - key = 'establishLatency' - labelText = this.$t('networkAppPerformance.tripTime') - } else if (r.httpResponseLatency || r.httpResponseLatency === 0) { - key = 'httpResponseLatency' - labelText = this.$t('networkAppPerformance.httpResponse') - } else if (r.sslConLatency || r.sslConLatency === 0) { - key = 'sslConLatency' - labelText = this.$t('networkAppPerformance.sslResponse') - } else if (r.sequenceGapLossPercent || r.sequenceGapLossPercent === 0) { - key = 'sequenceGapLossPercent' - labelText = this.$t('networkAppPerformance.packetLossRate') - } else if (r.pktRetransPercent || r.pktRetransPercent === 0) { - key = 'pktRetransPercent' - labelText = this.$t('networkAppPerformance.retransmissionRate') - } else if (r.sessions || r.sessions === 0) { - key = 'sessions' - labelText = this.$t('overall.sessions') - } - return { key, labelText } + computed: { + isNoData () { + return !this.loading && (_.isEmpty(this.chartData) || this.isError) && !this.isSingleValue && !this.isTabs && !this.isDomainDnsRecord && !this.isCryptocurrencyEventList && !this.isActiveIpTable && !this.isMap }, - getTableTitle (data) { - if (data.length > 0) { - const dataColumns = Object.keys(data[0]) // 返回数据的字段 - const columns = dataColumns.map(c => tableTitleMapping[c]) // 展示字段 - const keys = ['clientIp', 'serverIp', 'ip', 'appId', 'app', 'appName', 'domain'] - return columns.sort((a, b) => { - if (keys.indexOf(a.prop) > -1) { - return -1 - } else if (keys.indexOf(b.prop) > -1) { - return 1 - } else { - return 0 - } - }) + chartOption () { + if (this.customChartOption) { + return _.cloneDeep(this.customChartOption) } else { - return [] - } - }, - toggleStatisticsLegend (index) { - this.statisticsData[index].active = !this.statisticsData[index].active - this.statisticsData.forEach((d, i) => { - if (d.active) { - this.myChart.dispatchAction({ - type: 'legendSelect', - name: d.legend - }) - } else { - this.myChart.dispatchAction({ - type: 'legendUnSelect', - name: d.legend - }) - } - }) - }, - orderPieTableChange () { - if (this.chart.type === 31) { - const chartParams = this.chartInfo.params || null // 图表参数 - this.initEchartsWithPieTable(chartParams) - } - }, - timeLineIsAllZero (data) { - if (data.resultType === 'matrix') { - let allZero = true - try { - data.result.forEach(d => { - d.values.forEach(r => { - if (r[1] && r[1] !== '0') { - allZero = false - throw new Error('break') - } - }) - }) - } catch (e) {} - return allZero - } - }, - initECharts (chartParams) { - if (chartParams.showLegend === false) { - this.chartOption.legend.show = false - } - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - const seriesTemplate = this.chartOption.series[0] - const allZero = this.timeLineIsAllZero(response.data) - if (allZero) { - this.chartOption.yAxis = { - ...this.chartOption.yAxis, - min: 0, - max: 5, - interval: 1 - } - } - this.chartOption.series = response.data.result.map(r => { - return { - ...seriesTemplate, - name: legendMapping[`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`] ? legendMapping[`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`] : lineToSpace(r.legend), - data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType]) - } - }) - const rows = (response.data.result.length - 1) / 4 + 1 // 根据legend个数动态预留legend空间 - const gridTop = 10 + 27 * rows - this.chartOption.grid.top = gridTop - if (chartParams.unitType === unitTypes.byte) { - this.chartOption.yAxis.axisLabel.formatter = function (value, index, a, b) { - return unitConvert(value, unitTypes.byte).join(' ') - } - this.chartOption.grid.left = 75 - } - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - this.myChart.setOption(this.chartOption) - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - initRelationShip (chartParams) { - this.isError = false - this.errorInfo = '0' - const queryParams = { ...this.entity, limit: 5 } - post(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (!response.data.result) { - this.noData = true - return - } - const data = [] - const links = [] - handleData(data, links, response.data.result) - this.chartOption.series[0].data = data - this.chartOption.series[0].links = links - this.myChart.setOption(this.chartOption) - } else { - this.isError = true - this.errorInfo = response - this.noData = true - } - }).finally(() => { - setTimeout(() => { - this.loading = false - setTimeout(() => { - this.myChart.resize() - }) - }, 250) - }) - - const vm = this - function handleData (data, links, item) { - if (!data.some(d => d.name === item.name)) { - data.push({ name: item.name, ...handleStyle(item) }) - } - if (!vm.$_.isEmpty(item.from) && !vm.$_.isEmpty(item.to)) { - links.push({ target: item.to, source: item.from }) - } - if (!vm.$_.isEmpty(item.leaf)) { - item.leaf.forEach(i => { - handleData(data, links, i) - }) - } - } - - function handleStyle (item) { - const style = {} - switch (item.type) { - case 'app_id': { - style.itemStyle = { color: '#73DEB3' } - style.symbol = 'circle' - break - } - case 'domain': { - style.itemStyle = { color: '#73A0FA' } - style.symbol = 'circle' - break - } - case 'client_ip': { - style.itemStyle = { color: '#E8F6FF', borderColor: '#C9C9C9' } - style.symbol = 'roundRect' - style.symbolSize = [80, 25] - break - } - case 'server_ip': { - style.itemStyle = { color: '#E2FCEF', borderColor: '#C9C9C9' } - style.symbol = 'roundRect' - style.symbolSize = [80, 25] - break - } - } - return style - } - }, - initSankey (chartParams) { - const vm = this - const entityName = this.entity.ip || this.entity.domain || this.entity.app - const queryParams = { ...this.queryTimeRange, ...this.entity } - this.chartOption.series[0].tooltip = { - formatter: function (param) { - return ` - <div class="sankey__tooltip"> - <div class="sankey__tooltip-row"> - <div class="sankey__row-label">Via:</div> - <div class="sankey__row-value">${param.data.name}</div> - </div> - <div class="sankey__tooltip-row"> - <div style="margin: 6px 0; height: 1px; width: 100%; background-color: #E7EAED;"></div> - </div> - <div class="sankey__tooltip-row"> - <div class="sankey__row-label">Traffic:</div> - <div class="sankey__row-value">${param.data.convert[0]}${param.data.convert[1]} (${param.data.percent[0]}%)</div> - </div> - <div class="sankey__tooltip-row"> - <div class="sankey__row-label">Performance:</div> - </div> - <div class="sankey__tooltip-table"> - <div class="sankey__table-row"> - <div class="sankey__table-cell">${vm.$t('networkAppPerformance.tripTime')}:</div> - <div class="sankey__table-cell">${param.data.latency[0]} ${param.data.latency[1]}</div> - </div> - <div class="sankey__table-row"> - <div class="sankey__table-cell">${vm.$t('overall.packetLoss')}:</div> - <div class="sankey__table-cell">${param.data.lossPercent[0]} %</div> - </div> - <div class="sankey__table-row"> - <div class="sankey__table-cell">${vm.$t('overall.packetRetrans')}:</div> - <div class="sankey__table-cell">${param.data.retransPercent[0]} %</div> - </div> - </div> - </div> - ` - } - } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.noData = false - let inTotalValue = 0 - let outTotalValue = 0 - - /* 测试代码 - const t = [] - for (const k in response.data.result) { - t.push(response.data.result[k]) - } - response.data.result = t */ - - response.data.result.forEach(item => { - if (item.direction === 'in') { - inTotalValue += parseInt(item.bytes) - } else if (item.direction === 'out') { - outTotalValue += parseInt(item.bytes) - } - }) - const data = response.data.result.map(item => { - return { - ...item, - name: item.linkID, - percent: valueToRangeValue(parseInt(item.bytes) / (item.direction === 'in' ? inTotalValue : outTotalValue) * 100, unitTypes.percent), - convert: unitConvert(item.bytes, unitTypes.byte), - latency: valueToRangeValue(item.latency, unitTypes.time), - lossPercent: valueToRangeValue(item.lossPercent, unitTypes.percent), - retransPercent: valueToRangeValue(item.retransPercent, unitTypes.percent), - bytes: parseFloat(item.bytes) - } - }) - data.push({ name: entityName }) - - const link = data.map(item => { - const source = item.direction === 'in' ? item.linkID : entityName - const target = item.direction === 'in' ? entityName : item.linkID - return { - ...item, - source, - target, - value: item.bytes - } - }) - this.chartOption.series[0].data = data - this.chartOption.series[0].links = link - this.myChart.setOption(this.chartOption) - } - } - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - /* const inDirection = new Promise(resolve => - get(replaceUrlPlaceholder(chartParams.url, { ...queryParams, direction: 'ingress' })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.noData = false - resolve(handleData(response.data.result, 'in')) - } - } - resolve() - }) - ) - const outDirection = new Promise(resolve => - get(replaceUrlPlaceholder(chartParams.url, { ...queryParams, direction: 'egress' })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.noData = false - resolve(handleData(response.data.result, 'out')) - } - } - resolve() - }) - ) - Promise.all([inDirection, outDirection]).then(responses => { - const inData = responses[0] - const outData = responses[1] - this.chartOption.series[0].data = inData.data.concat(outData.data) - this.chartOption.series[0].links = inData.link.concat(outData.link) - this.myChart.setOption(this.chartOption) - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - - function handleData (originalData, direction) { - let totalValue = 0 - originalData.forEach(item => { - totalValue += parseInt(item.bytes) - }) - const data = originalData.map(item => { - return { - ...item, - name: item.linkID, - percent: unitConvert(parseInt(item.bytes) / totalValue, unitTypes.byte), - bytes: unitConvert(item.bytes, unitTypes.byte) - } - }) - - const link = data.map(item => { - const source = direction === 'in' ? item.linkID : entityName - const target = direction === 'in' ? entityName : item.linkID - return { - ...item, - source, - target, - value: item.bytes - } - }) - return { - data, - link - } - } */ - }, - initIpOpenPort (chartParams) { - get(replaceUrlPlaceholder(chartParams.url, { ip: this.entity.ip })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.noData = false - this.detailData = response.data.result - const protocols = [] - this.detailData.forEach((d, i) => { - const index = protocols.findIndex(p => p.name === d.protocol.toUpperCase()) - if (index === -1) { - protocols.push({ name: d.protocol.toUpperCase(), value: 1, itemStyle: { color: getChartColor(i) } }) - } else { - protocols[index].value++ - } - }) - this.chartOption.series[0].data = protocols - this.chartOption.xAxis.data = protocols.map(p => p.name) - this.myChart.setOption(this.chartOption) - } - } - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - initIpHostedDomain (chartParams) { - const list = new Promise(resolve => { - get(replaceUrlPlaceholder(chartParams.url, { ip: this.entity.ip })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.noData = false - this.detailData = response.data.result - } - } - resolve() - }) - }) - const byType = new Promise(resolve => { - get(replaceUrlPlaceholder(chartParams.byTypeUrl, { ip: this.entity.ip })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData0 = true - } else { - this.noData0 = false - const chartOption = this.$_.cloneDeep(this.chartOption) - chartOption.series[0].data = response.data.result.map(r => ({ ...r, unitType: chartParams.unitType })) - this.myChart.setOption(chartOption) - } - } - resolve() - }) - }) - const byCredit = new Promise(resolve => { - get(replaceUrlPlaceholder(chartParams.byCreditUrl, { ip: this.entity.ip })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData1 = true - } else { - this.noData1 = false - const chartOption = this.$_.cloneDeep(this.chartOption) - chartOption.series[0].data = response.data.result.map(r => ({ ...r, unitType: chartParams.unitType })) - this.myChart2.setOption(chartOption) - } - } - resolve() - }) - }) - Promise.all([list, byType, byCredit]).finally(response => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - initAppRelatedDomain (chartParams) { - this.noData = false - this.loading = false - this.chartOption.series[0].data = [ - { - name: 'test1', - value: 32 - }, - { - name: 'test2', - value: 21 - }, - { - name: 'test3', - value: 20 - }, - { - name: 'test4', - value: 7 - } - ] - this.myChart.setOption(this.chartOption) - this.myChart2.setOption(this.chartOption) - get(replaceUrlPlaceholder(chartParams.url, { appName: this.entity.appName })).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - } else { - this.detailData = response.data.result - this.noData = false - } - } - }).finally(() => { - setTimeout(() => { - this.loading = false - }, 250) - }) - }, - - handleTimeChartOption (chartParams, dataArray) { - let direction = 'vertical' - if (chartParams.direction) { - direction = chartParams.direction - if (direction == 'horizontal') { // 柱状图水平方向 - this.chartOption.xAxis = { - axisTick: { show: false }, - axisLine: { show: false }, - type: 'value', - axisLabel: { - formatter: function (value, index, a, b) { - return unitConvert(value, unitTypes.number).join(' ') - } - } - } - - this.chartOption.yAxis = { - type: 'category', - axisTick: { show: false }, - axisLine: { show: false }, - axisLabel: { - interval: 0, - // rotate: -40, //设置日期显示样式(倾斜度) - formatter: function (value) { // 在这里写你需要的时间格式 - return window.$dayJs.tz(Number(value)).format('M/D H:m') - } - }, - axisPointer: { // y轴上显示指针对应的值 - show: true - } - } - } else if (direction == 'vertical') { // 柱状图竖直方向 - this.chartOption.yAxis = { - axisTick: { show: false }, - axisLine: { show: false }, - type: 'value', - axisLabel: { - formatter: function (value, index, a, b) { - return unitConvert(value, unitTypes.number).join(' ') - } - }, - minInterval: 1 - } - this.chartOption.xAxis = { - type: 'category', - axisTick: { show: false }, - axisLine: { show: false }, - axisLabel: { - interval: 0, - // rotate: -40, //设置日期显示样式(倾斜度) - formatter: function (value) { // 在这里写你需要的时间格式 - return window.$dayJs.tz(Number(value)).format('M/D H:m') - } - }, - axisPointer: { // y轴上显示指针对应的值 - show: true - } - } - } - } - - let itemColorAlternately = false// true|false 柱体色是否轮替 - if (chartParams.itemColorAlternately) { - itemColorAlternately = chartParams.itemColorAlternately - } - - this.chartOption.tooltip = { - ...this.chartOption.tooltip, - formatter: (direction == 'horizontal') ? timeHorizontalFormatter : timeVerticalFormatter - } - - this.chartOption.series = { - ...this.chartOption.series[0], - name: this.chartInfo.name, - data: dataArray, - itemStyle: { - color: function (params) { - if (itemColorAlternately) { - return getCharBartColor([params.dataIndex]) - } else { - return getCharBartColor(0) - } - } - } - } - }, - - initEchartsTimeBar (chartParams) { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - - let dataArray = [] - if (chartParams.direction == 'vertical') { // 柱状图竖直方向 - dataArray = response.data.result[0].values.map((r, i) => { - return [Number(r[0]), Number(r[1]), chartParams.unitType] - }) - } else if (chartParams.direction == 'horizontal') { // 柱状图水平方向 - dataArray = response.data.result[0].values.map((r, i) => { - return [Number(r[1]), Number(r[0]), chartParams.unitType] - }) - } - - this.handleTimeChartOption(chartParams, dataArray) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - this.myChart.setOption(this.chartOption) - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - - initEchartsCategoryBar (chartParams) { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - - let dataArray = [] - if (chartParams.direction == 'horizontal') { // 柱状图水平方向 - dataArray = response.data.result.map((r, i) => { return [r.num, r.name] }) - } else if (chartParams.direction == 'vertical') { // 柱状图竖直方向 - dataArray = response.data.result.map((r, i) => { return [r.name, r.num] }) - } - this.handleCategoryChartOption(chartParams, dataArray) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - this.myChart.setOption(this.chartOption) - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - - handleCategoryChartOption (chartParams, dataArray) { - let xType = 'category' - let yType = 'value' - let direction = 'vertical' - if (chartParams.direction) { - direction = chartParams.direction - if (direction == 'horizontal') { // 柱状图水平方向 - xType = 'value' - yType = 'category' - } else if (direction == 'vertical') { // 柱状图竖直方向 - xType = 'category' - yType = 'value' - } - } - - let itemColorAlternately = false// true|false 柱体色是否轮替 - if (chartParams.itemColorAlternately) { - itemColorAlternately = chartParams.itemColorAlternately - } - - this.chartOption.tooltip = { - ...this.chartOption.tooltip, - formatter: (direction == 'horizontal') ? categoryHorizontalFormatter : categoryVerticalFormatter - } - this.chartOption.xAxis = { - ...this.chartOption.xAxis, - type: xType - } - this.chartOption.yAxis = { - ...this.chartOption.yAxis, - type: yType + return getOption(this.chartInfo.type) } - this.chartOption.series = { - ...this.chartOption.series[0], - data: dataArray, - itemStyle: { - color: function (params) { - if (itemColorAlternately) { - return getCharBartColor([params.dataIndex]) - } else { - return getCharBartColor(0) - } - } - } - } - }, - - initEchartsWithStatistics (chartParams) { - const queryParams = { ...this.queryTimeRange, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - const allZero = this.timeLineIsAllZero(response.data) - if (allZero) { - this.chartOption.yAxis = { - ...this.chartOption.yAxis, - min: 0, - max: 5, - interval: 1 - } - } - this.statisticsData = response.data.result.map(d => { - return { - ...d, - active: true - } - }) - const seriesTemplate = this.chartOption.series[0] - this.chartOption.series = response.data.result.map((r, i) => { - return { - ...seriesTemplate, - name: r.legend, - data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType]), - lineStyle: { - color: getChartColor[i] - } - } - }) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - this.myChart.setOption(this.chartOption) - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - }, - - initEchartsWithPieTable (chartParams) { - const self = this - chartParams.valueColumn = this.orderPieTable - const unitType = getUnitType(chartParams.valueColumn) - const queryParams = { ...this.queryTimeRange, limit: 10, order: this.orderPieTable, ...this.entity } // 统计数据的查询参数 - const tableQueryParams = { ...this.queryTimeRange, limit: 10, order: this.orderPieTable, ...this.entity } // 统计数据的查询参数 - tableQueryParams[chartParams.nameColumn] = [] // 处理两个图表不一样的地方) - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - const allZero = this.timeLineIsAllZero(response.data) - if (allZero) { - this.chartOption.yAxis = { - ...this.chartOption.yAxis, - min: 0, - max: 5, - interval: 1 - } - } - - const data = response.data.result.map(d => { - if (d[chartParams.nameColumn]) { - this.allSelectPieChartName.push(d[chartParams.nameColumn]) - } - return { - data: d, - name: d[chartParams.nameColumn], - value: parseInt(d[chartParams.valueColumn]), - unitType: unitType - } - }) - - this.allSelectPieChartName = tableQueryParams[chartParams.nameColumn] - this.chartOption.series[0].data = data - if (this.chartOption.series[0].data && this.chartOption.series[0].data.length > 10) { // pieWithTable 图例超过10个改为滚动显示 - this.chartOption.legend.type = 'scroll' - } - this.myChart.setOption(this.chartOption) - - if (!this.$_.isEmpty(data)) { - get(replaceUrlPlaceholder(chartParams.urlTable, tableQueryParams)).then(response2 => { - if (response2.code === 200) { - this.pieTableData = response2.data.result - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - }) - } - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || 'Unknown' - } - }).finally(() => { - setTimeout(() => { - this.loading = false - this.$nextTick(() => { - this.echartsResize() - }) - }, 250) - }) - // legend点击事件 - this.myChart.off('legendselectchanged') - this.myChart.on('legendselectchanged', function (params) { - self.myChart.setOption({ - legend: { selected: { [params.name]: true } } - }) - const index = self.chartOption.series[0].data.findIndex(d => d.name === params.name) - if (self.selectPieChartName !== params.name) { - self.myChart.dispatchAction({ - type: 'select', - seriesIndex: 0, - dataIndex: index - }) - self.selectPieChartName = params.name - self.loadPieTableData(params.name) - } else { - self.myChart.dispatchAction({ - type: 'unselect', - seriesIndex: 0, - dataIndex: index - }) - self.selectPieChartName = '' - self.loadPieTableData(this.allSelectPieChartName) - } - }) - // 饼图色块点击事件 - this.myChart.off('click') - this.myChart.on('click', function (echartParams) { - // 若是已选,则点击后取消选择,并查询全部数据 - if (echartParams.name === self.selectPieChartName) { - self.selectPieChartName = '' - self.loadPieTableData(this.allSelectPieChartName) - } else { // 否则查询当前name数据 - self.selectPieChartName = echartParams.name - self.loadPieTableData(echartParams.name) - } - }) - }, - loadPieTableData (name = '') { - const childrenParams = { ...this.queryTimeRange, limit: 10, order: this.orderPieTable, ...this.entity } - childrenParams[this.chartInfo.params.nameColumn] = name - get(replaceUrlPlaceholder(this.chartInfo.params.urlTable, childrenParams)).then(response => { - if (response.code === 200) { - this.pieTableData = response.data.result - } - }) - }, - tableLimitChange () { - const chartParams = this.chartInfo.params || null // 图表参数 - this.initChartTable(chartParams) - }, - initChartTable (chartParams) { - const queryParams = { ...this.queryTimeRange, limit: this.table.limit, order: this.table.orderBy, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - this.table.tableData = response.data.result - this.table.tableColumns = this.getTableTitle(response.data.result) - this.table.currentPageData = this.getTargetPageData(1, this.table.pageSize, this.table.tableData) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || this.$t('tip.unknownError') - } - }).finally(() => { - this.$nextTick(() => { - this.$refs.tablePagination.resetPageNo() - }) - setTimeout(() => { this.loading = false }, 250) - }) - }, - - activeIpTableLimitChange () { - const chartParams = this.chartInfo.params || null // 图表参数 - this.initChartActiveIpTable(chartParams) - }, - initChartActiveIpTable (chartParams) { - const queryParams = { ...this.queryTimeRange, order: this.activeIpTable.orderBy, ...this.entity } - get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { - if (response.code === 200) { - if (this.$_.isEmpty(response.data.result)) { - this.noData = true - return - } else { - this.noData = false - } - this.activeIpTable.tableData = response.data.result - this.activeIpTable.tableColumns = this.getTableTitle(response.data.result) - this.activeIpTable.currentPageData = this.getTargetPageData(1, this.activeIpTable.pageSize, this.activeIpTable.tableData) - } else { - this.isError = true - this.noData = true - this.errorInfo = response.msg || response.message || this.$t('tip.unknownError') - } - }).finally(() => { - setTimeout(() => { this.loading = false }, 250) - }) - }, - echartsResize () { - this.myChart && this.myChart.resize() - this.myChart2 && this.myChart2.resize() } }, - computed: { - computePosition () { - const gridColumn = `${this.chartInfo.x} / ${this.chartInfo.x + this.chartInfo.w}` - const gridRow = `${this.chartInfo.y} / ${this.chartInfo.y + this.chartInfo.h}` - return { - gridColumn, - gridRow - } + methods: { + resize () { + this.$refs['chart' + this.chartInfo.id] && this.$refs['chart' + this.chartInfo.id].resize() }, - location () { - let location = '' - if (this.detailData) { - if (this.detailData.country) { - location = this.detailData.country - if (this.detailData.province) { - location += ', ' - location += this.detailData.province - if (this.detailData.city) { - location += ', ' - location += this.detailData.city - } - } - } else if (this.detailData.province) { - location = this.detailData.province - if (this.detailData.city) { - location += ', ' - location += this.detailData.city - } - } else if (this.detailData.city) { - location = this.detailData.city - } - } - return location + showLoading (show) { + this.$emit('showLoading', show) }, - handleSingleValue () { - const value = this.singleValue.value - const unitType = this.chartInfo.params.unitType - const result = unitConvert(value, unitType) - switch (unitType) { - case unitTypes.percent: { - result[0] = result[0] < 0.01 ? '< 0.01' : result[0] - break - } - case unitTypes.time: { - result[0] = result[0] < 1 ? '< 1' : result[0] - break - } - default: break - } - return result + initEchartsWithTable () { + this.$refs['chart' + this.chartInfo.id] && this.$refs['chart' + this.chartInfo.id].initEchartsWithTable(`chart${this.chartInfo.id}`) } - }, - mounted () { - setTimeout(() => { - this.initChart() - this.throttle = this.$_.throttle(this.echartsResize, 500) - window.addEventListener('resize', this.throttle) - }, 300) + }, watch: { - chart: { - immediate: true, + chartData: { deep: true, - handler (n, o) { - if (o) { - setTimeout(() => { this.initChart() }) - } - } - }, - timeFilter: { - immediate: true, - deep: true, - handler (n, o) { - if (n && o) { - this.standaloneTimeRange.use = false - this.$nextTick(() => { - setTimeout(() => { this.initChart() }) - }) - } - } - }, - parentData: { - immediate: true, - deep: true, - handler (n, o) { - if (n) { - this.$nextTick(() => { - setTimeout(() => { this.initChart() }) - }) - } + handler (n) { } } }, setup (props) { - const chartInfo = JSON.parse(JSON.stringify(props.chart)) - chartInfo.category = getTypeCategory(props.chart.type) - - const dateRangeValue = 60 - const { startTime, endTime } = getNowTime(dateRangeValue) - // entity详情内的chart时间工具不是公共的,需要单独定义 - const chartTimeFilter = ref({ startTime, endTime, dateRangeValue }) return { - chartInfo, - chartTimeFilter, - layoutConstant, - chartTableTopOptions, - chartActiveIpTableOrderOptions, - chartPieTableTopOptions, - isEcharts: isEcharts(props.chart.type), - isEchartsTimeBar: isEchartsTimeBar(props.chart.type), - isEchartsCategoryBar: isEchartsCategoryBar(props.chart.type), - isEchartsWithTable: isEchartsWithTable(props.chart.type), - isEchartsWithStatistics: isEchartsWithStatistics(props.chart.type), - isSingleValue: isSingleValue(props.chart.type), - isSingleValueWithEcharts: isSingleValueWithEcharts(props.chart.type), - isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(props.chart.type), - isRelationShip: isRelationShip(props.chart.type), - isTable: isTable(props.chart.type), - isActiveIpTable: isActiveIpTable(props.chart.type), - isMap: isMap(props.chart.type), - isTitle: isTitle(props.chart.type), - isMapLine: isMapLine(props.chart.type), - isMapBlock: isMapBlock(props.chart.type), - isTabs: isTabs(props.chart.type), - isGroup: isGroup(props.chart.type), - isBlock: isBlock(props.chart.type), - isSankey: isSankey(props.chart.type), - 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), - isCryptocurrencyEventList: isCryptocurrencyEventList(props.chart.type), - isAppBasicInfo: isAppBasicInfo(props.chart.type), - isAppRelatedDomain: isAppRelatedDomain(props.chart.type), - layout: getLayout(props.chart.type), - myChart: shallowRef(null), - myChart2: shallowRef(null) // 个别有两个图表的chart + 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) } - }, - unmounted () { - window.removeEventListener('resize', this.throttle) } } </script> diff --git a/src/views/charts/Chart2.vue b/src/views/charts/Chart2.vue deleted file mode 100644 index 5ce07b18..00000000 --- a/src/views/charts/Chart2.vue +++ /dev/null @@ -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> diff --git a/src/components/charts/ChartError.vue b/src/views/charts/ChartError.vue index 147726d2..147726d2 100644 --- a/src/components/charts/ChartError.vue +++ b/src/views/charts/ChartError.vue diff --git a/src/views/charts/ChartHeader.vue b/src/views/charts/ChartHeader.vue index 47322a48..1ae0d764 100644 --- a/src/views/charts/ChartHeader.vue +++ b/src/views/charts/ChartHeader.vue @@ -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' diff --git a/src/views/charts/PanelChart.vue b/src/views/charts/PanelChart.vue index e364f48f..98996945 100644 --- a/src/views/charts/PanelChart.vue +++ b/src/views/charts/PanelChart.vue @@ -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' diff --git a/src/views/charts/charts/ChartCategoryBar.vue b/src/views/charts/charts/ChartCategoryBar.vue index 44ec8936..7523f7ab 100644 --- a/src/views/charts/charts/ChartCategoryBar.vue +++ b/src/views/charts/charts/ChartCategoryBar.vue @@ -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' diff --git a/src/views/charts/charts/ChartEchart.vue b/src/views/charts/charts/ChartEchart.vue index 2649780b..cab65a64 100644 --- a/src/views/charts/charts/ChartEchart.vue +++ b/src/views/charts/charts/ChartEchart.vue @@ -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', diff --git a/src/views/charts/charts/ChartEchartWithStatistics.vue b/src/views/charts/charts/ChartEchartWithStatistics.vue index b3bfccdf..d9991eff 100644 --- a/src/views/charts/charts/ChartEchartWithStatistics.vue +++ b/src/views/charts/charts/ChartEchartWithStatistics.vue @@ -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' diff --git a/src/views/charts/charts/ChartIpOpenPortBar.vue b/src/views/charts/charts/ChartIpOpenPortBar.vue index 50c67e0f..42334acd 100644 --- a/src/views/charts/charts/ChartIpOpenPortBar.vue +++ b/src/views/charts/charts/ChartIpOpenPortBar.vue @@ -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', diff --git a/src/views/charts/charts/ChartSingleValue.vue b/src/views/charts/charts/ChartSingleValue.vue index 761eb5a2..3ac52153 100644 --- a/src/views/charts/charts/ChartSingleValue.vue +++ b/src/views/charts/charts/ChartSingleValue.vue @@ -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: { diff --git a/src/views/charts/charts/ChartTimeBar.vue b/src/views/charts/charts/ChartTimeBar.vue index 89e35b02..20911ece 100644 --- a/src/views/charts/charts/ChartTimeBar.vue +++ b/src/views/charts/charts/ChartTimeBar.vue @@ -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' diff --git a/src/components/charts/StatisticsLegend.vue b/src/views/charts/charts/StatisticsLegend.vue index faa3e242..c4c12fe4 100644 --- a/src/components/charts/StatisticsLegend.vue +++ b/src/views/charts/charts/StatisticsLegend.vue @@ -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', diff --git a/src/components/charts/chart-table-title.js b/src/views/charts/charts/chart-table-title.js index bb9194d1..bb9194d1 100644 --- a/src/components/charts/chart-table-title.js +++ b/src/views/charts/charts/chart-table-title.js diff --git a/src/views/detections/Index.vue b/src/views/detections/Index.vue new file mode 100644 index 00000000..cca35d85 --- /dev/null +++ b/src/views/detections/Index.vue @@ -0,0 +1,13 @@ +<template> + +</template> + +<script> +export default { + name: 'Index' +} +</script> + +<style scoped> + +</style> diff --git a/src/views/entities/EntityExplorer.vue b/src/views/entities/EntityExplorer.vue deleted file mode 100644 index 2d2ee1d6..00000000 --- a/src/views/entities/EntityExplorer.vue +++ /dev/null @@ -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> diff --git a/src/views/entityExplorer/entityList/detailOverview/App.vue b/src/views/entityExplorer/entityList/detailOverview/App.vue index fc6c91cd..bd743668 100644 --- a/src/views/entityExplorer/entityList/detailOverview/App.vue +++ b/src/views/entityExplorer/entityList/detailOverview/App.vue @@ -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 () { diff --git a/src/views/entityExplorer/entityList/detailOverview/Domain.vue b/src/views/entityExplorer/entityList/detailOverview/Domain.vue index 4af40f47..ca055306 100644 --- a/src/views/entityExplorer/entityList/detailOverview/Domain.vue +++ b/src/views/entityExplorer/entityList/detailOverview/Domain.vue @@ -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 () { diff --git a/src/views/entityExplorer/entityList/detailOverview/Ip.vue b/src/views/entityExplorer/entityList/detailOverview/Ip.vue index 29ee1a8f..425c3b54 100644 --- a/src/views/entityExplorer/entityList/detailOverview/Ip.vue +++ b/src/views/entityExplorer/entityList/detailOverview/Ip.vue @@ -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 () { diff --git a/src/views/entityExplorer/entityList/detailOverview/entityDetailMixin.js b/src/views/entityExplorer/entityList/detailOverview/entityDetailMixin.js index 64b53a07..2eda0558 100644 --- a/src/views/entityExplorer/entityList/detailOverview/entityDetailMixin.js +++ b/src/views/entityExplorer/entityList/detailOverview/entityDetailMixin.js @@ -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' diff --git a/src/views/entityExplorer/entityList/entityListMixin.js b/src/views/entityExplorer/entityList/entityListMixin.js index 9da3a6ca..ee2bedfd 100644 --- a/src/views/entityExplorer/entityList/entityListMixin.js +++ b/src/views/entityExplorer/entityList/entityListMixin.js @@ -2,8 +2,8 @@ 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 {riskLevelMapping, unitTypes} from '@/utils/constants' +import { entityListLineOption } from '@/views/charts/charts/chart-options' +import { riskLevelMapping, unitTypes } from '@/utils/constants' export default { props: { |
