CN-268 feat: panel重构
This commit is contained in:
@@ -15,8 +15,8 @@ module.exports = {
|
||||
eqeqeq: 0, // 关闭必须使用全等
|
||||
'no-extend-native': 0,
|
||||
'vue/no-parsing-error': 0, // 关闭此项避免在{{}}中使用>、<号导致报错的问题
|
||||
'vue/no-use-v-if-with-v-for': 0, // vue2暂时关闭v-if和v-for写在一起的错误提示,到vue3后要遵守
|
||||
'no-useless-escape': 0,
|
||||
'no-eval': 0
|
||||
'no-eval': 0,
|
||||
'no-trailing-spaces': 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ https://www.lodashjs.com/
|
||||
多个单词时,应该以高阶的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾
|
||||
eg:`SearchButtonClear.vue` 反例:`ClearSearchButton.vue`
|
||||
- **文件夹**
|
||||
使用小写,单词间使用连字符`-`连接
|
||||
eg:`right-box`
|
||||
使用小写,单词间使用连字符`-`连接,或使用驼峰格式
|
||||
eg:`right-box`、`rightBox`
|
||||
|
||||
|
||||
- **VUE组件文件**
|
||||
@@ -99,4 +99,4 @@ eg:
|
||||
`el.style.border = 'xxx'`
|
||||
|
||||
- **布局**
|
||||
避免使用float,视情况使用position,建议使用flex和grid
|
||||
避免使用float,视情况使用position,建议使用flex和grid
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* 不含主题变量的通用css */
|
||||
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -14,3 +16,8 @@ body {
|
||||
cursor: default !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.temp-dom {
|
||||
visibility: hidden;
|
||||
font-size: 14px;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
@import './rightBoxCommon';
|
||||
@import './tableCommon';
|
||||
@import 'right-box-common';
|
||||
@import 'table-common';
|
||||
|
||||
/* 通用css */
|
||||
.panel-chart__no-data {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@@ -728,6 +728,7 @@
|
||||
.header__operation-btn {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
.ip-detail-as {
|
||||
color: #999;
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
@import './components/advancedSearch/advancedSearch';
|
||||
@import 'components/advancedSearch/advanced-search';
|
||||
@import './components/charts/panel';
|
||||
@import './components/common/TimeRange/dateTimeRange';
|
||||
@import './components/common/TimeRange/timeRefresh';
|
||||
@import 'components/common/TimeRange/date-time-range';
|
||||
@import 'components/common/TimeRange/time-refresh';
|
||||
@import './components/common/pagination';
|
||||
// @import './components/entities/entities';
|
||||
@import './components/layout/layout';
|
||||
@import './components/rightBox/settings/chartBox';
|
||||
@import './components/setting/galaxyProxyDebug';
|
||||
@import './components/table/settings/galaxyProxyTable';
|
||||
@import 'components/rightBox/settings/chart-box';
|
||||
@import 'components/setting/galaxy-proxy-debug';
|
||||
@import 'components/table/settings/galaxy-proxy-table';
|
||||
@import './components/table/common';
|
||||
@import './views/charts/chart';
|
||||
@import './views/entityExplorer/entityExplorer';
|
||||
@import './views/entityExplorer/search/explorerSearch';
|
||||
@import './views/entityExplorer/entityFilter';
|
||||
@import './views/entityExplorer/entityDetail';
|
||||
@import './views/entityExplorer/entityList/entityList';
|
||||
@import 'views/entityExplorer/entity-explorer';
|
||||
@import 'views/entityExplorer/search/explorer-search';
|
||||
@import 'views/entityExplorer/entity-filter';
|
||||
@import 'views/entityExplorer/entity-detail';
|
||||
@import 'views/entityExplorer/entityList/entity-list';
|
||||
@import './views/entityExplorer/entityList/card';
|
||||
@import './views/entityExplorer/entityList/row';
|
||||
@import './views/entityExplorer/entityList/detailOverview';
|
||||
@import 'views/entityExplorer/entityList/detail-overview';
|
||||
@import './views/charts/panel';
|
||||
//@import '../chart';
|
||||
|
||||
@@ -375,12 +375,11 @@
|
||||
}
|
||||
.chart__loading {
|
||||
position: absolute;
|
||||
height: calc(100% - 47px);
|
||||
top: 47px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #fefefe;
|
||||
z-index: 1;
|
||||
opacity: .9;
|
||||
opacity: .8;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
@@ -390,3 +389,12 @@
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
.map-back {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 15px;
|
||||
color: $--color-primary;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
636
src/assets/css/components/views/charts/panel.scss
Normal file
636
src/assets/css/components/views/charts/panel.scss
Normal file
@@ -0,0 +1,636 @@
|
||||
.cn-panel2 {
|
||||
position: relative;
|
||||
|
||||
.panel__time {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
|
||||
&>div {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.chart-list {
|
||||
&>.vue-grid-layout>.vue-grid-item {
|
||||
&>.panel-chart {
|
||||
border: 1px solid $--chart-box-border-color;
|
||||
background-color: #FFFFFF;
|
||||
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
|
||||
&.panel-chart--title-chart {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content:space-between;
|
||||
align-items:center;
|
||||
padding: 10px 20px 10px 18px;
|
||||
height: 47px;
|
||||
|
||||
font-size: 16px;
|
||||
color: $--color-text-primary;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.chart-header--float {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
box-sizing: border-box;
|
||||
height: 10px;
|
||||
opacity: 0;
|
||||
transition: all linear .2s;
|
||||
|
||||
&:hover {
|
||||
height: 47px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&.chart-header--title-chart {
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
padding: 0;
|
||||
}
|
||||
/*&:hover {
|
||||
background-color: $--chart-title-hover-background-color;
|
||||
|
||||
.chart-header__tools {
|
||||
.chart-header__tool .tool__icon {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
.chart-header__title {
|
||||
max-width: calc(100% - 100px);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chart-header__tools {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.chart-header__tool {
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
.tool__icon {
|
||||
// visibility: hidden;
|
||||
font-size: 14px;
|
||||
color: $--color-text-primary;
|
||||
}
|
||||
.nz-chart-dropdown {
|
||||
position: absolute;
|
||||
top: 44px;
|
||||
right: 0;
|
||||
left: unset;
|
||||
transform-origin: center top;
|
||||
z-index: 1000;
|
||||
width: 180px;
|
||||
li {
|
||||
padding-left: 15px !important;
|
||||
padding-right: 0 !important;
|
||||
width: calc(100% - 15px);
|
||||
text-align: left;
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover i {
|
||||
color: $--color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chart-header-error{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
.chart-screen-header.list-page{
|
||||
background: $--background-color-empty;
|
||||
}
|
||||
.chart-screen-header {
|
||||
display: flex;
|
||||
justify-content:space-between;
|
||||
align-items:center;
|
||||
padding: 0 20px 0 20px;
|
||||
height: 39px;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
color: $--color-text-primary;
|
||||
transition: all 0.2s;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-top: 15px;
|
||||
&.chart-header--float {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
box-sizing: border-box;
|
||||
height: 10px;
|
||||
opacity: 0;
|
||||
transition: all linear .2s;
|
||||
|
||||
&:hover {
|
||||
height: 39px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.chart-header__title {
|
||||
max-width: calc(100% - 100px);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
.chart-header__tools {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.chart-header__tool {
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
.tool__icon {
|
||||
visibility: hidden;
|
||||
font-size: 14px;
|
||||
color: $--color-text-primary;
|
||||
}
|
||||
.nz-chart-dropdown {
|
||||
position: absolute;
|
||||
top: 44px;
|
||||
right: 0;
|
||||
left: unset;
|
||||
transform-origin: center top;
|
||||
z-index: 1000;
|
||||
width: 180px;
|
||||
li {
|
||||
padding-left: 15px !important;
|
||||
padding-right: 0 !important;
|
||||
width: calc(100% - 15px);
|
||||
text-align: left;
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover i {
|
||||
color: $--color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chart-header-error{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
&>.cn-chart {
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
height: 100%;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,5 @@
|
||||
### 源码改动
|
||||
- theme-chalk/src/common/var.scss 首行增加$--theme属性
|
||||
- theme-chalk/src/mixins/mixins.scss 改动较多,如需了解请比对文件差异
|
||||
- // $arrow-selector: #{& + '__arrow'};
|
||||
改为 $arrow-selector: '.el-popper__arrow';
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
}
|
||||
|
||||
@at-root {
|
||||
#{renderThemeClass($selector)}##{&}#{$specSelector}.#{$block+$element-separator+$element+$modifierCombo} {
|
||||
#{renderThemeClass($selector)}#{&}#{$specSelector}.#{$block+$element-separator+$element+$modifierCombo} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@@ -164,9 +164,8 @@
|
||||
}
|
||||
|
||||
@mixin when($state) {
|
||||
$selector: &;
|
||||
@at-root {
|
||||
#{renderThemeClass($selector)}&.#{$state-prefix + $state} {
|
||||
&.#{$state-prefix + $state} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
word-wrap: break-word;
|
||||
visibility: visible;
|
||||
|
||||
$arrow-selector: #{& + '__arrow'};
|
||||
// $arrow-selector: #{& + '__arrow'};
|
||||
$arrow-selector: '.el-popper__arrow';
|
||||
|
||||
@include when(dark) {
|
||||
color: $--color-white;
|
||||
|
||||
@@ -51,4 +51,12 @@ $--chart-single-value-icon-background-color: #E8F6FF;
|
||||
|
||||
$--content-right-background-color: #EFF2F5; //右侧背景色
|
||||
|
||||
// 空白背景色
|
||||
$--background-color-empty: #fffffe;
|
||||
$--background-color-1: #EFEFEF;
|
||||
// 普通字色(覆盖element-ui内置变量)
|
||||
$--color-text-regular: #666665;
|
||||
$--border-color-light: #E7EAED;
|
||||
$--chart-box-border-color: $--border-color-light;
|
||||
$--chart-title-hover-background-color: #323238;
|
||||
@import './common';
|
||||
|
||||
@@ -51,4 +51,12 @@ $--chart-single-value-icon-background-color: #E8F6FF;
|
||||
|
||||
$--content-right-background-color: #EFF2F5; //右侧背景色
|
||||
|
||||
// 空白背景色
|
||||
$--background-color-empty: #fffffe;
|
||||
$--background-color-1: #EFEFEF;
|
||||
// 普通字色(覆盖element-ui内置变量)
|
||||
$--color-text-regular: #666665;
|
||||
$--border-color-light: #E7EAED;
|
||||
$--chart-box-border-color: $--border-color-light;
|
||||
$--chart-title-hover-background-color: $--background-color-1;
|
||||
@import './common';
|
||||
|
||||
36
src/components/common/Loading.vue
Normal file
36
src/components/common/Loading.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="chart__loading" v-show="showLoading">
|
||||
<i class="el-icon-loading"></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading',
|
||||
props: {
|
||||
loading: Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startLoading () {
|
||||
this.showLoading = true
|
||||
},
|
||||
endLoading () {
|
||||
this.showLoading = false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
loading: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler (n) {
|
||||
this.showLoading = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -5,6 +5,8 @@
|
||||
<cn-header></cn-header>
|
||||
<cn-container v-if="containerShow" ref="container"></cn-container>
|
||||
</main>
|
||||
<!-- 临时文本dom,用来计算文本长度 -->
|
||||
<span class="temp-dom"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rightBoxMixin from '@/mixins/rightBox'
|
||||
import rightBoxMixin from '@/mixins/right-box'
|
||||
import { get, post, put } from '@/utils/http'
|
||||
import { panelTypeAndRouteMapping } from '@/utils/constants'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rightBoxMixin from '@/mixins/rightBox'
|
||||
import rightBoxMixin from '@/mixins/right-box'
|
||||
import { api } from '@/utils/api'
|
||||
import { VAceEditor } from 'vue3-ace-editor'
|
||||
import 'ace-builds/src-noconflict/mode-javascript'
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rightBoxMixin from '@/mixins/rightBox'
|
||||
import rightBoxMixin from '@/mixins/right-box'
|
||||
import { get, post, put } from '@/utils/http'
|
||||
export default {
|
||||
name: 'I18nBox',
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rightBoxMixin from '@/mixins/rightBox'
|
||||
import rightBoxMixin from '@/mixins/right-box'
|
||||
import { get, post, put } from '@/utils/http'
|
||||
export default {
|
||||
name: 'userBox',
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
<el-switch
|
||||
id="account-input-status"
|
||||
v-model="editObject.status"
|
||||
:active-color="theme.themeColor"
|
||||
:disabled="(editObject.username === loginName) || (editObject.username==='admin' && editObject.id==1)"
|
||||
:active-value="1"
|
||||
:inactive-value="0">
|
||||
@@ -85,7 +84,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rightBoxMixin from '@/mixins/rightBox'
|
||||
import rightBoxMixin from '@/mixins/right-box'
|
||||
import { get, post, put } from '@/utils/http'
|
||||
export default {
|
||||
name: 'UserBox',
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
<el-switch
|
||||
v-if="scope.row.id"
|
||||
v-model="scope.row.status"
|
||||
:active-color="theme.themeColor"
|
||||
active-value="1"
|
||||
:disabled="(scope.row.username === loginName) || (scope.row.username==='admin' && scope.row.id==1) "
|
||||
inactive-value="0"
|
||||
|
||||
@@ -11,7 +11,7 @@ import i18n from '@/i18n'
|
||||
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
||||
import 'highlight.js/styles/color-brewer.css'
|
||||
import '@/assets/css/main.scss' // 样式入口
|
||||
// import VueGridLayout from 'vue-grid-layout'
|
||||
import VueGridLayout from 'vue-grid-layout'
|
||||
import ElementPlus from 'element-plus'
|
||||
import dayjs from 'dayjs'
|
||||
import utc from 'dayjs/plugin/utc' // dependent on utc plugin
|
||||
@@ -34,7 +34,7 @@ app.use(store)
|
||||
app.use(ElementPlus)
|
||||
app.use(i18n)
|
||||
app.use(hljsVuePlugin)
|
||||
// app.use(VueGridLayout)
|
||||
app.use(VueGridLayout)
|
||||
|
||||
app.directive('has', hasPermission) // 注册指令
|
||||
app.directive('click-outside', clickOutside)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import theme from '@/assets/css/theme.scss'
|
||||
import { hasButton } from '@/permission'
|
||||
export default {
|
||||
data () {
|
||||
@@ -11,7 +10,6 @@ export default {
|
||||
refresh: false,
|
||||
query: false
|
||||
},
|
||||
theme: theme, // scss主题变量
|
||||
prevent_opt: {
|
||||
save: false,
|
||||
import: false,
|
||||
|
||||
@@ -8,10 +8,9 @@ import { storageKey } from '@/utils/constants'
|
||||
import { loadI18n } from '@/i18n'
|
||||
|
||||
const loginWhiteList = ['/login', '/'] // 免登陆白名单
|
||||
const permissionWhiteList = [...loginWhiteList, '/entityDetail'] // 权限白名单
|
||||
const permissionWhiteList = [...loginWhiteList] // 权限白名单
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
// await test(to, from)
|
||||
// 加载iso-3166-2资源
|
||||
loadGeoData()
|
||||
// 加载baseUrl
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createStore } from 'vuex'
|
||||
import user from './modules/user'
|
||||
import panel from './modules/panel'
|
||||
|
||||
const store = createStore({
|
||||
modules: {
|
||||
user
|
||||
user,
|
||||
panel
|
||||
},
|
||||
state () {
|
||||
return {
|
||||
|
||||
127
src/store/modules/panel.js
Normal file
127
src/store/modules/panel.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const panel = {
|
||||
state: {
|
||||
showRightBox: false,
|
||||
chart: '',
|
||||
delChart: false,
|
||||
groupId: '',
|
||||
type: '',
|
||||
timeRange: [],
|
||||
nowTimeType: {},
|
||||
headerH: 0.5,
|
||||
headerHPadding: 0.5,
|
||||
rowHeight: 150,
|
||||
chartListId: '',
|
||||
chartLastPosition: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setShowRightBox (state, flag) {
|
||||
state.showRightBox = flag
|
||||
},
|
||||
setChart (state, chart) {
|
||||
state.chart = chart
|
||||
},
|
||||
setDelChart (state, flag) {
|
||||
state.delChart = flag
|
||||
},
|
||||
setType (state, type) {
|
||||
state.type = type
|
||||
},
|
||||
setGroupId (state, id) {
|
||||
state.groupId = id
|
||||
},
|
||||
setPanelTime (state, time) {
|
||||
state.timeRange = time
|
||||
},
|
||||
setPanelNowTimeType (state, nowTimeType) {
|
||||
state.nowTimeType = nowTimeType
|
||||
},
|
||||
setChartLastPosition (state, position) {
|
||||
state.chartLastPosition = position
|
||||
},
|
||||
setHeaderH (state, h) {
|
||||
state.headerH = h.headerH
|
||||
state.headerHPadding = h.headerHPadding
|
||||
state.rowHeight = h.rowHeight
|
||||
},
|
||||
cleanPanel (state) {
|
||||
state.showRightBox = false
|
||||
state.chart = ''
|
||||
state.delChart = false
|
||||
state.groupId = ''
|
||||
state.type = ''
|
||||
},
|
||||
setChartListId (state, id) {
|
||||
state.chartListId = id
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getShowRightBox (state) {
|
||||
return state.showRightBox
|
||||
},
|
||||
getChart (state) {
|
||||
return state.chart
|
||||
},
|
||||
getType (state) {
|
||||
return state.type
|
||||
},
|
||||
getGroupId (state) {
|
||||
return state.groupId
|
||||
},
|
||||
getTimeRange (state) {
|
||||
return state.timeRange
|
||||
},
|
||||
getNowTimeType (state) {
|
||||
return state.nowTimeType
|
||||
},
|
||||
getDelChart (state) {
|
||||
return state.delChart
|
||||
},
|
||||
getHeaderH (state) {
|
||||
return state.headerH
|
||||
},
|
||||
getHeaderHPadding (state) {
|
||||
return state.headerHPadding
|
||||
},
|
||||
getRowHeight (state) {
|
||||
return state.rowHeight
|
||||
},
|
||||
getChartLastPosition (state, position) {
|
||||
return state.chartLastPosition
|
||||
},
|
||||
getChartListId (state, id) {
|
||||
return state.chartListId
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
dispatchShowRightBox (store, flag) {
|
||||
store.commit('setShowRightBox', flag)
|
||||
},
|
||||
dispatchChart (store, chart) {
|
||||
store.commit('setShowRightBox', chart)
|
||||
},
|
||||
dispatchDelChart (store, playload) {
|
||||
store.commit('setDelChart', true)
|
||||
store.commit('setChart', playload.chart)
|
||||
store.commit('setType', playload.type)
|
||||
},
|
||||
dispatchPanelTime (store, playload) {
|
||||
store.commit('setPanelTime', playload.time)
|
||||
store.commit('setPanelNowTimeType', playload.nowTimeType)
|
||||
},
|
||||
dispatchEditChart (store, playload) {
|
||||
store.commit('setShowRightBox', true)
|
||||
store.commit('setChart', playload.chart)
|
||||
store.commit('setType', playload.type)
|
||||
},
|
||||
dispatchHeaderH (store, playload) {
|
||||
store.commit('setHeaderH', playload.headerH)
|
||||
},
|
||||
clearPanel (store) {
|
||||
store.commit('cleanPanel')
|
||||
}
|
||||
}
|
||||
}
|
||||
export default panel
|
||||
@@ -129,7 +129,12 @@ export const unitTypes = {
|
||||
export const chartTableDefaultPageSize = 10 // table类型图表默认每页数据量
|
||||
export const chartTableTopOptions = [10, 100] // table类型图表的TOP-N选项
|
||||
export const chartActiveIpTableOrderOptions = ['machine'] // active ip table类型图表的order 选项
|
||||
export const chartPieTableTopOptions = [{ name: 'Sessions', value: 'sessions' }, { name: 'Packets', value: 'packets' }, { name: 'Bytes', value: 'bytes' }] // table类型图表的TOP-N选项
|
||||
// table类型图表的TOP-N选项
|
||||
export const chartPieTableTopOptions = [
|
||||
{ name: 'Sessions', value: 'sessions' },
|
||||
{ name: 'Packets', value: 'packets' },
|
||||
{ name: 'Bytes', value: 'bytes' }
|
||||
]
|
||||
|
||||
export const iso36112 = {
|
||||
[storageKey.iso36112Capital]: 'data/countriesWithCapital',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import _ from 'lodash'
|
||||
// 获取初始化时间,默认最近一周
|
||||
Date.prototype.setStart = function () {
|
||||
this.setHours(0)
|
||||
@@ -9,128 +10,28 @@ Date.prototype.setEnd = function () {
|
||||
this.setMinutes(59)
|
||||
this.setSeconds(59)
|
||||
}
|
||||
|
||||
export function getDefaultDate () {
|
||||
let start = this.getDays(-7)
|
||||
let end = this.getDays(0)
|
||||
start.setStart()
|
||||
end.setEnd()
|
||||
// let start = this.getHoursTime(-1);
|
||||
// let end = this.getHoursTime(0);
|
||||
start = this.timeFormate(start, 'yyyy-MM-dd hh:mm:ss')
|
||||
end = this.timeFormate(end, 'yyyy-MM-dd hh:mm:ss')
|
||||
this.selectDate = [start, end]
|
||||
// 将时间转化为秒
|
||||
export function getSecond (time) {
|
||||
const ms = getMillisecond(time)
|
||||
return ms ? Math.floor(ms / 1000) : null
|
||||
}
|
||||
|
||||
export function getHoursTime (hours) {
|
||||
const today = new Date().getTime()
|
||||
const date = new Date(today + (hours * 60 * 60 * 1000))
|
||||
return date
|
||||
}
|
||||
|
||||
// 初始化日期
|
||||
export function getDays (days) {
|
||||
const today = new Date().getTime()
|
||||
return new Date(today + (days * 24 * 60 * 60 * 1000))
|
||||
}
|
||||
export function formatDate (date, type) {
|
||||
const yy = date.getFullYear()
|
||||
const dateM = date.getMonth() + 1
|
||||
const mm = dateM > 9 ? dateM : `0${dateM}`
|
||||
const dateD = date.getDate()
|
||||
const dd = dateD > 9 ? dateD : `0${dateD}`
|
||||
if (type) {
|
||||
return `${yy}${type}${mm}${type}${dd}`
|
||||
}
|
||||
return `${yy}${mm}${dd}`
|
||||
}
|
||||
export function timeFormate (date, fmt = 'yyyy-MM-dd hh:mm:ss') {
|
||||
const time = new Date(date)
|
||||
let week = ''
|
||||
switch (time.getDay()) {
|
||||
case 0:
|
||||
week = '周日'
|
||||
break
|
||||
case 1:
|
||||
week = '周一'
|
||||
break
|
||||
case 2:
|
||||
week = '周二'
|
||||
break
|
||||
case 3:
|
||||
week = '周三'
|
||||
break
|
||||
case 4:
|
||||
week = '周四'
|
||||
break
|
||||
case 5:
|
||||
week = '周五'
|
||||
break
|
||||
case 6:
|
||||
week = '周六'
|
||||
break
|
||||
default:
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
week = ''
|
||||
break
|
||||
}
|
||||
}
|
||||
export function getStep (startTime, endTime) {
|
||||
const start = new Date(startTime)
|
||||
const end = new Date(endTime)
|
||||
let step = '15s'
|
||||
const numInterval = end.getTime() - start.getTime()
|
||||
const oneDay = 86400000
|
||||
const sevenDay = 604800000
|
||||
const thirtyDay = 2592000000
|
||||
if (numInterval < oneDay) { // 小于1天,step为15s
|
||||
step = '15s'
|
||||
} else if (numInterval < sevenDay) {
|
||||
step = '5m'
|
||||
} else if (numInterval < thirtyDay) {
|
||||
step = '10m'
|
||||
} else {
|
||||
step = '30m'
|
||||
}
|
||||
return step
|
||||
}
|
||||
export function getNumStr (num) {
|
||||
if (num >= 1000) {
|
||||
const kbNum = num / 1000
|
||||
if (kbNum >= 1000) {
|
||||
const mbNum = kbNum / 1000
|
||||
if (mbNum > 1000) {
|
||||
const gbNum = mbNum / 1000
|
||||
if (gbNum > 1000) {
|
||||
const tbNum = gbNum / 1000
|
||||
if (tbNum > 1000) {
|
||||
const pbNum = tbNum / 1000
|
||||
return `${pbNum.toFixed(2)}PB`
|
||||
}
|
||||
return `${tbNum.toFixed(2)}TB`
|
||||
}
|
||||
return `${gbNum.toFixed(2)}GB`
|
||||
}
|
||||
return `${mbNum.toFixed(2)}MB`
|
||||
// 将时间转化为毫秒
|
||||
export function getMillisecond (time) {
|
||||
let ms = null
|
||||
if (_.isDate(time)) {
|
||||
ms = time.getTime()
|
||||
} else if (_.isNumber(time)) {
|
||||
const timeStr = _.toString(time)
|
||||
const difference = timeStr.length - 13
|
||||
if (difference >= 0) {
|
||||
ms = timeStr.slice(0, 13)
|
||||
} else {
|
||||
ms = Math.floor(time * (10 ** (0 - difference)))
|
||||
}
|
||||
return `${kbNum.toFixed(2)}KB`
|
||||
}
|
||||
return num.toFixed(2)
|
||||
}
|
||||
export function debounce (fn, delay) {
|
||||
// 记录上一次的延时器
|
||||
let timer = null
|
||||
delay = delay || 200
|
||||
return function () {
|
||||
const args = arguments
|
||||
const that = this
|
||||
// 清除上一次延时器
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(that, args)
|
||||
}, delay)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
// 初始化日期
|
||||
export function getNowTime (interval) {
|
||||
const endTime = window.$dayJs.tz().valueOf()
|
||||
const startTime = endTime - interval * 60 * 1000
|
||||
|
||||
@@ -425,6 +425,7 @@ export function replaceUrlPlaceholder (url, params) {
|
||||
_.forIn(params, (value, key) => {
|
||||
url = url.replace('{{' + key + '}}', value)
|
||||
})
|
||||
url = url.replace(/{{(.*?)}}/g, '')
|
||||
return url
|
||||
}
|
||||
// 双引号替换为单引号
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
<template v-for="chart in tab.children">
|
||||
<chart
|
||||
v-if="activeTab == tab.id"
|
||||
:key="chart.id"
|
||||
:chart="chart"
|
||||
:key="Chart.id"
|
||||
:chart="Chart"
|
||||
:time-filter="timeFilter"
|
||||
:ref="`chart-${chart.id}`"
|
||||
:ref="`chart-${Chart.id}`"
|
||||
:entity="entity"
|
||||
@getCurrentTimeRange="getCurrentTimeRange"
|
||||
></chart>
|
||||
@@ -367,11 +367,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="cn-chart__body">
|
||||
<template v-for="chart in chartInfo.children" :key="chart.id">
|
||||
<template v-for="chart in chartInfo.children" :key="Chart.id">
|
||||
<chart
|
||||
:chart="chart"
|
||||
:chart="Chart"
|
||||
:time-filter="timeFilter"
|
||||
:ref="`chart-${chart.id}`"
|
||||
:ref="`chart-${Chart.id}`"
|
||||
:entity="entity"
|
||||
:parent-data="groupData"
|
||||
:from-block="fromBlock"
|
||||
@@ -402,11 +402,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="cn-chart__body">
|
||||
<template v-for="chart in chartInfo.children" :key="chart.id">
|
||||
<template v-for="chart in chartInfo.children" :key="Chart.id">
|
||||
<chart
|
||||
:chart="chart"
|
||||
:chart="Chart"
|
||||
:time-filter="chartTimeFilter"
|
||||
:ref="`chart-${chart.id}`"
|
||||
:ref="`chart-${Chart.id}`"
|
||||
:entity="entity"
|
||||
:parent-data="groupData"
|
||||
:from-block="true"
|
||||
|
||||
132
src/views/charts/Chart2.vue
Normal file
132
src/views/charts/Chart2.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="cn-chart">
|
||||
<loading :loading="loading"></loading>
|
||||
<chart-no-data v-if="!loading && (isNoData || isError)"></chart-no-data>
|
||||
<template v-else>
|
||||
|
||||
<chart-tabs
|
||||
v-if="isTabs"
|
||||
:chart-info="chartInfo"
|
||||
:query-params="queryParams"
|
||||
></chart-tabs>
|
||||
|
||||
<chart-map
|
||||
v-else-if="isMap"
|
||||
:chart-info="chartInfo"
|
||||
:chart-data="chartData"
|
||||
:query-params="queryParams"
|
||||
@showLoading="showLoading"
|
||||
></chart-map>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Loading from '@/components/common/Loading'
|
||||
import ChartNoData from './charts/ChartNoData'
|
||||
import ChartTabs from './charts/ChartTabs'
|
||||
import ChartMap from './charts/ChartMap'
|
||||
import {
|
||||
isEcharts,
|
||||
isSingleValue,
|
||||
isTable,
|
||||
isActiveIpTable,
|
||||
isTitle,
|
||||
isMap,
|
||||
getOption,
|
||||
isEchartsWithTable,
|
||||
isEchartsWithStatistics,
|
||||
isEchartsTimeBar,
|
||||
isEchartsCategoryBar,
|
||||
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: {
|
||||
Loading,
|
||||
ChartNoData,
|
||||
ChartTabs,
|
||||
ChartMap
|
||||
},
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
|
||||
queryParams: Object, // 接口请求参数
|
||||
customChartOption: Object, // 需要自定义echarts的option时传入,非必须;传入该值时仍需传对应格式的chartData
|
||||
isFullscreen: Boolean,
|
||||
loading: Boolean,
|
||||
panelLock: Boolean,
|
||||
isError: Boolean
|
||||
},
|
||||
computed: {
|
||||
isNoData () {
|
||||
return _.isEmpty(this.chartData)
|
||||
},
|
||||
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)
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
return {
|
||||
isEcharts: isEcharts(props.chartInfo.type),
|
||||
isEchartsTimeBar: isEchartsTimeBar(props.chartInfo.type),
|
||||
isEchartsCategoryBar: isEchartsCategoryBar(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),
|
||||
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>
|
||||
52
src/views/charts/ChartHeader.vue
Normal file
52
src/views/charts/ChartHeader.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div class="chart-header" :class="{'chart-header--title-chart': isTitle}">
|
||||
<div class="chart-header__title">{{chartInfo.name}}</div>
|
||||
<chart-error :isError="isError" :errorInfo="errorInfo"></chart-error>
|
||||
<div class="chart-header__tools" v-if="!isTitle">
|
||||
<el-popover trigger="click" 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>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isTitle } from './charts/tools'
|
||||
import ChartError from '@/components/charts/ChartError'
|
||||
export default {
|
||||
name: 'ChartHeader',
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
errorInfo: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isError: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ChartError
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dropdownMenuShow: false,
|
||||
errorText: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh () {
|
||||
this.$emit('refresh')
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
return {
|
||||
isTitle: isTitle(props.chartInfo.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<div style="padding: 10px 0 20px 20px; overflow: auto" v-if="!isEntityDetail">
|
||||
<div id="cn-panel"
|
||||
:class="(isCryptocurrency)?'cn-panel cn-panel-crypto':'cn-panel'"
|
||||
>
|
||||
<div style="padding: 10px 10px 20px 10px; overflow: auto" v-if="!isEntityDetail">
|
||||
<div id="cn-panel" class="cn-panel2">
|
||||
<div class="panel__time">
|
||||
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
||||
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
||||
</div>
|
||||
<chart
|
||||
<panel-chart-list
|
||||
:time-filter="timeFilter"
|
||||
:data-list="chartList"
|
||||
:panel-lock="panelLock"
|
||||
>
|
||||
</panel-chart-list>
|
||||
<!-- <chart
|
||||
v-for="chart in chartList"
|
||||
:key="chart.id"
|
||||
:chart="chart"
|
||||
@@ -15,7 +19,7 @@
|
||||
:ref="`chart-${chart.id}`"
|
||||
:entity="entity"
|
||||
@getCurrentTimeRange="getCurrentTimeRange"
|
||||
></chart>
|
||||
></chart>-->
|
||||
<!-- <grid-layout v-model:layout="chartList"
|
||||
:col-num="12"
|
||||
:row-height="30"
|
||||
@@ -40,12 +44,12 @@
|
||||
<div class="entity-detail__body">
|
||||
<div class="cn-panel" @scroll="scroll" id="cn-panel">
|
||||
<template v-for="chart in chartList" :key="chart.id">
|
||||
<chart
|
||||
<!-- <chart
|
||||
:chart="chart"
|
||||
:ref="`chart-${chart.id}`"
|
||||
:entity="entity"
|
||||
@getCurrentTimeRange="getCurrentTimeRange"
|
||||
></chart>
|
||||
></chart>-->
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +62,7 @@ import { ref } from 'vue'
|
||||
import { panelTypeAndRouteMapping } from '@/utils/constants'
|
||||
import { api, getPanelList, getChartList } from '@/utils/api'
|
||||
import { getNowTime } from '@/utils/date-util'
|
||||
import Chart from './Chart'
|
||||
import PanelChartList from './PanelChartList'
|
||||
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
|
||||
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
|
||||
|
||||
@@ -70,13 +74,14 @@ export default {
|
||||
typeName: String
|
||||
},
|
||||
components: {
|
||||
Chart,
|
||||
DateTimeRange,
|
||||
TimeRefresh
|
||||
TimeRefresh,
|
||||
PanelChartList
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
chartList: [], // 普通panel的chart
|
||||
panelLock: true,
|
||||
// entity详情的chart
|
||||
detailTabs: [],
|
||||
detailChartList: [],
|
||||
|
||||
309
src/views/charts/PanelChart.vue
Normal file
309
src/views/charts/PanelChart.vue
Normal file
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<!-- chart外层箱子 -->
|
||||
<div :class="{'panel-chart--fullscreen': isFullscreen, 'panel-chart--title-chart': isTitle}" class="panel-chart" :id="isFullscreen ? ('chart-screen-' + chartInfo.id ) : ('chart-local-' + chartInfo.id)">
|
||||
<!-- title和工具栏,支持浮动 -->
|
||||
<chart-header
|
||||
v-if="!isFullscreen && showHeader"
|
||||
:is-error="isError"
|
||||
:error-info="errorInfo"
|
||||
:chart-data="chartData"
|
||||
:chart-info="chartInfo"
|
||||
@loadMore="loadMore"
|
||||
@refresh="refresh"
|
||||
@showFullscreen="showFullscreen"
|
||||
></chart-header>
|
||||
<!-- chart -->
|
||||
<!-- 数据查询后传入chart组件,chart组件内不查询,只根据接传递的数据来渲染 -->
|
||||
<chart
|
||||
ref="chart"
|
||||
v-if="(!isGroup || !chartInfo.param.collapse) && !isTitle"
|
||||
:chart-data="chartData"
|
||||
:chart-info="chartInfo"
|
||||
:query-params="queryParams"
|
||||
:panel-lock="panelLock"
|
||||
:is-error="isError"
|
||||
:loading="loading"
|
||||
:is-fullscreen="isFullscreen"
|
||||
@showLoading="showLoading"
|
||||
></chart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChartHeader from './ChartHeader'
|
||||
import Chart from '@/views/charts/Chart2'
|
||||
import {
|
||||
isEcharts,
|
||||
isSingleValue,
|
||||
isTable,
|
||||
isActiveIpTable,
|
||||
isTitle,
|
||||
isMap,
|
||||
isEchartsWithTable,
|
||||
isEchartsWithStatistics,
|
||||
isEchartsTimeBar,
|
||||
isEchartsCategoryBar,
|
||||
isMapLine,
|
||||
isMapBlock,
|
||||
isSingleValueWithEcharts,
|
||||
isSingleValueWithEchartsTemp,
|
||||
isRelationShip,
|
||||
isTabs,
|
||||
isGroup,
|
||||
isSankey,
|
||||
isIpBasicInfo,
|
||||
isIpOpenPort,
|
||||
isIpHostedDomain,
|
||||
isDomainWhois,
|
||||
isDomainDnsRecord,
|
||||
isCryptocurrencyEventList,
|
||||
isAppBasicInfo,
|
||||
isAppRelatedDomain,
|
||||
isBlock
|
||||
} from './charts/tools'
|
||||
import { tableTitleMapping } from '@/components/charts/chart-table-title'
|
||||
import { replaceUrlPlaceholder } from '@/utils/tools'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
import { chartPieTableTopOptions, chartTableDefaultPageSize, chartTableTopOptions } from '@/utils/constants'
|
||||
import { get } from '@/utils/http'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'PanelChart',
|
||||
components: {
|
||||
ChartHeader,
|
||||
Chart
|
||||
},
|
||||
props: {
|
||||
chartInfo: Object, // 其中的param json串已转化为对象
|
||||
timeFilter: Object, // 时间范围
|
||||
isFullscreen: Boolean,
|
||||
panelLock: Boolean,
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
chartData: null, // 图表要渲染的数据,请求接口得到,传入chart组件,chart组件内除特别情况(多级)外不做查询
|
||||
loading: false,
|
||||
isError: false, // 接口响应是否报错
|
||||
errorInfo: '', // 接口具体错误信息
|
||||
queryTimeRange: { // 实际查询接口时使用的时间
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
queryParams: {},
|
||||
standaloneTimeRange: { // 单个图表刷新时,重新获取时间范围,且不影响到其他图表
|
||||
use: false,
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
orderPieTable: chartPieTableTopOptions[0].value,
|
||||
// 挖矿右下角图
|
||||
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的所有数据
|
||||
},
|
||||
table: {
|
||||
pageSize: chartTableDefaultPageSize,
|
||||
limit: chartTableTopOptions[0], // top-n
|
||||
orderBy: 'sessions'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
headerH () {
|
||||
return this.$store.getters.getHeaderH
|
||||
},
|
||||
headerHPadding () {
|
||||
return this.$store.getters.getHeaderHPadding
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/* 参数 extraParams 额外请求参数,isRefresh 是否是刷新 */
|
||||
getChartData (url, extraParams = {}, isRefresh) {
|
||||
this.loading = true
|
||||
this.standaloneTimeRange.use = !!isRefresh
|
||||
try {
|
||||
// 单个图表刷新时,使用单独的时间
|
||||
if (this.standaloneTimeRange.use) {
|
||||
this.queryTimeRange = { startTime: getSecond(this.standaloneTimeRange.startTime), endTime: getSecond(this.standaloneTimeRange.endTime) }
|
||||
} else if (this.timeFilter) {
|
||||
this.queryTimeRange = { startTime: getSecond(this.timeFilter.startTime), endTime: getSecond(this.timeFilter.endTime) }
|
||||
} else {
|
||||
this.queryTimeRange = { startTime: getSecond(this.chartTimeFilter.startTime), endTime: getSecond(this.chartTimeFilter.endTime) }
|
||||
}
|
||||
const chartParams = this.chartInfo.params
|
||||
// 接口查询参数
|
||||
this.queryParams = {
|
||||
...this.handleQueryParams(),
|
||||
...this.queryTimeRange,
|
||||
...this.entity,
|
||||
...extraParams
|
||||
}
|
||||
const requestUrl = url || chartParams.url
|
||||
if (requestUrl) {
|
||||
get(replaceUrlPlaceholder(requestUrl, this.queryParams)).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.chartData = response.data.result
|
||||
this.isError = false
|
||||
} else {
|
||||
this.isError = true
|
||||
this.noData = true
|
||||
this.errorInfo = response.msg || response.message || 'Unknown'
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
handleQueryParams () {
|
||||
const params = {}
|
||||
if (this.isEchartsWithTable) {
|
||||
params.limit = 10
|
||||
params.order = this.orderPieTable
|
||||
} else if (this.isRelationShip) {
|
||||
params.limit = 5
|
||||
} else if (this.isActiveIpTable) {
|
||||
params.order = this.activeIpTable.orderBy
|
||||
} else if (this.isTable) {
|
||||
params.limit = this.table.limit
|
||||
params.order = this.table.orderBy
|
||||
}
|
||||
return params
|
||||
},
|
||||
resize () {
|
||||
this.$refs.chart.resize()
|
||||
},
|
||||
refresh () {
|
||||
const myEndTime = window.$dayJs.tz().valueOf()
|
||||
const myStartTime = myEndTime - this.chartTimeFilter.dateRangeValue * 60 * 1000
|
||||
this.standaloneTimeRange.use = true
|
||||
this.standaloneTimeRange.startTime = myStartTime
|
||||
this.standaloneTimeRange.endTime = myEndTime
|
||||
this.getChartData(null, {}, true)
|
||||
},
|
||||
showFullscreen (show) {
|
||||
this.$emit('showFullscreen', show, this.chartInfo)
|
||||
},
|
||||
loadMore () {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.chart && this.$refs.chart.$refs['chart' + this.chartInfo.id].initChart()
|
||||
})
|
||||
},
|
||||
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 }
|
||||
},
|
||||
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
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
showLoading (show) {
|
||||
this.loading = show
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.getChartData()
|
||||
},
|
||||
setup (props) {
|
||||
const dateRangeValue = 60
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||
return {
|
||||
chartTimeFilter,
|
||||
isEcharts: isEcharts(props.chartInfo.type),
|
||||
isEchartsTimeBar: isEchartsTimeBar(props.chartInfo.type),
|
||||
isEchartsCategoryBar: isEchartsCategoryBar(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),
|
||||
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>
|
||||
343
src/views/charts/PanelChartList.vue
Normal file
343
src/views/charts/PanelChartList.vue
Normal file
@@ -0,0 +1,343 @@
|
||||
<template>
|
||||
<div :id='`chartList${(isGroup ? "Group" : "") + timestamp}`' class="chart-list" ref="layoutBox">
|
||||
<grid-layout
|
||||
ref="layout"
|
||||
v-if="gridLayoutShow"
|
||||
v-model:layout="copyDataList"
|
||||
:col-num="30"
|
||||
:is-draggable="!panelLock"
|
||||
:is-resizable="!panelLock"
|
||||
:margin="[10, 10]"
|
||||
:row-height="40"
|
||||
:vertical-compact="true"
|
||||
:use-css-transforms="false"
|
||||
>
|
||||
<grid-item
|
||||
v-for="item in copyDataList"
|
||||
:key="item.id"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:w="item.w"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:static="item.static"
|
||||
:ref="'grid-item' + item.id"
|
||||
:isResizable = "item.type === 'group' ? false: null"
|
||||
dragAllowFrom=".chart-header"
|
||||
dragIgnoreFrom=".chart-header__tools"
|
||||
>
|
||||
<panel-chart
|
||||
:ref="'chart' + item.id"
|
||||
:chart-info="item"
|
||||
:show-header="true"
|
||||
:time-filter="timeFilter"
|
||||
@showFullscreen="showFullscreen"
|
||||
></panel-chart>
|
||||
</grid-item>
|
||||
</grid-layout>
|
||||
<!-- noData -->
|
||||
<div v-if="noData" class="no-data">
|
||||
<div class="no-data-div">No data</div>
|
||||
</div>
|
||||
<!-- 全屏查看 -->
|
||||
<el-dialog
|
||||
v-model="fullscreen.visible"
|
||||
:show-close="false"
|
||||
class="chart-fullscreen"
|
||||
destroy-on-close
|
||||
fullscreen
|
||||
:modal-append-to-body="false"
|
||||
>
|
||||
<panel-chart
|
||||
:ref="'chart-fullscreen' + fullscreen.chartInfo.id"
|
||||
:chart-info="fullscreen.chartInfo"
|
||||
:is-fullscreen="true"
|
||||
:panelLock="panelLock"
|
||||
:time-filter="timeFilter"
|
||||
@showFullscreen="showFullscreen"
|
||||
></panel-chart>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PanelChart from '@/views/charts/PanelChart'
|
||||
import VueGridLayout from 'vue-grid-layout'
|
||||
import { getTypeCategory } from './charts/tools'
|
||||
|
||||
export default {
|
||||
name: 'PanelChartList',
|
||||
components: {
|
||||
PanelChart,
|
||||
GridLayout: VueGridLayout.GridLayout,
|
||||
GridItem: VueGridLayout.GridItem
|
||||
},
|
||||
props: {
|
||||
timeFilter: Object, // 时间范围
|
||||
panelLock: { type: Boolean, default: true },
|
||||
isGroup: Boolean,
|
||||
dataList: Array // 看板中所有图表信息
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
gridLayoutLoading: false,
|
||||
gridLayoutShow: false,
|
||||
copyDataList: [],
|
||||
noData: false, // no data
|
||||
tempDom: { height: '', width: '' },
|
||||
stepWidth: null,
|
||||
timer: null,
|
||||
timestamp: new Date().getTime(),
|
||||
fullscreen: {
|
||||
visible: false,
|
||||
chartData: [],
|
||||
chartInfo: {}
|
||||
},
|
||||
scrollTop: 0,
|
||||
scrollTopTimer: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const dom = document.getElementById(this.isGroup ? `chartListGroup${this.timestamp}` : `chartList${this.timestamp}`)
|
||||
if (dom) {
|
||||
this.stepWidth = Math.floor(dom.offsetWidth / 12)
|
||||
}
|
||||
},
|
||||
showFullscreen (show, chartInfo) {
|
||||
this.fullscreen.chartInfo = chartInfo
|
||||
this.fullscreen.visible = show
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataList: {
|
||||
deep: true,
|
||||
handler (n, o) {
|
||||
this.gridLayoutShow = false
|
||||
this.gridLayoutLoading = true
|
||||
this.noData = !n || n.length < 1
|
||||
/*const nn = JSON.parse(`
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Sessions",
|
||||
"i18n": "overall.sessions",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 11,
|
||||
"x": 20,
|
||||
"y": 1,
|
||||
"w": 10,
|
||||
"h": 5,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/sessions?startTime={{startTime}}&endTime={{endTime}}\\",\\"unitType\\":\\"number\\"}",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Traffic summary",
|
||||
"i18n": "trafficSummary.trafficSummary",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 93,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 30,
|
||||
"h": 1,
|
||||
"params": "",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Active list",
|
||||
"i18n": "trafficSummary.activeList",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 93,
|
||||
"x": 0,
|
||||
"y": 16,
|
||||
"w": 30,
|
||||
"h": 1,
|
||||
"params": "",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Domain analysis statistics",
|
||||
"i18n": "trafficSummary.domainStatistics",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 93,
|
||||
"x": 0,
|
||||
"y": 35,
|
||||
"w": 30,
|
||||
"h": 1,
|
||||
"params": "",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Packets",
|
||||
"i18n": "overall.packets",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 11,
|
||||
"x": 20,
|
||||
"y": 6,
|
||||
"w": 10,
|
||||
"h": 5,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/packets?startTime={{startTime}}&endTime={{endTime}}\\",\\"unitType\\":\\"number\\"}",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Throughput",
|
||||
"i18n": "trafficSummary.throughput",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 11,
|
||||
"x": 20,
|
||||
"y": 11,
|
||||
"w": 10,
|
||||
"h": 5,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/throughput?startTime={{startTime}}&endTime={{endTime}}\\",\\"unitType\\":\\"byte\\"}",
|
||||
"remark": "packets",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Active client",
|
||||
"i18n": "trafficSummary.activeClient",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 61,
|
||||
"x": 0,
|
||||
"y": 17,
|
||||
"w": 10,
|
||||
"h": 9,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/activeClientIP?startTime={{startTime}}&endTime={{endTime}}&order={{order}}&limit={{limit}}\\"}",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Domain category",
|
||||
"i18n": "trafficSummary.domainCategory",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 31,
|
||||
"x": 0,
|
||||
"y": 36,
|
||||
"w": 15,
|
||||
"h": 13,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/topDomainCategories?startTime={{startTime}}&endTime={{endTime}}&limit={{limit}}\\",\\"nameColumn\\":\\"fqdnCategoryName\\",\\"valueColumn\\":\\"uniqDomains\\",\\"tableNameColumn\\":\\"domain\\",\\"urlTable\\":\\"/interface/traffic/activeDomainCategories?startTime={{startTime}}&endTime={{endTime}}&fqdnCategoryName={{fqdnCategoryName}}&limit={{limit}}&order={{order}}\\",\\"urlChildrenTable\\":\\"/interface/traffic/domainCategoryServerIpList?startTime={{startTime}}&endTime={{endTime}}&order={{order}}&limit={{limit}}&domain={{domain}}\\"}",
|
||||
"remark": "",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Traffic map",
|
||||
"i18n": "trafficSummary.trafficMap",
|
||||
"panelId": 1,
|
||||
"pid": 0,
|
||||
"type": 2,
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"w": 20,
|
||||
"h": 15,
|
||||
"params": "{\\"url\\":\\"/interface/traffic/map?startTime={{startTime}}&endTime={{endTime}}&country={{country}}&province={{province}}&city={{city}}\\",\\"unitType\\":\\"byte\\",\\"valueColumn\\":\\"bytes\\"}",
|
||||
"remark": "traffic summaryyy",
|
||||
"state": 1,
|
||||
"buildIn": 0,
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"panel": {
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
`)*/
|
||||
const tempList = n.map(item => {
|
||||
let params = {}
|
||||
const height = item.h
|
||||
if (item.params) {
|
||||
try {
|
||||
params = JSON.parse(item.params)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
params.showHeader = true
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
i: item.id,
|
||||
w: item.w,
|
||||
h: height,
|
||||
x: item.x || 0,
|
||||
y: item.y || 0,
|
||||
params,
|
||||
category: getTypeCategory(item.type) // 类别,是echarts还是map等等
|
||||
}
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.copyDataList = JSON.parse(JSON.stringify(tempList))
|
||||
setTimeout(() => {
|
||||
this.gridLayoutShow = true
|
||||
})
|
||||
this.gridLayoutLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
263
src/views/charts/charts/ChartMap.vue
Normal file
263
src/views/charts/charts/ChartMap.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div class="map-back" v-show="showMapBackButton" @click="mapBack">< back</div>
|
||||
<div class="chart-drawing" :id="`chart${chartInfo.id}`"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as L from 'leaflet'
|
||||
import * as am4Core from '@amcharts/amcharts4/core'
|
||||
import * as am4Maps from '@amcharts/amcharts4/maps'
|
||||
import { getGeoData, replaceUrlPlaceholder } from '@/utils/tools'
|
||||
import { storageKey } from '@/utils/constants'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import icon from 'leaflet/dist/images/marker-icon.png'
|
||||
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
|
||||
import {
|
||||
isIpBasicInfo,
|
||||
isMapBlock
|
||||
} from './tools'
|
||||
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
|
||||
import { HeatLegend } from '@/components/amcharts/heatLegend'
|
||||
import { getData } from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'ChartMap',
|
||||
data () {
|
||||
return {
|
||||
myChart: null,
|
||||
mapPictureUrl: '/Tiles/{z}/{x}/{y}.png',
|
||||
showMapBackButton: false,
|
||||
polygonSeries: null, // 世界地图series
|
||||
countrySeries: null // 下钻国家series
|
||||
}
|
||||
},
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
chartData: [Array, Object],
|
||||
queryParams: Object
|
||||
},
|
||||
methods: {
|
||||
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
|
||||
this.loadLeafletMap()
|
||||
} 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)')
|
||||
this.loadAm4ChartMap(this.polygonSeries)
|
||||
// 地图点击事件
|
||||
polygonTemplate.events.on('hit', async ev => {
|
||||
const countryId = ev.target.dataItem.dataContext.id
|
||||
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()
|
||||
const country = ev.target.dataItem.dataContext.serverCountry
|
||||
const queryParams = { ...this.queryParams, country }
|
||||
const chartData = await getData(replaceUrlPlaceholder(this.chartInfo.params.url, queryParams))
|
||||
this.loadAm4ChartMap(this.countrySeries, ev.target.dataItem.dataContext.serverCountry, chartData)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
loadAm4ChartMap (polygonSeries, country, chartData) {
|
||||
this.$emit('showLoading', true)
|
||||
try {
|
||||
// 清除数据
|
||||
polygonSeries.data.splice(0)
|
||||
// 清除legend
|
||||
this.myChart.children.each((s, i) => {
|
||||
if (s && s.className !== 'Container') {
|
||||
this.myChart.children.removeIndex(i)
|
||||
}
|
||||
})
|
||||
|
||||
this.showMapBackButton = !!country
|
||||
const chartParams = this.chartInfo.params
|
||||
const data = chartData || this.chartData
|
||||
if (data && 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 ''
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
this.$emit('showLoading', false)
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
loadLeafletMap () {
|
||||
this.$emit('showLoading', true)
|
||||
try {
|
||||
this.myChart.setView([this.chartData.latitude, this.chartData.longitude], 5)
|
||||
const myIcon = L.divIcon({
|
||||
className: 'cn-icon cn-icon-position2 position-icon'
|
||||
})
|
||||
L.marker([this.chartData.latitude, this.chartData.longitude], { icon: myIcon }).addTo(this.myChart)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
this.$emit('showLoading', false)
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
mapBack () {
|
||||
this.countrySeries.hide()
|
||||
this.$nextTick(() => {
|
||||
this.showMapBackButton = false
|
||||
this.polygonSeries.show()
|
||||
this.myChart.goHome()
|
||||
})
|
||||
},
|
||||
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>
|
||||
`
|
||||
},
|
||||
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 }
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initMap(`chart${this.chartInfo.id}`)
|
||||
},
|
||||
setup (props) {
|
||||
return {
|
||||
isIpBasicInfo: isIpBasicInfo(props.chartInfo.type),
|
||||
isMapBlock: isMapBlock(props.chartInfo.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
9
src/views/charts/charts/ChartNoData.vue
Normal file
9
src/views/charts/charts/ChartNoData.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="panel-chart__no-data">No data</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ChartNoData'
|
||||
}
|
||||
</script>
|
||||
68
src/views/charts/charts/ChartTabs.vue
Normal file
68
src/views/charts/charts/ChartTabs.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<el-tabs
|
||||
class="cn-chart cn-chart__tabs"
|
||||
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" :key="chart.id">
|
||||
<panel-chart
|
||||
:ref="'chart' + chart.id"
|
||||
:chart-info="chart"
|
||||
:show-header="true"
|
||||
:time-filter="timeFilter"
|
||||
@showFullscreen="showFullscreen"
|
||||
></panel-chart>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import PanelChart from '@/views/charts/PanelChart'
|
||||
export default {
|
||||
name: 'ChartTabs',
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
|
||||
queryParams: Object // 接口请求参数
|
||||
},
|
||||
components: {
|
||||
PanelChart
|
||||
},
|
||||
computed: {
|
||||
timeFilter () {
|
||||
return {
|
||||
startTime: this.queryParams.startTime,
|
||||
endTime: this.queryParams.endTime
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showFullscreen () {
|
||||
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
let activeTab = ''
|
||||
if (!_.isEmpty(props.chartInfo.children)) {
|
||||
activeTab = `${props.chartInfo.children[0].id}`
|
||||
}
|
||||
return {
|
||||
activeTab
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
828
src/views/charts/charts/chart-options.js
Normal file
828
src/views/charts/charts/chart-options.js
Normal file
@@ -0,0 +1,828 @@
|
||||
/**
|
||||
* @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
|
||||
}
|
||||
135
src/views/charts/charts/options/bar.js
Normal file
135
src/views/charts/charts/options/bar.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import {
|
||||
categoryVerticalFormatter,
|
||||
chartColor,
|
||||
getCharBartColor,
|
||||
timeVerticalFormatter
|
||||
} from '@/views/charts/charts/tools'
|
||||
|
||||
export 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%'
|
||||
}]
|
||||
}
|
||||
export 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])
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
export 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 tDate = new Date(value)
|
||||
return [tDate.getMonth() + 1, tDate.getDate()].join('/') + ' ' + [tDate.getHours(), tDate.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])
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
25
src/views/charts/charts/options/graph.js
Normal file
25
src/views/charts/charts/options/graph.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export 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: []
|
||||
}
|
||||
]
|
||||
}
|
||||
274
src/views/charts/charts/options/line.js
Normal file
274
src/views/charts/charts/options/line.js
Normal file
@@ -0,0 +1,274 @@
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import { chartColor } from '@/views/charts/charts/chart-options'
|
||||
import { axisFormatter, tooLongFormatter } from '../tools'
|
||||
|
||||
export const line = {
|
||||
tooltip: {
|
||||
appendToBody: true,
|
||||
trigger: 'axis',
|
||||
textStyle: {
|
||||
width: '20px',
|
||||
overflow: 'truncate'
|
||||
},
|
||||
formatter: axisFormatter,
|
||||
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: []
|
||||
}
|
||||
]
|
||||
}
|
||||
export const lineWithStatistics = {
|
||||
tooltip: {
|
||||
appendToBody: true,
|
||||
trigger: 'axis',
|
||||
textStyle: {
|
||||
width: '20px',
|
||||
overflow: 'truncate'
|
||||
},
|
||||
formatter: axisFormatter,
|
||||
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: []
|
||||
}
|
||||
]
|
||||
}
|
||||
export const lineStack = {
|
||||
tooltip: {
|
||||
appendToBody: true,
|
||||
trigger: 'axis',
|
||||
textStyle: {
|
||||
width: '20px',
|
||||
overflow: 'truncate'
|
||||
},
|
||||
formatter: axisFormatter,
|
||||
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: []
|
||||
}
|
||||
]
|
||||
}
|
||||
export 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 entityListLine = {
|
||||
tooltip: {
|
||||
appendToBody: true,
|
||||
trigger: 'axis',
|
||||
textStyle: {
|
||||
width: '20px',
|
||||
overflow: 'truncate'
|
||||
},
|
||||
formatter: axisFormatter,
|
||||
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
|
||||
}
|
||||
]
|
||||
}
|
||||
93
src/views/charts/charts/options/pie.js
Normal file
93
src/views/charts/charts/options/pie.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { chartColor } from '@/views/charts/charts/chart-options'
|
||||
import { tooLongFormatter } from '../tools'
|
||||
|
||||
export 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)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
export 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)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
43
src/views/charts/charts/options/sankey.js
Normal file
43
src/views/charts/charts/options/sankey.js
Normal file
@@ -0,0 +1,43 @@
|
||||
export 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'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
337
src/views/charts/charts/tools.js
Normal file
337
src/views/charts/charts/tools.js
Normal file
@@ -0,0 +1,337 @@
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { format } from 'echarts'
|
||||
import _ from 'lodash'
|
||||
import { line, lineWithStatistics, lineStack, singleValueLine } from './options/line'
|
||||
import { ipOpenPortBar, timeBar, categoryBar } from './options/bar'
|
||||
import { pieWithTable, ipHostedDomain } from './options/pie'
|
||||
import { relationShip } from './options/graph'
|
||||
import { sankey } from './options/sankey'
|
||||
|
||||
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 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 } // 单值图中的折线图
|
||||
]
|
||||
export function getOption (type) {
|
||||
const mapping = typeOptionMappings.find(m => m.value === type)
|
||||
return mapping && mapping.option ? _.cloneDeep(mapping.option) : null
|
||||
}
|
||||
|
||||
/* 柱状图:挖矿事件统计(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
|
||||
}
|
||||
|
||||
|
||||
/* 根据type获取图表分类 */
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 根据type获取布局 */
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
export function getGroupHeight (arr) {
|
||||
if (arr.length) {
|
||||
let lastItem = []
|
||||
let maxY = arr[0].y
|
||||
arr.forEach((children, index) => {
|
||||
if (maxY === children.y) {
|
||||
lastItem.push(children)
|
||||
} else if (maxY < children.y) {
|
||||
maxY = children.y
|
||||
lastItem = [children]
|
||||
}
|
||||
})
|
||||
let maxHeight = 0
|
||||
lastItem.forEach(last => {
|
||||
if (maxHeight < last.height) {
|
||||
maxHeight = last.height
|
||||
}
|
||||
})
|
||||
if (maxY < 0) {
|
||||
maxY = 0
|
||||
}
|
||||
return maxHeight + maxY
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
export function getLayoutPosition (arr) {
|
||||
if (arr.length) {
|
||||
let lastItem = []
|
||||
let maxY = 0
|
||||
arr.forEach((children, index) => {
|
||||
if (maxY === children.y) {
|
||||
lastItem.push(children)
|
||||
} else if (maxY < children.y) {
|
||||
maxY = children.y
|
||||
lastItem = [children]
|
||||
}
|
||||
})
|
||||
let maxX = 0
|
||||
lastItem.forEach(last => {
|
||||
if (maxX < last.x + last.span) {
|
||||
maxX = last.x + last.span
|
||||
}
|
||||
})
|
||||
return {
|
||||
x: maxX,
|
||||
y: maxY
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
export function axisFormatter (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 tooLongFormatter (name) {
|
||||
return format.truncateText(name, 110, '12')
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import chartTable from '@/components/table/settings/ChartTable'
|
||||
import chartBox from '@/components/rightBox/settings/ChartBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import galaxyProxyBox from '@/components/rightBox/settings/GalaxyProxyBox'
|
||||
import galaxyProxyTable from '@/components/table/settings/GalaxyProxyTable'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import { api } from '@/utils/api'
|
||||
import { get, put } from '@/utils/http'
|
||||
import TopToolMoreOptions from '@/components/common/popBox/TopToolMoreOptions'
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import i18nTable from '@/components/table/settings/I18nTable'
|
||||
import i18nBox from '@/components/rightBox/settings/I18nBox'
|
||||
import { put } from '@/utils/http'
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import operationLogTable from '@/components/table/settings/OperationLogTable'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import rolesTable from '@/components/table/settings/RoleTable'
|
||||
import roleBox from '@/components/rightBox/settings/RoleBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/dataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import userTable from '@/components/table/settings/UserTable'
|
||||
import userBox from '@/components/rightBox/settings/UserBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
Reference in New Issue
Block a user