Compare commits

..

1 Commits

Author SHA1 Message Date
zhangyu
b822015daa feat: 隐藏menu 以及header 2022-03-07 13:38:47 +08:00
130 changed files with 2455 additions and 7108 deletions

0
2.md Normal file
View File

View File

@@ -29,7 +29,7 @@ npm run lint
### 3.图表组件库
图表echarts5.0
地图amCharts4
地图amCharts
拖拽 & ResizeVue-grid-layout  https://jbaysolutions.github.io/vue-grid-layout/guide/
### 4.响应式方案
@@ -51,7 +51,7 @@ https://www.lodashjs.com/
多个单词时,应该以高阶的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾
eg`SearchButtonClear.vue` 反例:`ClearSearchButton.vue`
- **文件夹**
使用小写,单词间使用连字符`-`连接,或使用驼峰格式
使用小写,单词间使用连字符`-`连接,或使用驼峰格式
eg`right-box``rightBox`

View File

@@ -12,8 +12,7 @@ module.exports = {
],
plugins: [
'@vue/babel-plugin-jsx',
['@babel/proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-private-methods', { loose: true }],
'@babel/proposal-class-properties',
'@babel/transform-runtime',
'lodash'
],

View File

@@ -9,7 +9,7 @@
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
},
"dependencies": {
"@amcharts/amcharts4": "^4.10.24",
"@amcharts/amcharts4": "^4.10.20",
"@amcharts/amcharts4-geodata": "^4.1.20",
"axios": "^0.21.1",
"babel-plugin-lodash": "^3.3.4",

File diff suppressed because one or more lines are too long

View File

@@ -4,12 +4,11 @@
</div>
</template>
<script>
import { storageKey } from '@/utils/constants'
export default {
name: 'App',
setup () {
// 处理刷新后 $dayJs的时区变为默认的问题
const timezone = localStorage.getItem(storageKey.sysTimezone) || ''
const timezone = localStorage.getItem('cn-sys-timezone') || ''
if (timezone) {
window.$dayJs.tz.setDefault(timezone)
} else {

View File

@@ -39,11 +39,7 @@
<script>
import { mapActions } from 'vuex'
import { post, get } from '@/utils/http'
import { useRouter } from 'vue-router'
import { storageKey } from '@/utils/constants'
import { api } from '@/utils/api'
import { post } from '@/utils/http'
export default {
name: 'Login',
@@ -66,18 +62,11 @@ export default {
return
}
this.loading = true
post(api.login, { username: this.username, pin: this.pin }).then(
post('sys/login', { username: this.username, pin: this.pin }).then(
res => {
if (res.code === 200) {
if (!this.$_.isEmpty(res.data.lang)) {
localStorage.setItem(storageKey.language, res.data.lang)
}
if (!this.$_.isEmpty(res.data.theme)) {
localStorage.setItem(storageKey.theme, res.data.theme)
}
res.loginSuccessPath = this.loginSuccessPath
this.loginSuccess(res)
localStorage.setItem(storageKey.username, this.username)
localStorage.setItem('cn-username', this.username)
} else if (res.code === 518005) {
this.$message.error(this.$t('Incorrect username or password'))
this.loading = false
@@ -93,36 +82,6 @@ export default {
this.blockOperation.query = false
this.$message.error(this.$t('tip.unknownError'))
})
},
appearance () {
get(api.appearance).then(res => {
if (res.code === 200) {
this.appearanceOut(res.data)
}
})
},
appearanceOut (data) {
if (this.$_.isEmpty(localStorage.getItem(storageKey.language))) {
localStorage.setItem(storageKey.language, data.lang)
}
if (this.$_.isEmpty(localStorage.getItem(storageKey.sysTimezone))) {
localStorage.setItem(storageKey.sysTimezone, data.timezone)
}
if (this.$_.isEmpty(localStorage.getItem(storageKey.theme))) {
localStorage.setItem(storageKey.theme, data.theme)
}
if (this.$_.isEmpty(localStorage.getItem(storageKey.dateFormat))) {
localStorage.setItem(storageKey.dateFormat, data.dateFormat)
}
}
},
mounted () {
this.appearance()
},
setup (props) {
const { currentRoute } = useRouter()
return {
loginSuccessPath: currentRoute.value.query.redirect
}
}
}

View File

@@ -21,10 +21,3 @@ body {
font-size: 14px;
position: fixed;
}
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}

View File

@@ -46,7 +46,7 @@
border: 1px solid #E6EAED;
}
.top-tool-search {
.top-tool-search.margin-r-20 {
.top-tool-btn {
border-left: none;
}
@@ -247,7 +247,7 @@
box-shadow: 1px 0 $--right-box-border-color;
}
.el-table:not(.no-operation):not(.chart-table).el-table--border .el-table__header-wrapper th:nth-last-child(3) {
//border-right: none !important;
border-right: none !important;
box-shadow: 1px 0 $--right-box-border-color;
}
.el-table__fixed-body-wrapper {

View File

@@ -66,11 +66,3 @@
border-color: rgba(154,154,154,0.20);
}
}
.entity__pagination .pagination {
.el-pager li.more + li {
display: none;
}
.el-pager li.number:not(:last-of-type) {
display: inline-block !important;
}
}

View File

@@ -41,7 +41,6 @@
@import './views/charts/chartAlarmInfo';
@import './views/chartHeader';
@import './views/charts/chartMap';
@import './views/report/builtinReport';
//@import '../chart';

View File

@@ -1,82 +1,42 @@
.cn-chart-header-button {
.cn-chart-header-button{
display: flex;
.cn-chart-header-button-group {
display: flex;
.el-button {
border-radius: 0%;
}
.el-button:hover {
background: #FFFFFF;
border-color: #0091FF;
}
.el-button:last-of-type {
border-radius: 0 2px 2px 0;
}
.el-button:first-of-type{
border-radius: 2px 0 0 2px;
}
.cn-chart-header-button-all {
border-color: #0091FF;
color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
}
.cn-chart-header-button-critical {
border-color: #0091FF;
color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
}
.cn-chart-header-button-high {
border-color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
color: #0091FF;
}
.cn-chart-header-button-low {
border-color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
color: #0091FF;
}
.cn-chart-header-button-info {
border-color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
color: #0091FF;
}
.cn-chart-header-button-medium {
border-color: #0091FF;
background-color: #FFFFFF;
z-index: 1;
color: #0091FF;
}
.el-button--default {
height: 24px;
min-height: 24px;
display: flex;
justify-content: space-around;
align-items: center;
font-family: Roboto-Regular;
font-size: 12px;
font-weight: 400;
}
.cn-chart-header-button-all{
border: 1px solid #0091FF;
color: #0091FF;
background-color: #FFFFFF;
}
.cn-chart-header-button-critical{
border: 1px solid #0091FF;
color: #0091FF;
background-color: #FFFFFF;
.header__operation-btn {
margin-left: 12px;
cursor: pointer;
color: #999;
}
}
.cn-chart-header-button-high{
border: 1px solid #0091FF;
background-color: #FFFFFF;
color: #0091FF;
}
.cn-chart-header-button-low{
border: 1px solid #0091FF;
background-color: #FFFFFF;
color: #0091FF;
}
.cn-chart-header-button-info{
border: 1px solid #0091FF;
background-color: #FFFFFF;
color: #0091FF;
}
.cn-chart-header-button-medium{
border: 1px solid #0091FF;
background-color: #FFFFFF;
color: #0091FF;
}
.el-button--default{
height: 24px;
border-radius: 2px 0 0 2px;
min-height:24px;
display: flex;
justify-content: center;
align-items: center;
}
}

View File

@@ -1,11 +1,10 @@
.cn-chart__one-situation-statistics{
height: 100%;
.one-situation-statistics__box {
.chart-one-situation-statistics{
padding-top: 22px;
.situation-statistics-main {
display: flex;
align-items: center;
margin-left: 33px;
height: 100%;
.box__progress{
.situation-statistics-main-left{
display: block;
width: 76px;
height: 76px;
@@ -13,7 +12,7 @@
font-size: 16px;
}
}
.box__count{
.situation-statistics-main-right{
margin-left: 22px;
:first-child{
font-size: 18px;

View File

@@ -1,18 +1,18 @@
.cn-chart__two-situation-statistics{
.chart-two-situation-statistics{
padding-top: 22px;
.box__body {
.situation-statistics-top {
display: flex;
align-items: center;
margin-left: 33px;
padding-top: 22px;
.body__progress{
.situation-statistics-main-left{
display: block;
.el-progress__text span{
font-size: 16px;
}
}
.body__count{
.situation-statistics-main-right{
margin-left: 22px;
:first-child{
font-size: 18px;

View File

@@ -277,26 +277,22 @@
.map-tooltip {
display: flex;
flex-direction: column;
padding: 3px 3px 0;
.map-tooltip__title {
padding-bottom: 10px;
color: #fff;
color: #333;
font-size: 16px;
}
.map-tooltip__content {
display: flex;
flex-direction: column;
justify-content: space-between;
color: #666;
font-size: 14px;
.content-row {
.row__label {
color: #ddd;
padding-right: 5px;
}
.row__value {
color: #fff;
}
span {
line-height: 35px;
}
span:first-of-type {
padding-right: 20px;
}
}
}

View File

@@ -1,31 +1,26 @@
.cn-chart__alarm-info {
.cn-chart-alarm-info {
width: 100%;
height: 100%;
margin-left: 30px;
position: relative;
.alarm-info__box {
height: calc(100% - 40px);
.cn-chart-alarm-info-mainContent{
height: calc(100% - 40px) ;
width: 100%;
.box__body {
.cn-chart-alarm-content {
display: flex;
margin-left: 30px;
margin-right: 30px;
justify-content: flex-start;
align-items: center;
width: 100%;
height: calc(100% / 9);
border-bottom: 1px solid #E7EAED;
.body__content {
border-bottom: 1px solid #E7EAED ;
.cn-alarm-info-main {
display: flex;
.content__icon-box {
.cn-alarm-info-main-left{
position: relative;
display: flex;
justify-content: center;
align-items: center;
.icon-box__icon {
.cn-chart-alarm-info-icon {
width: 30px;
height: 30px;
border-radius: 50%;
@@ -33,123 +28,71 @@
justify-content: center;
align-items: center;
}
.cn-icon-alert {
.cn-icon-alert{
width: 12px;
position: absolute;
top: calc(50% - 8px);
left: calc(50% - 8px);
top: 13px;
left: 7px;
}
}
.content__text-box {
.cn-alarm-info-textContent{
margin-left: 17px;
.text-box__title {
font-size: 16px;
.cn-alarm-info-main-title {
font-size: 19px;
line-height: 19px;
font-family: Roboto-Regular;
color: #333333;
max-width: 30%;
font-weight: 400;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.text-box__text {
font-size: 12px;
.cn-alarm-info-bottom {
display: flex;
font-size: 14px;
line-height: 14px;
text-align: center;
margin-top: 10px;
display: flex;
align-items: center;
flex-wrap: wrap;
&>div {
margin-bottom: 4px;
}
.text__time-box {
.cn-alarm-info-bottom-middle {
display: flex;
margin-left: 20px;
height: 14px;
.cn-icon-time2 {
color: #8FA1BE;
width: 10px;
height: 10px;
font-size: 12px;
}
.time-box__start-time {
font-family: PingFangSC-Regular;
font-size: 12px;
.cn-alarm-info-bottom-time {
color: #999999;
line-height: 14px;
font-weight: 400;
font-size: 12px;
}
}
.text__duration-box {
height: 14px;
.cn-alarm-info-bottom-right {
display: flex;
justify-content: center;
align-items: center;
.cn-icon-time2 {
color: #8FA1BE;
width: 10px;
height: 10px;
font-size: 12px;
}
.time-box__start-time {
font-family: PingFangSC-Regular;
font-size: 12px;
margin-left: 17px;
.cn-alarm-info-bottom-time {
color: #999999;
line-height: 17px;
font-weight: 400;
}
}
.text__type {
.cn-alarm-info-bottom-type {
width: auto;
font-family: Roboto-Regular;
line-height: 16px;
height: 16px;
font-size: 12px;
border: 1px solid;
font-weight: 400;
max-width: 150px;
padding-left: 2px;
padding-right: 2px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
}
.duration-box__circle {
.cn-alarm-info-bottom-circle {
display: inline-block;
width: 5px;
height: 5px;
border-radius: 50%;
font-family: Roboto-Black;
font-size: 12px;
color: #666666;
line-height: 17px;
font-weight: 400;
}
}
}
}
}
}
.alarm-info__pagination {
height: 40px !important;
.cn-chart-alarm-info-pagination{
height: 40px;
width: 100%;
}
}
}

View File

@@ -14,7 +14,7 @@
flex: 0 0 25%;
overflow: auto;
padding-bottom: 20px;
//border-bottom: 1px solid $--right-box-border-color;
border-bottom: 1px solid $--right-box-border-color;
.related-domain__list-title {
padding: 13px 30px 0;
@@ -65,7 +65,7 @@
}
}
}
.cn-panel2 .chart-list > .vue-grid-layout > .vue-grid-item > .panel-chart .chart-header,.cn-panel2 .chart-list > .dns-screen> .panel-chart .chart-header {
.cn-panel2 .chart-list > .vue-grid-layout > .vue-grid-item > .panel-chart .chart-header {
border-bottom: 1px solid $--right-box-border-color;
}
.cn-panel2 .chart-list > .vue-grid-layout > .vue-grid-item > .panel-chart .chart-header.is-group-collapse {

View File

@@ -3,6 +3,7 @@
.chart-list {
.vue-grid-layout>.vue-grid-item {
.cn-chart {
height: 100% !important;
.cn-chart__echarts {
display: flex;
flex-direction: column;

View File

@@ -1,8 +1,4 @@
.cn-chart__single-value {
.single-value__unit {
padding-left: 6px;
}
&.cn-chart__single-value--detail-overview.cn-chart__single-value--icon-left {
width: unset;
flex: 0 0 240px;
@@ -11,42 +7,35 @@
.single-value__icon {
width: 38px;
height: 38px;
i {
font-size: 15px;
}
}
.single-value__content {
.content__data {
font-size: 14px;
color: #333;
.single-value__unit {
font-size: 14px;
color: #333;
}
}
.content__title {
font-size: 12px;
}
}
}
&.cn-chart__single-value--icon-left {
display: flex;
align-items: center;
height: 100%;
width: 100%;
.single-value-icon__box {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 40%;
}
.single-value__icon {
display: flex;
justify-content: center;
@@ -54,7 +43,6 @@
height: 72px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
display: flex;
align-items: center;
@@ -62,20 +50,17 @@
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
max-width: 60%;
padding-right: 10px;
.content__data {
padding-bottom: 7%;
font-size: 20px;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__title {
overflow: hidden;
white-space: nowrap;
@@ -83,13 +68,11 @@
font-size: 16px;
color: #666666;
}
&.single-value__content--with-chart {
.content__title {
border-bottom: 1px solid $--content-right-background-color;
}
}
.single-value__unit {
font-weight: normal;
padding-left: 10px;
@@ -98,7 +81,6 @@
}
}
}
&.cn-chart__single-value--icon-right {
display: flex;
flex-direction: row-reverse;
@@ -106,34 +88,29 @@
align-items: center;
height: 100%;
width: 100%;
.single-value-icon__box {
flex: 0 0 80px;
}
.single-value__icon {
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
position: relative;
width: 56px;
height: 56px;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: translate(-50%,-50%);
font-size: 24px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
height: 100%;
flex-direction: column;
padding: 0 10px;
.content__title {
display: flex;
align-items: center;
@@ -141,7 +118,6 @@
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
padding-top: 5%;
@@ -153,7 +129,6 @@
}
}
}
&.cn-chart__single-value--icon-right--color {
display: flex;
flex-direction: row-reverse;
@@ -161,7 +136,6 @@
align-items: center;
height: 100%;
width: 100%;
.single-value__content {
display: flex;
height: 100%;
@@ -186,32 +160,28 @@
fill: currentColor;
overflow: hidden;
}
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: translate(-50%,-50%);
font-size: 24px;
}
}
}
.single-value__data {
.single-value__data{
display: flex;
height: 100%;
flex-direction: column;
padding-left: 20px;
.content__title {
display: flex;
align-items: flex-end;
align-items: end;
height: 50%;
font-size: 16px;
color: #666666;
padding-bottom: 5px;
}
.content__data {
display: flex;
padding-top: 5%;
@@ -224,19 +194,16 @@
}
}
}
&.cn-chart__single-value--chart {
display: flex;
padding: 13px 20px;
height: 100%;
width: 100%;
.single-value__content {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
@@ -244,7 +211,6 @@
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
align-items: center;
@@ -253,423 +219,10 @@
color: #333333;
font-weight: bold;
}
.content__chart {
flex: auto
}
}
}
&.cn-chart__single-value--icon-doh {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background: #FFFFFF;
border: 1px solid #E7EAED;
box-shadow: 0 2px 4px 0 rgba(51, 51, 51, 0.02);
border-radius: 2px;
.single-value-icon__box {
flex: 0 0 80px;
}
.single-value__icon {
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
position: relative;
width: 56px;
height: 56px;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 10px;
margin-left: 20px;
.content__title {
display: flex;
align-items: center;
margin: 16px 0 27px 0;
font-family: PingFangSC-Medium;
font-size: 16px;
color: #333333;
line-height: 22px;
font-weight: 500;
}
.content__data {
display: flex;
padding-top: 5%;
height: 50%;
flex: auto;
font-size: 24px;
color: #333333;
font-weight: bold;
.content__data__doh {
.content__data__doh__count {
font-family: Roboto-Medium;
font-size: 30px;
color: #333333;
font-weight: 500;
}
.content__data__doh__percent {
margin-top: 10px;
font-family: Roboto-Black;
font-size: 14px;
color: #666666;
font-weight: 400;
span {
font-family: Roboto-Medium;
font-size: 14px;
color: #FC8157;
font-weight: 500;
margin-left: 10px;
}
}
}
}
}
}
&.cn-chart__single-value--protocol {
height: 100%;
width: 100%;
.single-value__content {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
.single-value__data {
display: flex;
flex-direction: column;
padding: 10px 20px 10px 18px;
.content__title {
font-size: 16px;
color: #333333;
}
}
.content__data {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}
.content__data-protocol:nth-of-type(1) {
margin-bottom: 50px;
span:nth-of-type(2) {
font-size: 12px;
color: #FC8157;
font-weight: 500;
}
}
.content__data-protocol:nth-of-type(2) {
span:nth-of-type(2) {
font-size: 12px;
color: #FBA342;
font-weight: 500;
}
}
.content__data-protocol {
display: flex;
height: 68px;
text-align: left;
.content__data-protocol-all {
flex: 1.5;
}
.content__data-protocol-icon {
display: flex;
width: 68px;
height: 100%;
margin: auto;
line-height: 68px;
border-radius: 100%;
justify-content: center;
i {
font-size: 26px;
}
}
.content__data-protocol-value {
flex: 2;
display: flex;
justify-content: space-between;
flex-direction: column;
.content__data-protocol-value-title {
margin-bottom: 7px;
font-size: 14px;
color: #666666;
font-weight: 400;
}
.content__data-protocol-value-num {
font-size: 26px;
color: #333333;
font-weight: 500;
}
}
.content__data-protocol-percent {
flex: 2;
display: flex;
justify-content: center;
height: 68px;
text-align: left;
font-size: 14px;
color: #666666;
font-weight: 400;
line-height: 95px;
}
}
}
}
&.cn-chart__single-value--percentile-right {
display: flex;
align-items: center;
justify-content: left;
height: 100%;
flex: 0 0 auto;
flex-wrap: nowrap;
margin-bottom: 10px;
.single-value-icon__box {
display: flex;
align-items: center;
justify-content: left;
margin-right: 5px;
flex: 0 0 80;
}
.single-value__icon {
display: flex;
justify-content: center;
width: 40px;
height: 40px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
display: flex;
align-items: center;
font-size: 20px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
max-width: 60%;
padding-right: 10px;
.data__title-in-one {
display:flex;
flex-direction: row;
align-items: center;
}
.content__data {
margin-bottom: 5px;
font-size: 12px;
color: #333333;
font-weight: bold;
}
.content__title {
white-space: nowrap;
font-size: 12px !important;
color: #7e8081;
margin-bottom: 5px;
padding: 3px 4px 3px 3px;
}
.title-background-color {
background-color: #EFF6FE;
border-radius: 4px;
}
.content__percentile {
white-space: nowrap;
text-overflow: ellipsis;
font-size: 12px;
color: #666666;
display:flex;
flex-direction: row;
.circle__content {
display:flex;
flex-display:row;
margin-right:4px;
.percentile__title-color {
color:#9b9b9b
}
}
}
.circle {
position: relative;
width: 6px;
height: 6px;
line-height: 6px;
border-radius: 50%;
-moz-border-radius: 50%;
margin: auto;
margin-right: 4px;
z-index: 1;
}
.circle.circle-p50 {
background: #ffa200;
}
.circle.circle-p90 {
background: #23bf9a;
}
&.single-value__content--with-chart {
.content__title {
border-bottom: 1px solid $--content-right-background-color;
}
}
.single-value__unit {
padding-left:0px;
padding-right: 5px;
color: #333333;
font-size: 14px;
font-weight: bold;
}
}
}
&.cn-chart__single-value--percentile-left {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
height: 100%;
width: unset;
.single-value-icon__box {
display: flex;
align-items: flex-start;
justify-content: right;
margin-right:25px;
flex: 0 0 80;
margin-bottom: 25px;
}
.single-value__icon {
display: flex;
justify-content: center;
width: 70px;
height: 70px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
display: flex;
align-items: center;
font-size: 28px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
max-width: 60%;
padding-right: 10px;
margin-left:25px;
.content__data {
margin-bottom: 7%;
font-size: 22px;
color: #333333;
font-weight: bold;
}
.content__title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 14px !important;
color: #7e8081;
margin-bottom: 7%;
font-weight:400;
}
.content__percentile {
white-space: nowrap;
text-overflow: ellipsis;
font-size: 12px;
color: #666666;
display:flex;
flex-direction: row;
font-weight: bold;
.circle__content {
display:flex;
flex-display:row;
margin-right:15px;
.percentile__title-color {
color:#9b9b9b;
font-weight: 500;
}
}
}
.circle {
position: relative;
width: 7px;
height: 7px;
line-height: 7px;
border-radius: 50%;
-moz-border-radius: 50%;
margin: auto;
margin-right: 4px;
z-index: 1;
}
.circle.circle-p50 {
background: #ffa200;
}
.circle.circle-p90 {
background: #23bf9a;
}
&.single-value__content--with-chart {
.content__title {
border-bottom: 1px solid $--content-right-background-color;
}
}
.single-value__unit {
color: #333333;
font-size: 22px;
font-weight: bold;
}
}
}
}

View File

@@ -1,19 +1,17 @@
.cn-chart__ip-basic {
display: flex;
padding: 30px 60px 0 30px;
.cn-chart__ip-basic-info {
padding-right: 80px;
.el-descriptions {
padding-top: 30px;
}
&>.el-descriptions {
flex: 0 0 350px;
padding: 30px 36px;
}
.chart-location {
display: flex;
flex: 1;
flex-direction: column;
}
.el-descriptions :not(.is-bordered) td {
padding-bottom: 5px !important;
padding: 0 20px 20px 0;
}
.el-descriptions__content {
color: #3976CB;

View File

@@ -4,14 +4,14 @@
position: absolute;
right: 10px;
top: 10px;
z-index: 2;
z-index: 1;
display: flex;
&>div {
margin-left: 10px;
}
}
.chart-list {
&>.vue-grid-layout>.vue-grid-item, &>.dns-screen {
&>.vue-grid-layout>.vue-grid-item {
&>.panel-chart {
border: 1px solid $--chart-box-border-color;
background-color: #FFFFFF;
@@ -30,7 +30,7 @@
justify-content:space-between;
align-items:center;
padding: 10px 20px 10px 18px;
flex: 0 0 40px;
height: 47px;
font-size: 16px;
color: $--color-text-primary;
@@ -131,7 +131,7 @@
}
.header__operations {
display: flex;
justify-content: flex-end;
justify-content: end;
align-items: center;
.header__operation-btn {
@@ -213,8 +213,7 @@
&>.cn-chart {
position: relative;
border-radius: 2px;
flex-grow: 1;
overflow: hidden;
height: 100%;
width: 100%;
.chart-drawing {
height: 100%;
@@ -225,7 +224,7 @@
border-bottom: 1px solid $--content-right-background-color;
.header__operations {
display: flex;
justify-content: flex-end;
justify-content: end;
align-items: center;
.header__operation.header__operation--echarts {
@@ -469,12 +468,12 @@
flex-shrink: 1;
flex-grow: 1;
overflow: hidden;
min-width: calc(50% - 37px);
min-width: 200px;
text-overflow: ellipsis;
white-space: nowrap;
}
.table__below-statistics {
width: calc((50% + 10px)/4);
width: 80px;
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;

View File

@@ -1,6 +1,5 @@
.cn-detection--list {
display: flex;
.cn-detection__collapse {
margin-bottom: 1px;
padding-top: 18px;
@@ -20,7 +19,6 @@
transform: rotate(90deg);
}
}
span:hover {
cursor: pointer;
}
@@ -30,7 +28,6 @@
font-size: 12px;
}
}
.cn-detection__case {
flex: 1;
display: flex;
@@ -51,7 +48,6 @@
height: 20px;
border-radius: 12px;
}
.cn-detection__row {
display: flex;
flex-direction: column;
@@ -67,40 +63,26 @@
padding-bottom: 3px;
color: #333333;
align-items: center;
i {
color: #7b8fa2;
color:#7b8fa2;
margin-right: 5px;
font-size: 18px;
font-size:18px;
}
.line {
color: #da5656;
margin-left: 12px;
color:#da5656;
margin-left:12px;
font-size: xx-small;
font-weight: bold;
}
.circle {
width: 10px;
height: 10px;
border: 2px solid #da5656;
width:10px;
height:10px;
border:2px solid #da5656;
border-radius: 10px;
margin-top: 4px;
margin-right: 12px;
}
.domain {
background: #EFF2F5;
border-radius: 2px;
font-size: 14px;
color: #333333;
letter-spacing: 0;
line-height: 14px;
margin-left: 5px;
margin-right:12px;
}
}
.cn-detection__body {
display: flex;
flex-direction: column;
@@ -119,27 +101,22 @@
padding-right: 40px;
display: flex;
align-items: center;
i {
padding-right: 6px;
color: #8FA1BE;
font-size: 14px;
}
span {
font-size: 14px;
}
span:first-of-type {
color: #999;
}
span:last-of-type {
color: #666;
}
}
}
.show-detail {
flex-shrink: 0;
padding: 0 30px;
@@ -153,7 +130,6 @@
}
}
}
.cn-detection__detail-overview {
flex-basis: 100%;
padding: 0 10px;
@@ -164,71 +140,3 @@
}
}
}
.security.cn-detection--list,.service.cn-detection--list {
height: 100%;
flex-direction: column;
justify-content: space-between;
.cn-detection__case {
background: #FFFFFF;
border: 1px solid #E7EAED;
border-radius: 2px;
margin-bottom: 10px;
}
.cn-detection__case {
padding: 18px 0;
flex: unset;
}
.cn-detection__header {
margin-bottom: 8px;
}
.cn-detection-table {
overflow: auto;
}
.cn-detection__case-severity {
display: flex;
width: 38px;
height: 34px;
text-align: center;
margin: auto;
margin-right: 20px;
margin-left: 29px;
line-height: 34px;
i {
font-size: 40px;
}
}
.el-pagination__jump {
margin-left: 0 !important;
}
.cn-detection__footer {
background: #FFFFFF;
position: relative;
box-shadow: 0 0 4px 0 rgba(0,0,0,0.06);
.el-pagination__total {
position: absolute;
left: 0;
}
}
.domain.cn-detection-domain {
height: 20px;
line-height: 20px !important;
padding: 0 4px;
font-style: italic;
}
.critical {
color: #D84C4C !important;
}
.high {
color: #FF9A79 !important;
}
.info {
color: #D1BD50 !important;
}
.medium {
color: #FFB65A !important;
}
.low {
color: #FFD82D !important;
}
}

View File

@@ -8,18 +8,6 @@
display: flex;
flex-direction: column;
.overview__metric {
display:flex;
flex-direction: row;
padding-top: 10px;
.metric__column {
display:flex;
flex-direction: column;
margin-right: 15px;
}
}
.overview__title {
padding: 10px 0;
color: #333;
@@ -45,39 +33,16 @@
color: #6B717B;
}
.row__charts {
height: 20px;
width: 80px;
}
.row__content--metric {
display: flex;
flex-wrap: nowrap;
color: #666666;
font-size:14px;
font-weight: 400;
}
.row__content {
display: flex;
color: #3976CB;
&.row__content--link {
font-style: italic;
text-decoration: underline;
color: #1890FF;
cursor: pointer;
}
.row__content--link{
font-style: italic;
text-decoration: underline;
color: #1890FF;
cursor: pointer;
}
span{
font-style: italic;
color: #1890FF;
}
}
}
}
@@ -97,7 +62,6 @@
display: flex;
justify-content: center;
align-items: center;
flex-basis: 16px;
font-size: 12px;
color: #666666;
}

View File

@@ -21,7 +21,7 @@
justify-content:space-between;
align-items:center;
padding: 10px 20px 10px 0px;
flex: 0 0 40px;
height: 40px;
font-size: 14px;
color: $--color-text-primary;

View File

@@ -25,7 +25,7 @@
background-color: #F3F7FA;
i {
font-size: 26px;
font-size: 22px;
color: #4E84B4;
}
}

View File

@@ -160,7 +160,7 @@
.body__detail {
cursor: pointer;
font-size: 14px;
color: #3976CB;
color: #8FA1BE;
position: absolute;
right: 30px;
}

View File

@@ -9,7 +9,7 @@
right: 50px;
top: 0;
width: 550px;
height: 320px;
height: 350px;
&.overview-map--ip {
height: 210px;
@@ -54,12 +54,6 @@
color: #8FA1BE;
cursor: pointer;
}
&.overview__row--single-value {
flex-wrap: nowrap;
.cn-chart__single-value--detail-overview {
margin-right: 60px;
}
}
.row__label {
color: #6B717B;
padding-right: 20px;
@@ -76,8 +70,6 @@
.row__content {
display: flex;
color: #3976CB;
word-wrap: break-word;
max-width: 30%;
.alert-level-tag {
display: flex;
@@ -106,7 +98,6 @@
.row__content {
padding: 2px 0;
max-width: unset;
&:first-of-type {
padding-top: 0;

View File

@@ -1,6 +1,5 @@
.cn-entity--list {
display: flex;
.cn-entity__collapse {
margin-bottom: 1px;
padding-top: 30px;
@@ -20,7 +19,6 @@
transform: rotate(90deg);
}
}
span:hover {
cursor: pointer;
}
@@ -30,7 +28,6 @@
font-size: 12px;
}
}
.cn-entity__case {
flex: 1;
overflow: hidden;
@@ -54,11 +51,10 @@
background-color: #F3F7FA;
i {
font-size: 26px;
font-size: 22px;
color: #4E84B4;
}
}
.cn-entity__row {
display: flex;
flex-direction: column;
@@ -71,7 +67,6 @@
padding-bottom: 3px;
color: #333333;
}
.cn-entity__body {
display: flex;
flex-direction: column;
@@ -88,60 +83,22 @@
.basic-info__item {
padding-right: 40px;
.item__box {
display: flex;
align-items: center;
flex-direction: row;
i {
padding-right: 6px;
color: #8FA1BE;
font-size: 12px;
height: 13px;
}
span {
font-size: 14px;
}
span:first-of-type {
color: #999;
}
span:last-of-type {
color: #666;
}
.row__charts {
height: 19px;
width: 60px;
padding-left: 5px;
}
}
i {
padding-right: 6px;
color: #8FA1BE;
font-size: 12px;
}
span {
font-size: 14px;
}
span:first-of-type {
color: #999;
}
span:last-of-type {
color: #666;
}
}
}
.show-detail {
flex-shrink: 0;
padding: 0 30px;
@@ -155,7 +112,6 @@
}
}
}
.cn-entity__detail-overview {
flex-basis: 100%;
padding: 0 10px;
@@ -166,4 +122,4 @@
}
}
}
}
}

View File

@@ -1,137 +0,0 @@
.cn-builtin {
background: #fff;
margin: 10px;
height: calc(100% - 20px) !important;
display: flex;
flex-direction: row;
.cn-builtin-left {
width: 288px;
height: 100%;
border-right: 1px solid #E7EAED;
.cn-builtin-left-title {
padding: 28px 0 26px 13px;
font-size: 16px;
color: #333333;
letter-spacing: 0;
}
.cn-builtin-left-menu {
width: 250px;
height: 46px;
margin: auto;
font-size: 14px;
color: #333333;
letter-spacing: 0;
line-height: 46px;
padding-left: 15px;
cursor: pointer;
}
.cn-builtin-left-menu.cn-active {
background: #F4FAFF;
border-radius: 2px;
color: #0091FF;
}
}
.cn-builtin-right {
flex: 1;
.list-page .main-container {
padding: 0;
.cn-table {
height: calc(100% - 62px) !important;
.el-table--fit.el-table--border {
height: calc(100% - 55px) !important;
}
}
}
.el-table__header th:first-of-type .el-checkbox:last-of-type {
border-left: none;
display: none;
}
.table-operation-all {
width: 300px;
position: absolute;
bottom: 17px;
z-index: 2;
left: 20px;
line-height: 24px;
height: 24px;
display: flex;
.el-checkbox {
width: 14px;
height: 14px;
padding: 0;
.el-checkbox__input,.el-checkbox__inner {
width: 100%;
height: 100%;
min-width: unset;
}
}
.table-operation-all-span {
height: 24px;
display: flex;
span {
margin: 0 10px;
font-size: 14px;
color: #666666;
letter-spacing: 0;
font-weight: 400;
}
.table-operation-back-down {
font-weight: 500;
height: 24px;
background: #D7D7D7;
border-radius: 2px;
line-height: 21px;
cursor: pointer;
position: relative;
span {
margin: 3px 8px;
font-size: 12px;
color: #FFFFFF;
}
}
.table-operation-back-down div {
color: #FFFFFF;
height: 24px;
background: #D7D7D7;
border-radius: 2px;
i {
font-size: 25px;
top: calc(50% - 12px);
}
}
.table-operation-back-down.table-operation-all-checkbox {
background: #0091ff;
}
.table-operation-back-down.table-operation-all-loading {
background: #D7D7D7;
}
}
}
.table-operation-items {
.table-operation-item--down {
margin-right: 16px;
cursor: pointer;
}
.table-operation-item--down,.table-operation-item--preview {
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
.chart__loading {
.el-icon-loading {
font-size: 12px;
left: calc(50% - 6px);
top: calc(50% - 6px);
}
}
.icon {
height: 25px;
width: 25px;
}
}
.table-operation-item--preview {
cursor: pointer;
}
}
}
}

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "cn-icon"; /* Project id 2614877 */
src: url('iconfont.woff2?t=1649728125883') format('woff2'),
url('iconfont.woff?t=1649728125883') format('woff'),
url('iconfont.ttf?t=1649728125883') format('truetype');
src: url('iconfont.woff2?t=1645687921203') format('woff2'),
url('iconfont.woff?t=1645687921203') format('woff'),
url('iconfont.ttf?t=1645687921203') format('truetype');
}
.cn-icon {
@@ -13,62 +13,6 @@
-moz-osx-font-smoothing: grayscale;
}
.cn-icon-report:before {
content: "\e76f";
}
.cn-icon-shezhi:before {
content: "\e76c";
}
.cn-icon-preview:before {
content: "\e76d";
}
.cn-icon-download2:before {
content: "\e76e";
}
.cn-icon-requests:before {
content: "\e76a";
}
.cn-icon-traffic:before {
content: "\e76b";
}
.cn-icon-domain2:before {
content: "\e767";
}
.cn-icon-ip2:before {
content: "\e768";
}
.cn-icon-app2:before {
content: "\e769";
}
.cn-icon-intercept:before {
content: "\e600";
}
.cn-icon-fraudulent-app:before {
content: "\e601";
}
.cn-icon-fraudulent-ip:before {
content: "\e602";
}
.cn-icon-fraudulent-domain:before {
content: "\e603";
}
.cn-icon-partly-cloudy:before {
content: "\e604";
}
.cn-icon-detection:before {
content: "\e766";
}
@@ -77,7 +21,7 @@
content: "\e764";
}
.cn-icon-clear:before {
.cn-icon-qingchu:before {
content: "\e765";
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -20,6 +20,7 @@
@changeMode="changeMode"
@search="search"
></tag-mode>
<!-- <div class="search-tip&#45;&#45;error">something error...</div>-->
</div>
</template>
@@ -101,20 +102,8 @@ export default {
ElMessage.error(this.$t('tip.invalidExpression'))
}
}
},
enterListener (event) {
if (event.keyCode === 13) {
this.$refs.tagMode && this.$refs.tagMode.search()
this.$refs.textMode && this.$refs.textMode.search()
}
}
},
mounted () {
document.addEventListener('keydown', this.enterListener)
},
unmounted () {
document.removeEventListener('keydown', this.enterListener)
},
setup (props) {
// 默认为文本模式
let searchMode = ref('text')

View File

@@ -308,12 +308,6 @@ export default {
})
}
},
mounted () {
const vm = this
this.emitter.on('advanced-search', function () {
vm.search()
})
},
watch: {
convertMetaList: {
immediate: true,

View File

@@ -23,7 +23,6 @@ import CodeMirror from 'codemirror'
import { toRaw } from 'vue'
import { columnType } from '@/components/advancedSearch/meta/meta'
import { ElMessage } from 'element-plus'
import { reg } from '@/utils/constants'
export default {
name: 'TextMode',
@@ -46,38 +45,15 @@ export default {
lineNumbers: false
})
this.codeMirror.setOption('extraKeys', {
Enter: (cm) => {}
Enter: (cm) => {
this.search()
}
})
},
search () {
let originalSql = this.codeMirror.getValue().trim()
let originalSql = this.codeMirror.getValue()
if (originalSql) {
originalSql = originalSql.replaceAll(/"/g, '')
// 为解决ip无法校验通过的问题先将带引号的ip转为不带引号的再把不带引号的转为带引号的
originalSql = originalSql.replaceAll(reg.notStrictWithQuotIpv4, function (word) {
return word.replaceAll(/'/g, '')
})
originalSql = originalSql.replaceAll(reg.notStrictIpv4, function (word) {
return `'${word}'`
})
originalSql = originalSql.replaceAll(reg.notStrictWithQuotIpv6, function (word) {
return word.replaceAll(/'/g, '')
})
originalSql = originalSql.replaceAll(reg.notStrictIpv6, function (word) {
return `'${word}'`
})
let tempArr = originalSql.split(' ')
tempArr = tempArr.map(t => {
if (t.lastIndexOf("'") !== (t.length - 1) && t.indexOf("'") !== 0) {
if (reg.containChinese.test(t)) {
return `'${t}'`
}
}
return t
})
originalSql = tempArr.join(' ')
originalSql = originalSql.replace(/"/g, '')
const parser = new SqlParser(originalSql, this.columnList)
const errorList = parser.validate()
if (this.$_.isEmpty(errorList)) {
@@ -126,7 +102,7 @@ export default {
const column = this.columnList.find(c => c.name === param.column)
current = `${current ? current + ' AND ' : ''}${param.column}${handleOperatorSpace(param.operator)}${this.handleValue(param.value, column, param.operator)}`
})
toRaw(this.codeMirror).setValue(current.trim())
toRaw(this.codeMirror).setValue(current)
},
removeParams (params) {
let current = this.codeMirror.getValue()
@@ -139,7 +115,7 @@ export default {
current = current.replace(piece, '')
})
})
toRaw(this.codeMirror).setValue(current.trim())
toRaw(this.codeMirror).setValue(current)
},
changeParams (params) {
let current = this.codeMirror.getValue()
@@ -151,7 +127,7 @@ export default {
const newSqlPiece = `${param.newParam.column}${handleOperatorSpace(param.newParam.operator)}${this.handleValue(param.newParam.value, newColumn, param.newParam.operator)}`.trim()
current = current.replace(oldSqlPiece, newSqlPiece)
})
toRaw(this.codeMirror).setValue(current.trim())
toRaw(this.codeMirror).setValue(current)
}
},
watch: {
@@ -168,10 +144,6 @@ export default {
},
mounted () {
this.initCodeMirror()
const vm = this
this.emitter.on('advanced-search', function () {
vm.search()
})
}
}
</script>

View File

@@ -9,7 +9,7 @@
:current-page="pageObj.pageNo"
:page-sizes="pageSizes?pageSizes:[20, 50, 100]"
:page-size="Number(pageObj.pageSize)"
:layout="layout"
layout="total, prev, pager, next, slot"
:total="pageObj.total"
>
<el-select v-model="pageSize" :placeholder="pageSize+$t('pageSize')" size="mini" :popper-append-to-body="appendToBody" class="pagination-size-select" @change="size" :popper-class="popClass" @visible-change="popperVisible">
@@ -22,7 +22,6 @@
<script>
import { defaultPageSize } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
export default {
name: 'pagination',
@@ -32,11 +31,7 @@ export default {
tableId: {},
postPageSizes: {},
appendToBody: { default: true },
popClass: {},
layout: {
type: String,
default: 'total, prev, pager, next, slot'
}
popClass: {}
},
data () {
return {
@@ -133,7 +128,7 @@ export default {
this.pageSize = this.postPageSizes[0]
this.resetPageSizes()
} else {
const pageSize = localStorage.getItem(storageKey.pageSize + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId)
const pageSize = localStorage.getItem('cn-pageSize-' + localStorage.getItem('cn-username') + '-' + this.tableId)
if (pageSize != 'undefined' && pageSize != null) {
this.pageSize = parseInt(pageSize)
}
@@ -157,15 +152,6 @@ export default {
deep: true,
handler (n, o) {
}
},
tableData: {
immediate: true,
deep: true,
handler (n, o) {
if (n) {
this.checkbox = n
}
}
}
}
}

View File

@@ -80,7 +80,6 @@
<script>
import { ref, computed } from 'vue'
import MyDatePicker from '../MyDatePicker'
import { storageKey } from '@/utils/constants'
export default {
name: 'DateTimeRange',
@@ -92,9 +91,6 @@ export default {
endTime: {
type: Number,
default: window.$dayJs.tz().valueOf()
},
dateRange: {
type: Number
}
/* useRefresh: {
type: Boolean,
@@ -114,10 +110,11 @@ export default {
const myStartTime = ref(props.startTime)
const myEndTime = ref(props.endTime)
const timeArr = ref([myStartTime.value, myEndTime.value])
const address = localStorage.getItem(storageKey.sysTimezone)
const utc = localStorage.getItem(storageKey.timezoneOffset)
const rangeHistory = ref(localStorage.getItem(storageKey.dataRangeHistory) ? JSON.parse(localStorage.getItem(storageKey.dataRangeHistory)) : [])
const dateRangeValue = props.dateRange ? ref(props.dateRange) : ref(60)
const address = localStorage.getItem('cn-sys-timezone')
const utc = localStorage.getItem('cn-timezone-offset')
const rangeHistory = ref(localStorage.getItem('date-range-history') ? JSON.parse(localStorage.getItem('date-range-history')) : [])
const dateRangeValue = ref(60)
dateRangeValue.value = 60
const isCustom = ref(false)
const dateRangeArr = [
{
@@ -236,7 +233,7 @@ export default {
start: myStartTime.value,
end: myEndTime.value
})
localStorage.setItem(storageKey.dataRangeHistory, JSON.stringify(rangeHistory.value))
localStorage.setItem('date-range-history', JSON.stringify(rangeHistory.value))
ctx.emit('change', myStartTime.value, myEndTime.value, dateRangeValue)
dropdownFlag.value = false
}

View File

@@ -59,8 +59,6 @@
<script>
import axios from 'axios'
import { post } from '@/utils/http'
import { storageKey } from '@/utils/constants'
export default {
name: 'TopToolMoreOptions',
props: {
@@ -109,7 +107,7 @@ export default {
if (this.paramsType) {
form.append('type', this.paramsType)
}
form.append('language', localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : 'en')
form.append('language', localStorage.getItem('cn-language') ? localStorage.getItem('cn-language') : 'en')
post(this.importUrl, form, { 'Content-Type': 'multipart/form-data' }).then(response => {
if (response.code == 200 && response.msg == 'success') {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.importSuccess') })
@@ -129,7 +127,7 @@ export default {
this.importFile = null
},
downloadTemplate () {
const language = localStorage.getItem(storageKey.language) || 'en' // 初始未选择默认 en 英文
const language = localStorage.getItem('cn-language') || 'en' // 初始未选择默认 en 英文
const fileName = this.exportFileName + '-' + this.$t('overall.template') + '-' + this.getTimeString() + '.json'
let url = null
@@ -160,7 +158,7 @@ export default {
})
}
params.pageSize = -1
params.language = localStorage.getItem(storageKey.language) || 'en'
params.language = localStorage.getItem('cn-language') || 'en'
this.export(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.json')
this.closeDialog()

View File

@@ -171,15 +171,15 @@ export default {
let className
switch (this.from) {
case ('ip'): {
className = 'cn-icon cn-icon-ip2 ip-green'
className = 'cn-icon cn-icon-ip ip-green'
break
}
case ('domain'): {
className = 'cn-icon cn-icon-domain2 domain-blue'
className = 'cn-icon cn-icon-domain domain-blue'
break
}
case ('app'): {
className = 'cn-icon cn-icon-app2 app-orange'
className = 'cn-icon cn-icon-app app-orange'
break
}
default: break

View File

@@ -18,7 +18,7 @@
<el-option v-for="(value, key) in entityType" :label="value" :key="key" :value="key">
<template v-if="value === entityType.ip"><i style="color: #23BF9A;" class="cn-icon cn-icon-ip"></i></template>
<template v-else-if="value === entityType.domain"><i style="color: #23BF9A;" class="cn-icon cn-icon-domain"></i></template>
<template v-else-if="value === entityType.app"><i style="color: #23BF9A;" class="cn-icon cn-icon-app2"></i></template>
<template v-else-if="value === entityType.app"><i style="color: #23BF9A;" class="cn-icon cn-icon-app"></i></template>
{{value}}
</el-option>
<template #prefix>
@@ -91,7 +91,6 @@
import { useRoute } from 'vue-router'
import { get, put } from '@/utils/http'
import { entityType, storageKey } from '@/utils/constants'
import { api } from '@/utils/api'
export default {
name: 'Header',
@@ -105,7 +104,7 @@ export default {
}
return {
username: 'admin', // sessionStorage.getItem('cn-username'),
language: localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : 'en',
language: localStorage.getItem('cn-language') ? localStorage.getItem('cn-language') : 'en',
showChangePin: false,
from: '', // entity类型
changePassForm: {
@@ -172,8 +171,8 @@ export default {
this.showChangePin = false
},
changeLocal (lang) {
if (lang !== localStorage.getItem(storageKey.language)) {
localStorage.setItem(storageKey.language, lang)
if (lang !== localStorage.getItem('cn-language')) {
localStorage.setItem('cn-language', lang)
window.location.reload()
}
},
@@ -182,10 +181,10 @@ export default {
},
logout () {
localStorage.removeItem(storageKey.token)
get(api.logout)
get('/logout')
},
refreshLang () {
this.language = localStorage.getItem(storageKey.language)
this.language = localStorage.getItem('cn-language')
this.$i18n.locale = this.language
this.$nextTick(() => {
window.location.reload()
@@ -197,7 +196,7 @@ export default {
submit () {
this.$refs.changePassForm.validate((valid) => {
if (valid) {
put(api.pin, { oldPin: this.changePassForm.oldPwd, newPin: this.changePassForm.newPwd }).then(res => {
put('sys/user/pin', { oldPin: this.changePassForm.oldPwd, newPin: this.changePassForm.newPwd }).then(res => {
if (res.code === 200) {
this.$message.success('Success')
this.showChangePin = false

View File

@@ -1,8 +1,8 @@
<template>
<div class="cn-home">
<left-menu @refresh="refresh"></left-menu>
<left-menu @refresh="refresh" v-show="showMenus"></left-menu>
<main ref="body" class="cn-body">
<cn-header></cn-header>
<cn-header v-show="showHeader"></cn-header>
<cn-container v-if="containerShow" ref="container"></cn-container>
</main>
<!-- 临时文本dom用来计算文本长度 -->
@@ -21,6 +21,14 @@ export default {
'cn-header': Header,
'cn-container': Container
},
computed: {
showHeader () {
return this.$store.getters.getShowMenu
},
showMenus () {
return this.$store.getters.getShowMenu
}
},
data () {
return {
containerShow: true

View File

@@ -70,13 +70,11 @@
</template>
<script>
import { storageKey } from '@/utils/constants'
export default {
name: 'LeftMenu',
data () {
return {
systemName: localStorage.getItem(storageKey.sysName),
systemName: localStorage.getItem('cn-sys-name'),
logo: ''
}
},

View File

@@ -133,7 +133,7 @@
<script>
import rightBoxMixin from '@/mixins/right-box'
import { get, post, put } from '@/utils/http'
import { panelTypeAndRouteMapping, storageKey } from '@/utils/constants'
import { panelTypeAndRouteMapping } from '@/utils/constants'
import { api } from '@/utils/api'
import { VAceEditor } from 'vue3-ace-editor'
import 'ace-builds/src-noconflict/mode-javascript'
@@ -149,7 +149,7 @@ export default {
data () {
return {
url: api.chart,
loginName: localStorage.getItem(storageKey.username),
loginName: localStorage.getItem('cn-username'),
panelTypeAndRouteMapping: panelTypeAndRouteMapping,
rules: { // 表单校验规则
name: [
@@ -355,7 +355,7 @@ export default {
},
methods: {
isCurrentUser (username) {
return localStorage.getItem(storageKey.username) === username
return localStorage.getItem('cn-username') === username
},
/* 密码失去焦点 检验确认密码 */
pinBlur () {
@@ -397,7 +397,7 @@ export default {
})
},
async getChartData (value) {
await get(api.chart, { panelId: value }).then(response => {
await get('/visual/chart?panelId=' + value).then(response => {
if (response.code === 200) {
this.chartData = response.data.list
}

View File

@@ -57,16 +57,13 @@
<script>
import rightBoxMixin from '@/mixins/right-box'
import { get, post, put } from '@/utils/http'
import { storageKey } from '@/utils/constants'
import { api } from '@/utils/api'
export default {
name: 'I18nBox',
mixins: [rightBoxMixin],
data () {
return {
url: api.i18nSys,
loginName: localStorage.getItem(storageKey.username),
url: 'sys/i18n',
loginName: localStorage.getItem('cn-username'),
rules: { // 表单校验规则
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
@@ -91,7 +88,7 @@ export default {
},
methods: {
isCurrentUser (username) {
return localStorage.getItem(storageKey.username) === username
return localStorage.getItem('cn-username') === username
},
/* 密码失去焦点 检验确认密码 */
pinBlur () {
@@ -133,7 +130,7 @@ export default {
})
},
getLangData () {
get(api.dict, { type: 'lang', pageSize: -1 }).then(response => {
get('sys/dict?type=lang&pageSize=-1').then(response => {
if (response.code === 200) {
this.langData = response.data.list
}

View File

@@ -50,8 +50,6 @@
<script>
import rightBoxMixin from '@/mixins/right-box'
import { get, post, put } from '@/utils/http'
import { api } from '@/utils/api'
export default {
name: 'userBox',
mixins: [rightBoxMixin],
@@ -66,7 +64,7 @@ export default {
data () {
return {
editRole: {},
url: api.role,
url: 'sys/role',
rightBox: { model: { show: false } },
rules: { // 表单校验规则
name: [
@@ -112,7 +110,7 @@ export default {
return new Promise(resolve => {
self.menus = []
if (self.editRole.id) {
get(api.menu + self.editRole.id).then(response => {
get('/sys/role/menu/' + self.editRole.id).then(response => {
if (response.code == 200) {
self.menus = response.data.menus
self.selectedIds = response.data.selectedIds
@@ -122,7 +120,7 @@ export default {
resolve()
})
} else {
get(api.sysMenu).then(response => {
get('/sys/menu').then(response => {
if (response.code == 200) {
self.menus = response.data.list
} else {

View File

@@ -54,36 +54,6 @@
</template>
</el-select>
</el-form-item>
<!--i18n-->
<el-form-item :label="$t('config.i18n.lang')" prop="i18n">
<el-select id="account-input-roleIds"
v-model="editObject.lang"
class="right-box__select"
clearable
collapse-tags
placeholder=""
popper-class="right-box-select-dropdown prevent-clickoutside"
size="small">
<template v-for="lang in langData" :key="lang.value">
<el-option :label="lang.label" :value="lang.value"></el-option>
</template>
</el-select>
</el-form-item>
<!--theme-->
<el-form-item :label="$t('config.user.theme')" prop="i18n">
<el-select id="account-input-roleIds"
v-model="editObject.theme"
class="right-box__select"
clearable
collapse-tags
placeholder=""
popper-class="right-box-select-dropdown prevent-clickoutside"
size="small">
<template v-for="theme in themeData" :key="theme.value">
<el-option :label="theme.label" :value="theme.value"></el-option>
</template>
</el-select>
</el-form-item>
<!--enable-->
<el-form-item :label="$t('config.user.enable')">
<el-switch
@@ -116,9 +86,6 @@
<script>
import rightBoxMixin from '@/mixins/right-box'
import { get, post, put } from '@/utils/http'
import { themeData, langData, storageKey } from '@/utils/constants'
import { api } from '@/utils/api'
export default {
name: 'UserBox',
mixins: [rightBoxMixin],
@@ -133,8 +100,8 @@ export default {
}
}
return {
url: api.user,
loginName: localStorage.getItem(storageKey.username),
url: 'sys/user',
loginName: localStorage.getItem('cn-username'),
rules: { // 表单校验规则
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
@@ -170,9 +137,7 @@ export default {
{ type: 'email', message: this.$t('validate.email') }
]
},
roleData: [],
themeData,
langData
roleData: []
}
},
setup () {
@@ -182,7 +147,7 @@ export default {
},
methods: {
isCurrentUser (username) {
return localStorage.getItem(storageKey.username) === username
return localStorage.getItem('cn-username') === username
},
/* 密码失去焦点 检验确认密码 */
pinBlur () {
@@ -224,7 +189,7 @@ export default {
})
},
getRoleData () {
get(api.role, { pageSize: -1 }).then(response => {
get('sys/role?pageSize=-1').then(response => {
if (response.code === 200) {
this.roleData = response.data.list
}

View File

@@ -11,7 +11,7 @@
<div class="top-tool-right">
<!-- <el-input v-model="keyWord" value="keyWord"></el-input>
<el-button @click="onsearch" icon="el-icon-search" type="info" size="mini" style="margin-right: 10px"></el-button>-->
<div v-if="showLayout.indexOf('search') > -1" class="top-tool-search" :class="{'margin-r-20': from !== fromRoute.builtinReport}">
<div v-if="showLayout.indexOf('search') > -1" class="top-tool-search margin-r-20">
<div style="display: flex">
<el-input
v-model="keyWord" size="small" @keyup.enter="onsearch"></el-input>
@@ -69,9 +69,6 @@ export default {
tableId: {
type: String
},
builtinId: {
type: Number
},
tableTitle: {
type: Array
},
@@ -98,11 +95,7 @@ export default {
this.$emit('update:customTableTitle', custom)
},
onsearch () {
const params = {
q: this.keyWord,
id: this.builtinId
}
this.$emit('search', params)
this.$emit('search', this.keyWord)
}
},
watch: {

View File

@@ -38,7 +38,6 @@
</template>
<script>
import { storageKey } from '@/utils/constants'
export default {
props: {
customTableTitle: Array, // 自定义的title
@@ -52,9 +51,9 @@ export default {
}
},
created () {
const localStorageTitle = JSON.parse(localStorage.getItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId))
const localStorageTitle = JSON.parse(localStorage.getItem('cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId))
if (localStorageTitle) {
localStorage.setItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId, JSON.stringify(localStorageTitle))
localStorage.setItem('cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId, JSON.stringify(localStorageTitle))
}
},
watch: {
@@ -93,8 +92,10 @@ export default {
// 点击第二个cancel
save () {
this.$emit('update', this.custom)
localStorage.setItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId,
JSON.stringify(this.custom))
localStorage.setItem(
'cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId,
JSON.stringify(this.custom)
)
this.esc()
}
},

View File

@@ -1,146 +0,0 @@
<template>
<el-table
id="userTable"
ref="dataTable"
:data="tableData"
:height="height"
border
@header-dragend="dragend"
@sort-change="tableDataSort"
@selection-change="selectionChange"
>
<el-table-column
:resizable="false"
align="center"
type="selection"
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitles"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"
:min-width="`${item.minWidth}`"
:prop="item.prop"
:resizable="true"
:sort-orders="['ascending', 'descending']"
:sortable="item.sortable"
:width="`${item.width}`"
>
<template #header>
<span class="data-column__span">{{item.label}}</span>
<div class="col-resize-area"></div>
</template>
<template #default="scope" :column="item">
<span v-if="item.prop === 'dataRange'">
<template v-if="scope.row.startTime && scope.row.endTime">
{{scope.row.startTime}}-{{scope.row.endTime}}
</template>
</span>
<span v-if="item.prop === 'type'">
{{scope.row.reportTemp.name}}
</span>
<span v-else>{{scope.row[item.prop]}}</span>
</template>
</el-table-column>
<el-table-column
:resizable="false"
:width="operationWidth"
fixed="right">
<template #header>
<div class="table-operation-title">{{$t('overall.option')}}</div>
</template>
<template #default="scope">
<div class="table-operation-items">
<div class="table-operation-item--down" @click="tableOperation(['download', scope.row, 1])">
<loading :loading="loadingTableId === scope.row.id"></loading>
<svg class="icon" aria-hidden="true" :class="{'table-operation-all-loading': loadingTableId}">
<use xlink:href="#cn-icon-download2"></use>
</svg>
</div>
<div class="table-operation-item--preview" @click="tableOperation(['preview', scope.row])">
<loading :loading="loadingPreviewId === scope.row.id"></loading>
<svg class="icon" aria-hidden="true" :class="{'table-operation-all-loading': loadingPreviewId}">
<use xlink:href="#cn-icon-preview"></use>
</svg>
</div>
</div>
</template>
</el-table-column>
</el-table>
<div class="table-operation-all">
<el-checkbox v-model="checkboxAll" @change="selectAll(tableData)"></el-checkbox>
<div class="table-operation-all-span">
<span>{{ $t('overall.all') }}</span>
<div class="table-operation-back-down" :class="{'table-operation-all-checkbox': batchDow, 'table-operation-all-loading': loading}" @click="tableOperation(['download', this.checkboxIds, 2])">
<loading :loading="loading"></loading>
<span>{{$t('report.batchDow')}}</span>
</div>
</div>
</div>
</template>
<script>
import table from '@/mixins/table'
import Loading from '@/components/common/Loading'
export default {
name: 'builtinReportTable',
mixins: [table],
components: {
Loading
},
data () {
return {
tableTitle: [ // 原始table列
{
label: this.$t('config.user.name'),
prop: 'name',
show: true,
sortable: 'custom'
}, {
label: this.$t('config.chart.remark'),
prop: 'remark',
show: true
}, {
label: this.$t('overall.type'),
prop: 'type',
show: true,
sortable: 'custom'
}, {
label: this.$t('report.dataRange'),
prop: 'dataRange',
show: true,
minWidth: 110
}
],
checkboxAll: false,
checkboxIds: '',
batchDow: false,
builtinId: '',
indeterminate: false,
loading: false,
loadingTableId: '',
loadingPreviewId: ''
}
},
methods: {
selectionChange (objs) {
this.$emit('selectionChange', objs)
this.checkboxIds = objs.map(item => { return item.id }).join(',')
this.checkboxAll = objs.length > 0 || objs.length === this.tableData.length
this.batchDow = objs.length > 0
},
selectAll (objs) {
if (objs) {
objs.forEach(item => {
this.$refs.dataTable.toggleAllSelection(item)
})
} else {
this.$refs.dataTable.clearSelection()
}
}
}
}
</script>

View File

@@ -70,7 +70,7 @@ export default {
mixins: [table],
data () {
return {
url: api.i18nLang,
url: api.i18n,
tableTitle: [ // 原始table列
{
label: 'ID',

View File

@@ -82,14 +82,13 @@
<script>
import table from '@/mixins/table'
import { put } from '@/utils/http'
import { storageKey } from '@/utils/constants'
export default {
name: 'userTable',
mixins: [table],
data () {
return {
loginName: localStorage.getItem(storageKey.username),
loginName: localStorage.getItem('cn-username'),
tableTitle: [ // 原始table列
{
label: 'ID',

View File

@@ -1,6 +1,5 @@
import { createApp } from 'vue'
import '@/assets/css/font/iconfont.css'
import '@/assets/css/font/iconfont.js'
import router from '@/router'
import store from '@/store'
import App from '@/App.vue'

View File

@@ -1,6 +1,5 @@
import { hasButton } from '@/permission'
import { getMillisecond } from '@/utils/date-util'
import { storageKey } from '@/utils/constants'
export default {
data () {
return {
@@ -43,7 +42,7 @@ export default {
utcTimeToSysTime (str) { // utc 0 到系统设置的时区
let date = ''
if (isNaN(str)) {
date = window.$dayJs(str).valueOf() + localStorage.getItem(storageKey.timezoneLocalOffset) * 60 * 60 * 1000
date = window.$dayJs(str).valueOf() + localStorage.getItem('cn-timezone-local-offset') * 60 * 60 * 1000
} else {
date = str
}

View File

@@ -3,10 +3,6 @@ import { defaultPageSize, fromRoute, position } from '@/utils/constants'
import { get, del } from '@/utils/http'
import { ref } from 'vue'
import pagination from '@/components/common/Pagination'
import axios from 'axios'
import { api } from '@/utils/api'
import { storageKey } from '@/utils/constants'
export default {
components: {
pagination
@@ -45,7 +41,7 @@ export default {
asce: tableSort.asce,
desc: tableSort.desc,
strToDate: tableSort.strToDate,
tableOperation ([command, row, param]) {
tableOperation ([command, row]) {
switch (command) {
case 'edit': {
this.edit(row)
@@ -59,14 +55,6 @@ export default {
this.copy(row)
break
}
case 'download': {
this.download(row, param)
break
}
case 'preview': {
this.preview(row)
break
}
default:
break
}
@@ -78,7 +66,7 @@ export default {
if (params) {
this.searchLabel = { ...this.searchLabel, ...params }
}
this.searchLabel = { ...this.searchLabel, ...this.pageObj}
this.searchLabel = { ...this.searchLabel, ...this.pageObj }
this.tools.loading = true
delete this.searchLabel.total
let listUrl = this.url
@@ -123,7 +111,7 @@ export default {
},
pageSize (val) {
this.pageObj.pageSize = val
localStorage.setItem(storageKey.pageSize + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId, val)
localStorage.setItem('cn-pageSize-' + localStorage.getItem('cn-username') + '-' + this.tableId, val)
this.getTableData()
},
add () {
@@ -149,101 +137,6 @@ export default {
this.object = { ...u, name: 'Copy from ' + u.name, id: '' }
this.rightBox.show = true
},
download (u, n) {
if (this.$refs.dataTable.loading && n === 2) { // 批量下载
return
} else if (this.$refs.dataTable.loadingTableId === u.id && n === 1) { // 列表单个下载
return
}
let fileName = ''
let url = ''
let params = {}
if (n === 2) { // 批量下载
fileName = 'builtinReport' + '-' + this.getTimeString() + '.zip' // 文件名称
url = api.reportBatchDownloadPdf // 批量 zip 下载
params = {
ids: u
}
} else if (n === 1) {
fileName = u.name + '.pdf' // 文件名称
url = api.reportDownloadPdf // 单个 pdf 下载
params = {
id: u.id
}
}
if (n === 2) { // 批量下载
this.$refs.dataTable.loading = true
} else if (n === 1) { // 列表单个下载
this.$refs.dataTable.loadingTableId = u.id // 列表单个下载
}
if (!u && n === 2) { // 批量下载
return this.$refs.dataTable.loading = false
} else if (!u && n === 1) { // 列表单个下载
return this.$refs.dataTable.loadingTableId = u.id
}
axios.get(url, { responseType: 'blob', params: params }).then(res => {
if (window.navigator.msSaveOrOpenBlob) {
// 兼容ie11
const blobObject = new Blob([res.data])
window.navigator.msSaveOrOpenBlob(blobObject, fileName)
} else {
const url = URL.createObjectURL(new Blob([res.data]))
const a = document.createElement('a')
document.body.appendChild(a) // 此处增加了将创建的添加到body当中
a.href = url
a.download = fileName
a.target = '_blank'
a.click()
a.remove() // 将a标签移除
}
if (n === 2) { // 批量下载
this.$refs.dataTable.loading = false
} else if (n === 1) { // 列表单个下载
this.$refs.dataTable.loadingTableId = !u.id
}
}, error => {
const $self = this
const reader = new FileReader()
reader.onload = function (event) {
const responseText = reader.result
const exception = JSON.parse(responseText)
if (exception.message) {
$self.$message.error(exception.message)
} else {
console.error(error)
}
}
reader.readAsText(error.response.data)
if (n === 2) { // 批量下载
this.$refs.dataTable.loading = false
} else if (n === 1) { // 列表单个下载
this.$refs.dataTable.loadingTableId = !u.id
}
}).catch(() => {
if (n === 2) { // 批量下载
this.$refs.dataTable.loading = false
} else if (n === 1) { // 列表单个下载
this.$refs.dataTable.loadingTableId = !u.id
}
})
},
preview (u) {
if (this.$refs.dataTable.loadingPreviewId === u.id) { // 列表单个下载
return
}
const params = {
id: u.id
}
this.$refs.dataTable.loadingPreviewId = u.id
axios.get(api.reportView, { params: params }).then(res => {
const prevWindow = window.open('', '')
prevWindow.document.write(res.data)
prevWindow.focus()
this.$refs.dataTable.loadingPreviewId = !u.id
}).catch(() => {
this.$refs.dataTable.loadingPreviewId = !u.id
})
},
esc () {
this.rightBox.show = false
},
@@ -258,21 +151,7 @@ export default {
},
search (params) {
this.pageObj.pageNo = 1
this.getTableData(params)
},
getTimeString () {
const split = '-'
const date = new Date()
const year = date.getFullYear()
const month = this.formatNum(date.getMonth() + 1)
const day = this.formatNum(date.getDate())
const hours = this.formatNum(date.getHours())
const minutes = this.formatNum(date.getMinutes())
const seconds = this.formatNum(date.getSeconds())
return year + split + month + split + day + ' ' + hours + split + minutes + split + seconds
},
formatNum (num) {
return num > 9 ? num : '0' + num
this.getTableData({ q: params })
}
},
watch: {
@@ -293,11 +172,11 @@ export default {
}
},
mounted () {
const pageSize = localStorage.getItem(storageKey.pageSize + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId)
const pageSize = localStorage.getItem('cn-pageSize-' + localStorage.getItem('cn-username') + '-' + this.tableId)
if (pageSize && pageSize !== 'undefined') {
this.pageObj.pageSize = pageSize
}
let localStorageTableTitle = localStorage.getItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId)
let localStorageTableTitle = localStorage.getItem('cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId)
localStorageTableTitle = localStorageTableTitle ? JSON.parse(localStorageTableTitle) : this.$refs.dataTable.tableTitle
this.tools.customTableTitle = this.$refs.dataTable.tableTitle.map((item, index) => { // 修复切换中英文的问题
if (localStorageTableTitle[index]) {

View File

@@ -24,7 +24,7 @@ export default {
}
})
},
getRelatedServerDataTwo (relationshipUrlTow, refTow) {
getRelatedServerDataTow (relationshipUrlTow, refTow) {
get(relationshipUrlTow, this.getQueryParams()).then(response => {
if (response.code === 200) {
const relationshipDataTwo = response.data.result

View File

@@ -41,7 +41,7 @@ export default {
tableOperation ([command, row, param]) {
switch (command) {
default:
this.$emit(command, row, param)
this.$emit(command, row)
break
}
},

View File

@@ -7,7 +7,7 @@ import axios from 'axios'
import { storageKey } from '@/utils/constants'
import { loadI18n } from '@/i18n'
const loginWhiteList = ['/login', '/'] // 免登陆白名单
const loginWhiteList = ['/login', '/', '/largeScreen'] // 免登陆白名单
const permissionWhiteList = [...loginWhiteList, '/entityDetail'] // 权限白名单
router.beforeEach(async (to, from, next) => {
@@ -45,7 +45,7 @@ router.beforeEach(async (to, from, next) => {
if (loginWhiteList.indexOf(to.path) !== -1) {
next()
} else {
next({ path: '/login', query: { redirect: to.fullPath } })
next({ path: '/login' })
}
}
})

View File

@@ -30,10 +30,6 @@ const routes = [
path: '/i18n',
component: () => import('@/views/settings/I18n')
},
{
path: '/report/builtIn',
component: () => import('@/views/report/builtinReport')
},
{
path: '/operationLog',
component: () => import('@/views/settings/OperationLog')
@@ -55,8 +51,8 @@ const routes = [
component: () => import('@/views/settings/Chart')
},
{
path: '/temp',
component: () => import('@/views/Temp')
path: '/largeScreen',
component: () => import('@/views/largeScreen/largeScreen')
}
]
}

View File

@@ -1,16 +1,17 @@
import { createStore } from 'vuex'
import user from './modules/user'
import panel from './modules/panel'
import { storageKey } from '@/utils/constants'
import largeScreen from './modules/largeScreen'
const store = createStore({
modules: {
user,
panel
panel,
largeScreen
},
state () {
return {
isShrink: localStorage.getItem(storageKey.leftMenuShrink) === 'true',
isShrink: localStorage.getItem('cn-left-menu-shrink') === 'true',
i18n: false,
showEntityTypeSelector: false, // 在entity explore页面时控制header显示实体类型选择框
@@ -34,7 +35,7 @@ const store = createStore({
mutations: {
isShrink (state) {
state.isShrink = !state.isShrink
localStorage.setItem(storageKey.leftMenuShrink, state.isShrink)
localStorage.setItem('cn-left-menu-shrink', state.isShrink)
},
loadI18n (state) {
state.i18n = true

View File

@@ -0,0 +1,24 @@
import dayjs from 'dayjs'
const largeScreen = {
state () {
return {
showMenu: true
}
},
mutations: {
setShowMenu (state, showMenu) {
state.showMenu = showMenu
}
},
getters: {
getShowMenu (state) {
return state.showMenu
}
},
actions: {
hideMenuHeader (state, res) {
state.commit('setShowMenu', false)
}
}
}
export default largeScreen

View File

@@ -14,8 +14,7 @@ const panel = {
chartLastPosition: {
x: 0,
y: 0
},
chartList: []
}
},
mutations: {
setShowRightBox (state, flag) {
@@ -56,12 +55,6 @@ const panel = {
},
setChartListId (state, id) {
state.chartListId = id
},
setChartList (state, chart) {
state.chartList.push(chart)
},
cleanChartList (state) {
state.chartList = []
}
},
getters: {
@@ -100,9 +93,6 @@ const panel = {
},
getChartListId (state, id) {
return state.chartListId
},
getChartList (state) {
return state.chartList
}
},
actions: {

View File

@@ -4,9 +4,6 @@ import { sortByOrderNum, getWelcomeMenu } from '@/permission'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import { ElMessage } from 'element-plus' // dependent on utc plugin
import { storageKey } from '@/utils/constants'
import { api } from '@/utils/api'
dayjs.extend(utc)
const user = {
@@ -46,56 +43,38 @@ const user = {
},
actions: {
loginSuccess (store, res) {
console.info(res)
window.$dayJs.tz.setDefault(res.data.timezone)
localStorage.setItem(storageKey.token, res.data.token)
localStorage.setItem(storageKey.sysName, res.data.systemName)
localStorage.setItem('cn-token', res.data.token)
localStorage.setItem('cn-sys-name', res.data.systemName)
if (res.systemLogo) {
localStorage.setItem(storageKey.sysLogo, res.data.systemLogo)
localStorage.setItem('cn-sys-logo', res.data.systemLogo)
}
localStorage.setItem(storageKey.sysTimezone, res.data.timezone)
localStorage.setItem(storageKey.timezoneOffset, dayjs.tz().utcOffset() / 60)
localStorage.setItem(storageKey.timezoneLocalOffset, dayjs().utcOffset() / 60)
post(api.permissions, { token: res.data.token }).then(res2 => {
const menuList = sortByOrderNum(res2.data.menus)
localStorage.setItem('cn-sys-timezone', res.data.timezone)
localStorage.setItem('cn-timezone-offset', dayjs.tz().utcOffset() / 60)
localStorage.setItem('cn-timezone-local-offset', dayjs().utcOffset() / 60)
post('/sys/user/permissions', { token: res.data.token }).then(res => {
const menuList = sortByOrderNum(res.data.menus)
store.commit('setMenuList', menuList)
store.commit('setButtonList', res2.data.buttons)
store.commit('setRoleList', res2.data.roles)
store.commit('setButtonList', res.data.buttons)
store.commit('setRoleList', res.data.roles)
if (res.loginSuccessPath) {
let tempArr = res.loginSuccessPath.split('?')
const path = tempArr[0]
const query = {}
if (tempArr[1]) {
tempArr = tempArr[1].split('&')
tempArr.forEach(t => {
const kv = t.split('=')
query[kv[0]] = kv[1]
})
}
const welcomeMenu = getWelcomeMenu(menuList)
if (welcomeMenu) {
router.push({
path: path,
query: query
path: welcomeMenu.route,
query: {
t: +new Date()
}
})
} else {
const welcomeMenu = getWelcomeMenu(menuList)
if (welcomeMenu) {
router.push({
path: welcomeMenu.route,
query: {
t: +new Date()
}
})
} else {
ElMessage.error('No menu')
}
ElMessage.error('No menu') // TODO 国际化
}
})
},
logoutSuccess (store, res) {
localStorage.removeItem(storageKey.username)
localStorage.removeItem(storageKey.username)
localStorage.removeItem(storageKey.token)
localStorage.removeItem('cn-username')
localStorage.removeItem('cn-username')
localStorage.removeItem('cn-token')
}
}
}

View File

@@ -11,33 +11,13 @@ import { storageKey } from '@/utils/constants'
export const api = {
// 系统相关
permission: '/sys/user/permissions',
i18n: '/sys/i18n/lang',
dict: '/sys/dict',
logout: '/logout',
pin: 'sys/user/pin',
appearance: '/sys/appearance',
permissions: '/sys/user/permissions',
operationLog: '/sys/log',
login: '/sys/login',
// user
user: '/sys/user',
// role
role: '/sys/role',
menu: '/sys/role/menu/',
sysMenu: '/sys/menu/',
// i18n
i18nLang: '/sys/i18n/lang',
i18nSys: '/sys/i18n',
// chart
chartList: '/visual/chart/list',
// galaxyProxy
galaxyProxy: '/galaxy/setting',
// 报告相关
reportJob: '/report/job',
reportTemp: '/report/temp',
reportBatchDownloadPdf: '/report/job/batchDownloadPdf',
reportDownloadPdf: '/report/job/downloadPdf',
reportView: '/report/job/view',
operationLog: '/sys/log',
chartList: '/visual/chart/list',
// 业务
panel: '/visual/panel',
chart: '/visual/chart',
@@ -54,6 +34,8 @@ export const api = {
entityNew: '/interface/entity/index/new',
entityActive: '/interface/entity/index/active',
entityTraffic: '/interface/entity/list/traffic',
entityAlertNum: '/interface/entity/list/alertNum',
entitySecurityNum: '/interface/entity/list/detectionNum',
ipBytes: '/interface/entity/detail/ip/bytes',
domainBytes: '/interface/entity/detail/domain/bytes',
appBytes: '/interface/entity/detail/app/bytes',
@@ -63,8 +45,8 @@ export const api = {
entityAppDetailNetworkQuantity: '/interface/entity/detail/overview/app/networkQuantity',
entityAppDetailLinkIn: '/interface/entity/detail/overview/app/linkIn',
entityAppDetailLinkOut: '/interface/entity/detail/overview/app/linkOut',
entityAppDetailPerformance: '/interface/entity/detail/overview/app/performanceEvent',
entityAppDetailSecurity: '/interface/entity/detail/overview/app/securityEvent',
entityAppDetailAlert: '/interface/entity/detail/overview/app/alert',
entityAppDetailSecurity: '/interface/entity/detail/overview/app/security',
entityAppRelatedServerDomain: '/interface/entity/detail/overview/app/relatedDomain',
entityAppRelatedServerIp: '/interface/entity/detail/overview/app/relatedServerIp',
// domain detail
@@ -74,12 +56,10 @@ export const api = {
entityDomainDetailNetworkQuantity: '/interface/entity/detail/overview/domain/networkQuantity',
entityDomainDetailLinkIn: '/interface/entity/detail/overview/domain/linkIn',
entityDomainDetailLinkOut: '/interface/entity/detail/overview/domain/linkOut',
entityDomainDetailPerformance: '/interface/entity/detail/overview/domain/performanceEvent',
entityDomainDetailSecurity: '/interface/entity/detail/overview/domain/securityEvent',
entityDomainDetailAlert: '/interface/entity/detail/overview/domain/alert',
entityDomainDetailSecurity: '/interface/entity/detail/overview/domain/security',
entityDomainRelatedServerIp: '/interface/entity/detail/overview/domain/relatedServerIp',
entityDomainRelatedServerApp: '/interface/entity/detail/overview/domain/relatedApp',
entityDetectionsIp: '/interface/entity/detail/overview/ip/dnsInfo',
entityDetectionsIpQueryRate: '/interface/entity/detail/overview/ip/dnsQueryRate',
// ip detail
entityIpDetailTraffic: '/interface/entity/detail/overview/ip/traffic',
entityIpDetailTrafficMap: '/interface/entity/detail/ip/trafficMap',
@@ -89,8 +69,8 @@ export const api = {
entityIpDetailNetworkQuantity: '/interface/entity/detail/overview/ip/networkQuantity',
entityIpDetailLinkIn: '/interface/entity/detail/overview/ip/linkIn',
entityIpDetailLinkOut: '/interface/entity/detail/overview/ip/linkOut',
entityIpDetailPerformance: '/interface/entity/detail/overview/ip/performanceEvent',
entityIpDetailSecurity: '/interface/entity/detail/overview/ip/securityEvent',
entityIpDetailAlert: '/interface/entity/detail/overview/ip/alert',
entityIpDetailSecurity: '/interface/entity/detail/overview/ip/security',
entityIpRelatedServerDomain: '/interface/entity/detail/overview/ip/relatedDomain',
entityIpRelatedServerApp: '/interface/entity/detail/overview/ip/relatedApp',
// detection
@@ -115,16 +95,9 @@ export const api = {
activeEntity: '/interface/detection/performance/filter/activeEntity',
listBasic: '/interface/detection/performance/list/basic',
listCount: '/interface/detection/performance/list/count',
overviewBasic: '/interface/detection/performance/detail/overview/basic',
metric: '/interface/detection/performance/detail/overview/metric'
overviewBasic: '/interface/detection/performance/detail/overview/basic'
}
},
// Dashboard
dashboard: {
DnsServiceInsights: {
alarmInfoCount: '/interface/dns/alarmInfoCount'
}
}
}
/* panel */
@@ -157,21 +130,13 @@ export async function getEntityFilter (params) {
export async function getDictList (params) {
return await getData(api.dict, params, true)
}
function handleResult (response) {
if (response.data.list || response.data.result) {
return response.data.list || response.data.result
} else if (response.data.result === 0) {
return response.data.result
} else {
return response.data
}
}
export async function getData (url, params = {}, isQueryList) {
const request = new Promise((resolve, reject) => {
try {
get(url, params).then(response => {
if (response.code === 200) {
resolve(handleResult(response))
resolve(isQueryList ? response.data.list || response.data.result : response.data.result || response.data)
} else {
reject(response)
}
@@ -196,7 +161,7 @@ export async function getConfigJson () {
export async function getPermission () {
const request = new Promise(resolve => {
post(api.permission, { token: localStorage.getItem(storageKey.token) }).then(response => {
post(api.permission, { token: localStorage.getItem('cn-token') }).then(response => {
resolve({
menuList: sortByOrderNum(response.data.menus),
buttonList: response.data.buttons,
@@ -212,7 +177,7 @@ export async function getI18n () {
const langs = dictData.map(d => d.value).join(',')
localStorage.setItem(storageKey.languages, langs)
const request = new Promise(resolve => {
get(api.i18nLang, { l: langs }).then(response => {
get(api.i18n, { l: langs }).then(response => {
response.data.cn = response.data.zh
resolve(response.data)
})

File diff suppressed because one or more lines are too long

View File

@@ -42,5 +42,5 @@ export function getNowTime (interval) {
}
// 日期格式转换
export function rTime (date) {
return window.$dayJs.tz(new Date(date)).format('MM-DD HH:mm')
return window.$dayJs.tz(new Date(date)).format('YYYY-MM-DD HH:mm:ss')
}

View File

@@ -2,7 +2,7 @@ import axios from 'axios'
import { storageKey } from '@/utils/constants'
axios.interceptors.request.use(config => {
const token = localStorage.getItem(storageKey.token)
const token = localStorage.getItem('cn-token')
if (token) {
config.headers.Authorization = token // 请求头token
}

View File

@@ -1,7 +1,7 @@
import { ElMessageBox, ElMessage } from 'element-plus'
import i18n from '@/i18n'
import _ from 'lodash'
import { storageKey, iso36112, topDomain } from '@/utils/constants'
import { storageKey, iso36112 } from '@/utils/constants'
import { getIso36112JsonData } from '@/utils/api'
import { format } from 'echarts'
import router from '@/router'
@@ -442,17 +442,14 @@ export function lineToHump (name) {
return letter.toUpperCase()
})
}
// 驼峰转空格,首字母小
export function humpToSpace (name) {
const str = name.replace(/([A-Z])/g, ' $1')
return str.split(' ').map(s => _.lowerFirst(s)).join(' ')
}
// 下划线转换空格
// 下划线转换空格首位大
export function lineToSpace (name) {
if (_.isEmpty(name)) {
return ''
}
return name.replace(/\_(\w)/g, ' ')
return _.upperFirst(name.replace(/\_(\w)/g, function (all, letter) {
return ` ${letter.toUpperCase()}`
}))
}
// 驼峰转换下划线
export function humpToLine (name) {
@@ -461,71 +458,6 @@ export function humpToLine (name) {
}
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
}
// 排序功能:从大到小,降序排列
export function reverseSortBy (i) {
return function (a, b) {
return b[i] - a[i]
}
}
// 排序功能:从小到大,升序排列
export function sortBy (i) {
return function (a, b) {
return a[i] - b[i]
}
}
// echart图标y轴鼠标悬浮时显示标签所有内容
export function extensionEchartY (chart) {
// 判断是否创建过div框,如果创建过就不再创建了
// 该div用来盛放文本显示内容的方便对其悬浮位置进行处理
const id = document.getElementById('extension')
if (!id) {
const div = "<div id = 'extension' style=\"display:block\"></div>"
const contentDiv = document.createElement('div')
contentDiv.setAttribute('id', 'extension')
contentDiv.setAttribute('style', 'display:block')
document.documentElement.append(contentDiv)
}
chart.on('mouseover', function (params) {
// 注意这里我是以Y轴显示内容过长为例如果是x轴的话需要改为xAxis
if (params.componentType === 'yAxis') {
// 设置悬浮文本的位置以及样式
const extEle = document.getElementById('extension')
extEle.style.cssText = 'display:inline;position:absolute;' +
' padding: 12px;' +
' max-width: 400px !important;' +
' color: #666;' +
' background-color: rgb(255, 255, 255);' +
' font-size: 14px;' +
' line-height: 20px;' +
' font-weight:400; ' +
' font-family: "Microsoft YaHei"' +
' border-style: solid;' +
' border-width: 1px;' +
' border-radius: 4px;' +
' border-color: transparent !important;' +
' box-shadow: rgb(0 0 0 / 30%) 0px 0px 3px;' +
' white-space: nowrap;' +
' z-index: 99999999;'
extEle.innerHTML = params.value
document.documentElement.onmousemove = function (event) {
const extEle = document.getElementById('extension')
const xx = event.pageX - extEle.offsetWidth - 20
const yy = event.pageY + 20
extEle.style.cssText = extEle.style.cssText + 'top:' + yy + 'px;left:' + xx + 'px;'
}
}
})
chart.on('mouseout', function (params) {
// 注意这里我是以Y轴显示内容过长为例如果是x轴的话需要改为xAxis
if (params.componentType == 'yAxis') {
const extEle = document.getElementById('extension')
extEle.style.cssText = 'display:none;'
}
})
}
// 搜索功能:对象转字符串
export function objToStr (obj) {
return Object.keys(obj).map(k => {
@@ -606,31 +538,6 @@ export function copyValue (item) {
ElMessage.success(i18n.global.t('tip.copySuccess'))
}
export function computeSecondaryDomain (name) {
// 命中的顶级域名
let hitTopDomain = ''
// 同顶级域名比对
const hits = []
topDomain.forEach(td => {
const hitIndex = name.lastIndexOf(td)
if (hitIndex > -1 && hitIndex + td.length === name.length) {
hits.push(td)
}
})
if (hits.length > 0) {
hits.sort((a, b) => {
return b.split('.').length - a.split('.').length
})
hitTopDomain = hits[0]
} else {
const arr = name.split('.')
hitTopDomain = arr[arr.length - 1]
}
const index = name.lastIndexOf(hitTopDomain)
const preArr = name.substring(0, index).split('.')
return [preArr[preArr.length - 2], hitTopDomain].join('.')
}
export function getCurrentRoute () {
return router.currentRoute && router.currentRoute.path
}
@@ -652,35 +559,3 @@ export function arrayIsEqual (arr1, arr2) {
}
}
}
export function scrollToTop (dom, toTop, duration, direction) {
const clientHeight = dom.clientHeight
const currentTop = dom.scrollTop
const totalScrollDistance = Math.abs(currentTop - toTop)
let scrollY = currentTop
let oldTimestamp = null
function step (newTimestamp) {
if (oldTimestamp !== null) {
if (direction === 'up') {
scrollY -= totalScrollDistance * (newTimestamp - oldTimestamp) / duration
console.info(scrollY)
if (scrollY < 0) {
dom.scrollTop = 0
return
}
dom.scrollTop = scrollY
} else if (direction === 'down') {
scrollY += totalScrollDistance * (newTimestamp - oldTimestamp) / duration
if (scrollY > clientHeight) {
dom.scrollTop = clientHeight
return
}
dom.scrollTop = scrollY
}
}
oldTimestamp = newTimestamp
window.requestAnimationFrame(step)
}
window.requestAnimationFrame(step)
}

View File

@@ -3,7 +3,6 @@ import _ from 'lodash'
const numberUnit = ['', 'K', 'M', 'G', 'T', 'P', 'E']
const byteUnit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']
const bpsUnit = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps']
const timeUnit = [ // 时间单位步进倍数以ms为基数
{ unit: 'ms', step: 1 },
{ unit: 's', step: 1000 },
@@ -32,10 +31,7 @@ function asciiCompute (num, ascii = 1000, units, dot = 2) {
export function numberUnitConvert (value, sourceUnit, targetUnit, dot = 2) {
return asciiCompute(value, 1000, numberUnit, dot)
}
export function bpsUnitConvert (value, sourceUnit, targetUnit, dot = 2) {
return asciiCompute(value, 1000, bpsUnit, dot)
}
export function byteUnitConvert (value, unitType, sourceUnit = 'B', targetUnit, dot = 2) {
export function byteUnitConvert (value, sourceUnit = 'B', targetUnit, dot = 2) {
return asciiCompute(value, 1024, byteUnit, dot)
}
/* 时间单位转换例如将ms转为h */
@@ -90,24 +86,12 @@ export default function unitConvert (value, unitType, sourceUnit, targetUnit, do
case unitTypes.time: {
return timeUnitFormatter(value, sourceUnit, targetUnit, dot)
}
case unitTypes.percent: {
const r = (value * 100).toFixed(dot)
if (_.isNaN(r)) {
return ['-', '']
} else if (r == 0) {
return [0, '%']
} else {
return [r, '%']
}
}
case unitTypes.percent:
case unitTypes.number: {
return numberUnitConvert(value, sourceUnit, targetUnit, dot)
}
case unitTypes.bps: {
return bpsUnitConvert(value, sourceUnit, targetUnit, dot)
}
case unitTypes.byte: {
return byteUnitConvert(value, unitType, sourceUnit, targetUnit, dot)
return byteUnitConvert(value, sourceUnit, targetUnit, dot)
}
}
}
@@ -134,7 +118,7 @@ export function getUnitType (column) {
/* 单位转换,返回转换后的[value, unit]type=time时若value<1ms返回<1mstype=percent时若value<0.01%,返回<0.01% */
export function valueToRangeValue (value, unitType) {
const values = unitConvert(Number(value), unitType)
const values = unitConvert(value, unitType)
if (values[0] || values[0] === 0) {
switch (unitType) {
case unitTypes.time: {
@@ -145,7 +129,7 @@ export function valueToRangeValue (value, unitType) {
}
case unitTypes.percent: {
if (values[0] < 0.01) {
return ['<0.01', '%']
return ['<0.01', '']
}
break
}

View File

@@ -1,129 +0,0 @@
<template>
<div style="overflow: auto;height: 100%;">
<div style="height: 8000px; overflow: auto; width: 100%; display: flex; flex-direction: column; align-content: center; background-color: white;">
<!-- <div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">session/s</div>
<div id="lineCanvas1" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">bytes</div>
<div id="lineCanvas2" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">rate</div>
<div id="lineCanvas3" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">行程卡流量数据 rate</div>
<div id="lineCanvas6" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>-->
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">流量变化曲线</div>
<div id="lineCanvas" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<!-- <div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">协议占比</div>
<div id="pieCanvas0" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">APP占比</div>
<div id="pieCanvas1" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">域名占比</div>
<div id="pieCanvas2" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">IP占比</div>
<div id="pieCanvas3" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">出占比</div>
<div id="pieCanvas4" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;">入占比</div>
<div id="pieCanvas5" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>-->
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;"></div>
<div id="sunCanvas1" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
<div style="padding-left: 30px; font-size: 18px; font-weight: bold; color: #666;"></div>
<div id="sunCanvas2" style="margin-bottom: 100px; height: 500px; width: 100%;"></div>
</div>
</div>
</template>
<script>
import { lineData, lineOption, sunData1, sunData2, sunOption } from './testData'
import * as echarts from 'echarts'
import { getMillisecond } from '@/utils/date-util'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
export default {
name: 'Temp',
methods: {
/* initLine (lineData, index) {
const data = lineData.map(d => {
return [getMillisecond(new Date(d[0]).getTime()), d[index]]
})
const option = this.$_.cloneDeep(lineOption2)
option.series.data = data
if (index === 1) {
option.yAxis.axisLabel.formatter = function (params) {
return unitConvert(params, unitTypes.number).join(' ')
}
} else if (index === 2) {
option.yAxis.axisLabel.formatter = function (params) {
return unitConvert(params, unitTypes.byte).join(' ')
}
} else if (index === 3) {
option.yAxis.axisLabel.formatter = function (params) {
const arr = unitConvert(params, unitTypes.byte).join(' ')
return arr.replace(/B/g, 'bps')
}
} else if (index === 6) {
option.yAxis.axisLabel.formatter = function (params) {
const arr = unitConvert(params, unitTypes.byte).join(' ')
return arr.replace(/B/g, 'Mbps')
}
}
const dom = document.getElementById(`lineCanvas${index}`)
const lineChart = echarts.init(dom)
this.$nextTick(() => {
lineChart.setOption(option)
})
}, */
initLineChart () {
// 数据转为需要的格式:[[timestamp, value]]
const data = lineData.map(d => {
return [getMillisecond(new Date(d[2]).getTime()), d[1]]
})
const option = this.$_.cloneDeep(lineOption)
option.series.data = data
const dom = document.getElementById('lineCanvas')
const lineChart = echarts.init(dom)
this.$nextTick(() => {
lineChart.setOption(option)
})
},
initSunChart (index) {
const option = this.$_.cloneDeep(sunOption)
const data = index === 1 ? sunData1 : sunData2
option.series.data = data
const dom = document.getElementById('sunCanvas' + index)
const lineChart = echarts.init(dom)
this.$nextTick(() => {
lineChart.setOption(option)
})
}
/* initPie (index) {
const data = pieData[index].map(p => {
return {
value: parseFloat(p[1].replace('%', '')).toFixed(2),
name: p[0]
}
})
const option = this.$_.cloneDeep(pieOption)
option.series[0].data = data
const dom = document.getElementById(`pieCanvas${index}`)
const pieChart = echarts.init(dom)
this.$nextTick(() => {
pieChart.setOption(option)
})
} */
},
mounted () {
/* this.initLine(lineData2, 1)
this.initLine(lineData2, 2)
this.initLine(lineData2, 3)
this.initLine(lineData3, 6) */
this.initLineChart()
this.initSunChart(1)
this.initSunChart(2)
/* this.initPie(0)
this.initPie(1)
this.initPie(2)
this.initPie(3)
this.initPie(4)
this.initPie(5) */
}
}
</script>

View File

@@ -4,10 +4,8 @@
<chart-no-data v-if="isNoData"></chart-no-data>
<template v-else>
<chart-tabs
ref="chart"
v-if="isTabs"
:chart-info="chartInfo"
:time-filter="timeFilter"
:query-params="queryParams"
:entity="entity"
></chart-tabs>
@@ -16,10 +14,9 @@
v-else-if="isMap && !isIpBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
:entity="entity"
@getChartData="getChartData"
@query="query"
@showLoading="showLoading"
></chart-map>
@@ -27,26 +24,22 @@
v-else-if="isSingleValue"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-single-value>
<chart-block
ref="chart"
v-else-if="isBlock"
:time-filter="timeFilter"
:query-params="queryParams"
ref="chart"
:timeFilter="queryParams"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></chart-block>
<chart-group
ref="chart"
v-else-if="isGroup"
:query-params="queryParams"
:time-filter="timeFilter"
:timeFilter="queryParams"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
@@ -54,8 +47,6 @@
<ip-basic-info
v-else-if="isIpBasicInfo"
:time-filter="timeFilter"
:query-params="queryParams"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
@@ -66,7 +57,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-time-bar>
@@ -76,7 +66,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-category-bar>
@@ -86,7 +75,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-ip-open-port-bar>
@@ -96,7 +84,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:table="table"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-table>
@@ -106,7 +93,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:table="table"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-active-ip-table>
@@ -114,7 +100,6 @@
v-else-if="isAppBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-app-basic-info>
@@ -122,7 +107,6 @@
v-else-if="isDomainWhois"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-domain-whois>
@@ -130,7 +114,6 @@
v-else-if="isDomainDnsRecord"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-domain-dns-record>
@@ -138,7 +121,6 @@
v-else-if="isCryptocurrencyEventList"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-cryptocurrency-event-list>
@@ -146,7 +128,6 @@
v-else-if="isRelationShip"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-relation-ship>
@@ -154,7 +135,6 @@
v-else-if="isSankey"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
:entity="entity"
></chart-san-key>
@@ -164,8 +144,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-echart>
@@ -174,8 +152,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:result-type="resultType"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
></chart-echart-with-statistics>
@@ -184,7 +160,6 @@
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:time-filter="timeFilter"
:result-type="resultType"
:order-pie-table="orderPieTable"
@showLoading="showLoading"
@@ -192,10 +167,8 @@
<chart-echart-ip-hosted-domain
v-else-if="isIpHostedDomain"
:chart-data="chartData"
:chart-info="chartInfo"
:time-filter="timeFilter"
:query-params="queryParams"
:chart-data="chartData"
@showLoading="showLoading"
:entity="entity"
></chart-echart-ip-hosted-domain>
@@ -206,67 +179,36 @@
:chart-data="chartData"
@showLoading="showLoading"
:entity="entity"
:time-filter="timeFilter"
:query-params="queryParams"
></chart-echart-app-relate-domain>
<chart-one-situation-statistics
<chart-one-Situation-Statistics
v-else-if="isSingleSupportStatistics"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:time-filter="timeFilter"
:entity="entity"
@showLoading="showLoading"
></chart-one-situation-statistics>
:entity="entity"
></chart-one-Situation-Statistics>
<chart-two-situation-statistics
<chart-two-Situation-Statistics
v-else-if="isTwoSupportStatistics"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
:entity="entity"
></chart-two-situation-statistics>
></chart-two-Situation-Statistics>
<chart-alarm-info
v-else-if="isAlarmInfo"
v-else-if="isAlarmInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
@showLoading="showLoading"
:tabHandleClickType="tabHandleClickType"
@getAlarmInfo="getAlarmInfo"
:entity="entity"
>
:entity="entity">
</chart-alarm-info>
<chart-domain-recursive-resolve
:chart-data="chartData"
:time-filter="timeFilter"
:query-params="queryParams"
v-else-if="isDomainRecursiveResolve"
></chart-domain-recursive-resolve>
<chart-detection-security
:chart-data="chartData"
:time-filter="timeFilter"
:chart-info="chartInfo"
:query-params="queryParams"
v-else-if="isDetectionSecurity"
@getDetectionData="getDetectionData"
></chart-detection-security>
<chart-detection-service
:chart-data="chartData"
:time-filter="timeFilter"
:chart-info="chartInfo"
:query-params="queryParams"
v-else-if="isDetectionService"
@getDetectionData="getDetectionData"
></chart-detection-service>
</template>
</div>
</template>
@@ -299,9 +241,6 @@ import ChartSanKey from '@/views/charts/charts/ChartSanKey'
import ChartOneSituationStatistics from '@/views/charts/charts/ChartOneSituationStatistics'
import ChartTwoSituationStatistics from '@/views/charts/charts/ChartTwoSituationStatistics'
import ChartAlarmInfo from '@/views/charts/charts/ChartAlarmInfo'
import ChartDomainRecursiveResolve from '@/views/charts/charts/ChartDomainRecursiveResolve'
import chartDetectionSecurity from '@/views/charts/charts/chartDetectionSecurity'
import chartDetectionService from '@/views/charts/charts/chartDetectionService'
import {
isEcharts,
isEchartsLine,
@@ -321,12 +260,13 @@ import {
isMapLine,
isMapBlock,
isSingleValueWithEcharts,
isSingleValueWithPercent,
isSingleValueWithEchartsTemp,
isRelationShip,
isTabs,
isGroup,
isSankey,
isIpBasicInfo,
isIpOpenPort,
isIpHostedDomain,
isDomainWhois,
isDomainDnsRecord,
@@ -336,11 +276,7 @@ import {
isBlock,
isSingleSupportStatistics,
isTwoSupportStatistics,
isAlarmInfo,
isDomainRecursiveResolve,
isDetectionSecurity,
isDetectionService,
isDetectionsProtocol
isAlarmInfo
} from './charts/tools'
import _ from 'lodash'
@@ -373,14 +309,11 @@ export default {
ChartEchartAppRelateDomain,
ChartOneSituationStatistics,
ChartTwoSituationStatistics,
ChartAlarmInfo,
ChartDomainRecursiveResolve,
chartDetectionSecurity,
chartDetectionService
ChartAlarmInfo
},
data () {
return {
tabHandleClickType: ''
data(){
return{
tabHandleClickType:''
}
},
props: {
@@ -395,19 +328,16 @@ export default {
entity: Object,
isError: Boolean,
table: Object,
timeFilter: Object,
orderPieTable: Object,
tabHandleClickType: String
tabHandleClickType:String
},
computed: {
isNoData () {
return (
!this.loading &&
(!this.chartData || _.isEmpty(this.chartData) || this.isError) &&
(_.isEmpty(this.chartData) || this.isError) &&
!this.isSingleValue &&
!this.isTabs &&
!this.isBlock &&
!this.isGroup &&
!this.isDomainDnsRecord &&
!this.isCryptocurrencyEventList &&
!this.isActiveIpTable &&
@@ -423,7 +353,7 @@ export default {
} else {
return getOption(this.chartInfo.type)
}
}
},
},
methods: {
resize () {
@@ -433,14 +363,8 @@ export default {
showLoading (show) {
this.$emit('showLoading', show)
},
getAlarmInfo (url, extraParams, isRefresh, timeFilter) {
this.$emit('getChartData', url, extraParams, isRefresh, timeFilter)
},
getChartData (url, extraParams) {
this.$emit('getChartData', url, extraParams)
},
getDetectionData (url, extraParams, isRefresh, timeFilter) {
this.$emit('getChartData', url, extraParams, isRefresh, timeFilter)
getAlarmInfo(url,extraParams){
this.$emit('getChartData',url,extraParams)
},
initEchartsWithTable () {
this.$refs['chart' + this.chartInfo.id] &&
@@ -453,9 +377,13 @@ export default {
}
},
watch: {
tabHandleClickType: {
chartData: {
deep: true,
handler (n) {
handler (n) {}
},
tabHandleClickType:{
deep:true,
handler(n){
this.tabHandleClickType = n
}
}
@@ -472,7 +400,9 @@ export default {
isEchartsWithStatistics: isEchartsWithStatistics(props.chartInfo.type),
isSingleValue: isSingleValue(props.chartInfo.type),
isSingleValueWithEcharts: isSingleValueWithEcharts(props.chartInfo.type),
isSingleValueWithPercent: isSingleValueWithPercent(props.chartInfo.type),
isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(
props.chartInfo.type
),
isRelationShip: isRelationShip(props.chartInfo.type),
isTable: isTable(props.chartInfo.type),
isBasicTable: isBasicTable(props.chartInfo.type),
@@ -487,6 +417,7 @@ export default {
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(
@@ -494,16 +425,10 @@ export default {
),
isAppBasicInfo: isAppBasicInfo(props.chartInfo.type),
isAppRelatedDomain: isAppRelatedDomain(props.chartInfo.type),
isSingleSupportStatistics: isSingleSupportStatistics(
props.chartInfo.type
),
isSingleSupportStatistics: isSingleSupportStatistics(props.chartInfo.type),
isTwoSupportStatistics: isTwoSupportStatistics(props.chartInfo.type),
isAlarmInfo: isAlarmInfo(props.chartInfo.type),
isDomainRecursiveResolve: isDomainRecursiveResolve(props.chartInfo.type),
isDetectionSecurity: isDetectionSecurity(props.chartInfo.type),
isDetectionService: isDetectionService(props.chartInfo.type),
isDetectionsProtocol: isDetectionsProtocol(props.chartInfo.type)
}
}
},
}
</script>

View File

@@ -4,7 +4,7 @@
:class="{
'chart-header--title-chart': isTitle,
'is-group-collapse': isGroup,
'panel-chart-block': isBlock
'panel-chart-block': isBlock,
}"
>
<div class="chart-header__title" v-if="isGroup">
@@ -18,14 +18,7 @@
</span>
{{ chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name }}
</div>
<div
class="chart-header__title"
v-else-if="!isBasicTable"
:class="{ 'chart-header__title--block': isBlock }"
:title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name"
>
{{ chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name }}
</div>
<div class="chart-header__title" v-else-if="!isBasicTable" :class="{'chart-header__title--block': isBlock}" :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</div>
<template v-if="isBasicTable">
<div class="chart-header__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
@@ -81,13 +74,12 @@
@change="tableLimitChange"
>
<template
v-for="(item, index) in table.tableColumns.order"
v-for="(item, index) in table.tableColumns"
:key="item.prop"
>
<el-option
:value="item"
:label="$t(chartTableColumnMapping[item])"
></el-option>
<el-option v-if="index > 0" :value="item.prop">{{
item.prop
}}</el-option>
</template>
</el-select>
</div>
@@ -145,31 +137,21 @@
<template v-else-if="isAlarmInfo">
<div class="cn-chart-header-button">
<el-button-group class="cn-chart-header-button-group">
<el-button
:class="isFocusAll ? 'cn-chart-header-button-all' : ''"
@click="tabHandleClick('All')"
size="small"
>{{ $t('dns.all') }}</el-button
>
<el-button
:label="value"
:name="value"
plain:true
v-for="(value, key) in eventSeverity"
:key="key"
size="small"
:class="isFocus === value ? 'cn-chart-header-button-' + value : ''"
@click="tabHandleClick(value)"
>
{{ value }}
</el-button>
</el-button-group>
<div>
<span class="header__operation-btn" @click="refresh"
><i class="cn-icon cn-icon-refresh"></i
></span>
</div>
<el-button
:class="isFocusAll ? 'cn-chart-header-button-all' : ''"
@click="tabHandleClick('All')"
>{{ $t('dns.all') }}</el-button
>
<el-button
:label="value"
:name="value"
v-for="(value, key) in eventSeverity"
:key="key"
:class=" isFocus === value ? 'cn-chart-header-button-' + value : ''"
@click="tabHandleClick(value)"
>
{{ value }}
</el-button>
</div>
</template>
@@ -193,7 +175,6 @@
class="date-time-range"
:start-time="chartTimeFilter.startTime"
:end-time="chartTimeFilter.endTime"
:date-range="chartTimeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
@@ -247,9 +228,8 @@ import {
chartActiveIpTableOrderOptions,
chartPieTableTopOptions,
eventSeverity,
chartTableColumnMapping, panelTypeAndRouteMapping
chartTableColumnMapping
} from '@/utils/constants'
import { useRouter } from 'vue-router'
export default {
name: 'ChartHeader',
@@ -257,24 +237,24 @@ export default {
chartInfo: Object,
errorInfo: {
type: String,
default: ''
default: '',
},
isError: {
type: Boolean,
default: false
default: false,
},
table: Object,
orderPieTable: Object
orderPieTable: Object,
},
components: {
ChartError
ChartError,
},
data () {
data() {
return {
chartTableColumnMapping,
dropdownMenuShow: false,
errorText: '',
isFocus: false,
isFocus:false,
isFocusAll: true,
activeIpTable: {
// ActiveIpTable select
@@ -282,96 +262,95 @@ export default {
tableData: [
{
name: '192.168.20.21',
num: 111
num: 111,
},
{
name: '192.168.20.22',
num: 345
num: 345,
},
{
name: '192.168.20.23',
num: 111
num: 111,
},
{
name: '192.168.20.24',
num: 345
num: 345,
},
{
name: '192.168.20.25',
num: 111
num: 111,
},
{
name: '192.168.20.26',
num: 345
}
] // table的所有数据
}
num: 345,
},
], // table的所有数据
},
}
},
methods: {
refresh () {
refresh() {
this.$emit('refresh')
},
timeRefreshChange () {
// 不是自选时间
timeRefreshChange() {
if (!this.$refs.dateTimeRange.isCustom) {
const value = this.chartTimeFilter.dateRangeValue
this.$refs.dateTimeRange.quickChange(value)
} else {
this.$emit('refresh', this.chartTimeFilter)
this.$emit('refresh')
}
},
reload (s, e, v) {
reload(s, e, v) {
this.dateTimeRangeChange(s, e, v)
},
groupShow () {
groupShow() {
this.$emit('groupShow', this.chartInfo)
},
dateTimeRangeChange (s, e, v) {
dateTimeRangeChange(s, e, v) {
this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v }
this.$emit('refresh', this.chartTimeFilter)
},
tableLimitChange () {
tableLimitChange() {
this.$emit('tableChange')
},
activeIpTableLimitChange () {
activeIpTableLimitChange() {
this.$emit('tableChange')
},
orderPieTableChange () {
orderPieTableChange() {
this.$emit('orderPieTableChange', this.orderPieTable)
},
tabHandleClick (item) {
tabHandleClick(item) {
this.isFocus = item
if (item === 'All') {
this.isFocusAll = false
if(item === 'All'){
this.isFocusAll = true
} else {
}else{
this.isFocusAll = false
}
this.$emit('tabHandleClick', item)
}
},
},
watch: {
isFocus: {
deep: true,
handler (n) {}
beforeCreate() {
this.$emit('tabHandleClick', 'All')
},
watch:{
isFocus:{
deep:true,
handler(n){
}
}
},
computed: {
showRefreshButton () {
showRefreshButton() {
// 自己是group且父元素是block时不显示刷新按钮
// TODO 父元素是block且只有自己一个子元素时不显示刷新按钮
const isGroupAndParentIsBlock =
this.$_.get(this.chartInfo.parent, 'type') === 95 && this.isGroup
return !isGroupAndParentIsBlock
}
},
},
setup (props) {
const { currentRoute } = useRouter()
function isEntityDetail (r) {
return r.indexOf('entityDetail') > -1
}
const dateRangeValue = isEntityDetail(currentRoute.value.path) ? 60 * 24 : 60
setup(props) {
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
// entity详情内的chart时间工具不是公共的需要单独定义
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
@@ -389,8 +368,8 @@ export default {
isActiveIpTable: isActiveIpTable(props.chartInfo.type),
isEchartsWithTable: isEchartsWithTable(props.chartInfo.type),
isGroup: isGroup(props.chartInfo.type),
isAlarmInfo: isAlarmInfo(props.chartInfo.type)
isAlarmInfo: isAlarmInfo(props.chartInfo.type),
}
}
},
}
</script>

View File

@@ -1,8 +1,8 @@
<template>
<div style="padding: 10px 10px 20px 10px; overflow: auto" v-if="!isEntityDetail" @scroll="wholeScreenScroll">
<div style="padding: 10px 10px 20px 10px; overflow: auto" v-if="!isEntityDetail">
<div id="cn-panel" class="cn-panel2">
<div class="panel__time">
<date-time-range class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>
<date-time-range class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
<time-refresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
</div>
<panel-chart-list
@@ -11,7 +11,6 @@
:data-list="chartList"
:panel-lock="panelLock"
:entity="entity"
:whole-screen-scroll="panel.params && panel.params.wholeScreenScroll"
>
</panel-chart-list>
</div>
@@ -27,6 +26,14 @@
:entity="entity"
>
</panel-chart-list>
<!-- <template v-for="chart in chartList" :key="chart.id">
<chart
:chart="chart"
:ref="`chart-${chart.id}`"
:entity="entity"
@getCurrentTimeRange="getCurrentTimeRange"
></chart>
</template>-->
</div>
</div>
</div>
@@ -38,12 +45,7 @@ import { ref } from 'vue'
import { panelTypeAndRouteMapping } from '@/utils/constants'
import { api, getPanelList, getChartList } from '@/utils/api'
import { getNowTime } from '@/utils/date-util'
import { scrollToTop } from '@/utils/tools'
import {
isGroup,
isBlock,
getGroupHeight
} from './charts/tools'
import { getGroupHeight, getTypeCategory } from '@/views/charts/charts/tools'
export default {
name: 'Panel',
@@ -60,11 +62,7 @@ export default {
detailTabs: [],
detailChartList: [],
currentTab: '',
isCryptocurrency: false, // 是否为挖矿列表
scroll: {
prevent: false, // 阻止滚动
prevScrollTop: 0 // 前一次滚动条位置
}
isCryptocurrency: false// 是否为挖矿列表
}
},
async mounted () {
@@ -76,18 +74,14 @@ export default {
}
},
setup (props, ctx) {
// data
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const timeFilter = ref({ startTime, endTime, dateRangeValue })
const panel = ref({})
let panelType = 1 // 取得panel的type
const { params } = useRoute()
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
function isEntityDetail (t) {
return [4, 5, 6].indexOf(t) > -1
}
// date
const dateRangeValue = isEntityDetail(panelType) ? 60 * 24 : 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const timeFilter = ref({ startTime, endTime, dateRangeValue })
return {
panelType,
panel,
@@ -102,11 +96,6 @@ export default {
this.panel = panels[0]
}
if (this.panel.id) {
if (this.panel.params) {
this.panel.params = JSON.parse(this.panel.params)
} else {
this.panel.params = {}
}
const allCharts = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
chart.i = chart.id
this.recursionParamsConvert(chart)
@@ -126,7 +115,7 @@ export default {
recursionParamsConvert (chart) {
chart.params = chart.params ? JSON.parse(chart.params) : {}
chart.firstShow = false
if (isGroup(chart.type)) {
if (chart.type === 94) {
chart.oldH = chart.h
/* chart.params = {
collapse: false
@@ -136,10 +125,10 @@ export default {
chart.h = 1
}
}
if (isBlock(chart.type)) {
if (chart.type === 95) {
let sumGroup = 0
chart.children.forEach(item => {
if (isGroup(item.type)) {
if (item.type === 94) {
sumGroup++
}
})
@@ -157,7 +146,6 @@ export default {
callback({ startTime: myStartTime, endTime: myEndTime })
},
timeRefreshChange () {
// 不是自选时间
if (!this.$refs.dateTimeRange.isCustom) {
const value = this.timeFilter.dateRangeValue
this.$refs.dateTimeRange.quickChange(value)
@@ -183,37 +171,6 @@ export default {
},
groupParentCalcHeight (params) {
this.$refs.panelChartList.groupParentCalcHeight(params.chart, params.childrenList)
},
wholeScreenScroll (e) {
if (this.scroll.prevent) {
return
}
this.scroll.prevent = true
const clientHeight = e.target.clientHeight
const currentScrollTop = e.target.scrollTop
if (currentScrollTop > this.scroll.prevScrollTop) {
// 向下滚动若top在clientHeight内则整屏滚动下去
this.scroll.prevScrollTop = currentScrollTop
if (currentScrollTop < clientHeight) {
scrollToTop(e.target, clientHeight, 200, 'down')
setTimeout(() => {
this.scroll.prevScrollTop = e.target.scrollTop
}, 210)
}
} else if (currentScrollTop < this.scroll.prevScrollTop) {
// 向上滚动若top在clientHeight内则滚动到最顶部
this.scroll.prevScrollTop = currentScrollTop
if (currentScrollTop < clientHeight) {
scrollToTop(e.target, 0, 200, 'up')
setTimeout(() => {
this.scroll.prevScrollTop = e.target.scrollTop
}, 210)
}
}
const vm = this
setTimeout(() => {
vm.scroll.prevent = false
}, 210)
}
}
}

View File

@@ -7,7 +7,7 @@
>
<!-- title和工具栏支持浮动 -->
<chart-header
v-if="!isFullscreen && showHeader && !isSingleValue && !isTabs && !isDetectionSecurity && !isDetectionService"
v-if="!isFullscreen && showHeader && !isSingleValue && !isTabs"
:is-error="isError"
:error-info="errorInfo"
:chart-data="chartData"
@@ -26,7 +26,7 @@
<!-- 数据查询后传入chart组件chart组件内不查询只根据接传递的数据来渲染 -->
<chart
ref="chart"
v-if="(!isGroup || !(chartInfo.params && chartInfo.params.collapse)) && !isTitle "
v-if="((!isGroup) || !(chartInfo.params && chartInfo.params.collapse)) && !isTitle"
:chart-data="chartData"
:result-type="resultType"
:chart-info="chartInfo"
@@ -38,7 +38,6 @@
:table="table"
:is-fullscreen="isFullscreen"
:order-pie-table="orderPieTable"
:time-filter="timeFilter"
@getChartData="getChartData"
@showLoading="showLoading"
:tabHandleClickType="tabHandleClickType"
@@ -54,7 +53,6 @@ import {
isEcharts,
isSingleValue,
isTable,
isBasicTable,
isActiveIpTable,
isTitle,
isMap,
@@ -65,23 +63,20 @@ import {
isMapLine,
isMapBlock,
isSingleValueWithEcharts,
isSingleValueWithPercent,
isSingleValueWithEchartsTemp,
isRelationShip,
isTabs,
isGroup,
isSankey,
isIpBasicInfo,
isIpOpenPortBar,
isIpOpenPort,
isIpHostedDomain,
isDomainWhois,
isDomainDnsRecord,
isCryptocurrencyEventList,
isAppBasicInfo,
isAppRelatedDomain,
isBlock,
isAlarmInfo,
isDetectionSecurity,
isDetectionService
isBlock
} from './charts/tools'
import { tableTitleMapping, legendMapping } from '@/views/charts/charts/chart-table-title'
import { replaceUrlPlaceholder } from '@/utils/tools'
@@ -102,7 +97,11 @@ export default {
timeFilter: Object, // 时间范围
isFullscreen: Boolean,
panelLock: Boolean,
entity: Object
entity: Object,
showHeader: {
type: Boolean,
default: true
}
},
data () {
return {
@@ -150,7 +149,15 @@ export default {
}
] // table的所有数据
},
tabHandleClickType: ''
table: {
pageSize: chartTableDefaultPageSize,
limit: chartTableTopOptions[0], // top-n
orderBy: 'sessions',
tableColumns: [], // table字段
tableData: [], // table的所有数据
currentPageData: [] // table当前页的数据
},
tabHandleClickType:''
}
},
computed: {
@@ -159,41 +166,26 @@ export default {
},
headerHPadding () {
return this.$store.getters.getHeaderHPadding
},
showHeader () {
return this.chartInfo.params && this.chartInfo.params.showHeader
}
},
methods: {
/* 参数 extraParams 额外请求参数 */
getChartData (url, extraParams = {}, chartTimeFilter, num) {
/* 参数 extraParams 额外请求参数isRefresh 是否是刷新 */
getChartData (url, extraParams = {}, isRefresh, chartTimeFilter) {
const vm = this
this.loading = true
this.standaloneTimeRange.use = !!isRefresh
try {
// 单个图表刷新时,使用单独的时间
if (chartTimeFilter) {
// 图表自带timeFilter刷新时
this.queryTimeRange = { startTime: getSecond(chartTimeFilter.startTime), endTime: getSecond(chartTimeFilter.endTime), dateRangeValue: chartTimeFilter.dateRangeValue }
this.queryTimeRange = { startTime: getSecond(chartTimeFilter.startTime), endTime: getSecond(chartTimeFilter.endTime) }
} else if (this.standaloneTimeRange.use) {
// 单个图表刷新时,使用单独的时间
this.queryTimeRange = { startTime: getSecond(this.standaloneTimeRange.startTime), endTime: getSecond(this.standaloneTimeRange.endTime), dateRangeValue: this.timeFilter.dateRangeValue }
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), dateRangeValue: this.timeFilter.dateRangeValue }
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), dateRangeValue: this.chartTimeFilter.dateRangeValue }
this.queryTimeRange = { startTime: getSecond(this.chartTimeFilter.startTime), endTime: getSecond(this.chartTimeFilter.endTime) }
}
const chartParams = this.chartInfo.params
if (this.isAlarmInfo && JSON.stringify(extraParams) === '{}') {
extraParams = {
pageNo: 1,
pageSize: 9
}
}
if (this.isDetectionService || this.isDetectionSecurity) {
extraParams = {
pageNo: 1,
pageSize: 6
}
}
// 接口查询参数
this.queryParams = {
...this.handleQueryParams(),
@@ -206,9 +198,34 @@ export default {
if (requestUrl && requestUrl.indexOf('dnsServerRole') > -1) {
this.queryParams.dnsServerRole = extraParams.dnsServerRole || dnsServerRole.RTDNS
}
if (requestUrl) {
get(replaceUrlPlaceholder(requestUrl, this.queryParams)).then(response => {
// if (this.chartInfo.type === 23 && testData) {
// response = testData.data
// } else if (this.chartInfo.type === 24 && testData) {
// response = testData.data2
// }
if (this.chartInfo.type === 3) {
response = {
code: 200,
data: {
result: [
{
dnsServerRole: extraParams.dnsServerRole || dnsServerRole.RTDNS,
ipLocationCountry: 'China',
ipLocationId: 'CN',
count: 161
},
{
dnsServerRole: extraParams.dnsServerRole || dnsServerRole.RTDNS,
ipLocationCountry: 'Japan',
ipLocationId: 'JP',
count: 222
}
]
}
}
}
if (response.code === 200) {
if (Array.isArray(response.data.result)) {
response.data.result.forEach(item => {
@@ -219,7 +236,7 @@ export default {
}
this.chartData = response.data.result
this.resultType = response.data.resultType
if (isEchartsWithStatistics(this.chartInfo.type)) {
if (this.chartInfo.type === 12) {
const newArr = []
_.forEach(this.chartData, function (value, key) {
_.forEach(value.values, function (value, key) {
@@ -238,19 +255,13 @@ export default {
}
if (this.isTable) {
this.table.tableData = response.data.result
this.table.tableColumns = chartParams.columns
// this.table.tableColumns = chartParams.columns
// this.table.tableColumns = this.getTableTitle(response.data.result)
this.table.currentPageData = this.getTargetPageData(1, this.table.pageSize, this.table.tableData)
} else if (this.isSingleValue) {
if (chartParams && chartParams.dataKey) {
if (response.data.result && (response.data.result[chartParams.dataKey] || response.data.result[chartParams.dataKey] === 0)) {
this.chartData = response.data.result[chartParams.dataKey]
} else if (response.data.result && (response.data.result[chartParams.dataKey + 'Value'] || response.data.result[chartParams.dataKey + 'Value'] === 0)) {
this.chartData = {
value: response.data.result[chartParams.dataKey + 'Value'],
p50: response.data.result[chartParams.dataKey + 'P50'],
p90: response.data.result[chartParams.dataKey + 'P90']
}
} else {
this.chartData = null
}
@@ -263,11 +274,13 @@ export default {
this.errorInfo = response.msg || response.message || 'Unknown'
}
}).finally(() => {
this.loading = false
setTimeout(() => {
this.loading = false
}, 200)
})
} else if (this.isGroup || this.isTabs) {
this.$refs.chart.$refs.chart.reload()
} else if (this.isBlock) {
} else if (this.chartInfo.type === 94) {
this.chartInfo.children = [...this.chartInfo.children]
} else if (this.chartInfo.type === 95) {
if (!this.chartInfo.firstShow) {
this.chartInfo.firstShow = true
} else {
@@ -300,26 +313,15 @@ export default {
this.$refs.chart.resize()
},
refresh (chartTimeFilter) {
if (chartTimeFilter) {
this.timeFilter.startTime = chartTimeFilter.startTime
this.timeFilter.endTime = chartTimeFilter.endTime
this.timeFilter.dateRangeValue = chartTimeFilter.dateRangeValue
this.getChartData(null, {}, chartTimeFilter)
} else {
if (this.timeFilter.dateRangeValue && this.timeFilter.dateRangeValue > 0) {
const myEndTime = window.$dayJs.tz().valueOf()
const myStartTime = myEndTime - this.timeFilter.dateRangeValue * 60 * 1000
this.standaloneTimeRange.use = true
this.standaloneTimeRange.startTime = myStartTime
this.standaloneTimeRange.endTime = myEndTime
} else {
this.standaloneTimeRange.use = false
}
this.emitter.emit('chart-pageNo')
this.getChartData(null, {})
}
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.emitter.emit('chart-pageNo')
this.getChartData(null, {}, true, chartTimeFilter)
},
tabHandleClick (value) {
tabHandleClick(value){
this.tabHandleClickType = value
},
showFullscreen (show) {
@@ -394,14 +396,16 @@ export default {
mounted () {
this.showLoading(true)
this.getChartData()
this.$store.commit('cleanChartList')
// setTimeout(() => {
// this.getChartData()
// }, 200)
},
setup (props) {
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
let table = {}
if (isBasicTable(props.chartInfo.type)) {
if (isTable(props.chartInfo.type)) {
table = {
pageSize: chartTableDefaultPageSize,
limit: chartTableTopOptions[0], // top-n
@@ -421,7 +425,7 @@ export default {
isEchartsWithStatistics: isEchartsWithStatistics(props.chartInfo.type),
isSingleValue: isSingleValue(props.chartInfo.type),
isSingleValueWithEcharts: isSingleValueWithEcharts(props.chartInfo.type),
isSingleValueWithPercent: isSingleValueWithPercent(props.chartInfo.type),
isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(props.chartInfo.type),
isRelationShip: isRelationShip(props.chartInfo.type),
isTable: isTable(props.chartInfo.type),
isActiveIpTable: isActiveIpTable(props.chartInfo.type),
@@ -435,15 +439,12 @@ export default {
isSankey: isSankey(props.chartInfo.type),
isIpBasicInfo: isIpBasicInfo(props.chartInfo.type),
isIpHostedDomain: isIpHostedDomain(props.chartInfo.type),
isIpOpenPortBar: isIpOpenPortBar(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),
isAlarmInfo: isAlarmInfo(props.chartInfo.type),
isDetectionService: isDetectionService(props.chartInfo.type),
isDetectionSecurity: isDetectionSecurity(props.chartInfo.type)
isAppRelatedDomain: isAppRelatedDomain(props.chartInfo.type)
}
}
}

View File

@@ -1,17 +1,9 @@
<template>
<div style="height: calc(100vh - 70px);width: 100%;" v-if="wholeScreenScroll">
<dns-screen v-if="currentPath === wholeScreenRouterMapping.dns"
:copy-data-list="copyDataList"
ref="dnsScreen"
:time-filter="timeFilter"
:entity="entity">
</dns-screen>
</div>
<div :id='`chartList${(isGroup ? "Group" : "") + timestamp}`' class="chart-list" ref="layoutBox">
<grid-layout
ref="layout"
v-if="gridLayoutShow"
v-model:layout="normalCopyDataList"
v-model:layout="copyDataList"
:col-num="30"
:is-draggable="!panelLock"
:is-resizable="!panelLock"
@@ -21,7 +13,7 @@
:use-css-transforms="false"
>
<grid-item
v-for="item in normalCopyDataList"
v-for="item in copyDataList"
:key="item.id"
:h="item.h"
:i="item.i"
@@ -30,7 +22,7 @@
:y="item.y"
:static="item.static"
:ref="'grid-item' + item.id"
:isResizable="isGroup ? false: null"
:isResizable = "item.type === 'group' ? false: null"
dragAllowFrom=".chart-header"
dragIgnoreFrom=".chart-header__tools"
v-bind="anchorPoint(item)"
@@ -38,6 +30,7 @@
<panel-chart
:ref="'chart' + item.id"
:chart-info="item"
:show-header="true"
:time-filter="timeFilter"
:entity="entity"
@groupShow="groupShow"
@@ -73,24 +66,19 @@
<script>
import PanelChart from '@/views/charts/PanelChart'
import VueGridLayout from 'vue-grid-layout'
import { getGroupHeight, getTypeCategory, isGroup } from './charts/tools'
import { getGroupHeight, getTypeCategory } from './charts/tools'
import _ from 'lodash'
import { useRouter } from 'vue-router'
import DnsScreen from '@/views/charts/wholeScreenScroll/DnsScreen'
import { wholeScreenRouterMapping } from '@/utils/constants'
export default {
name: 'PanelChartList',
components: {
PanelChart,
DnsScreen,
GridLayout: VueGridLayout.GridLayout,
GridItem: VueGridLayout.GridItem
},
props: {
timeFilter: Object, // 时间范围
panelLock: { type: Boolean, default: true },
wholeScreenScroll: { type: Boolean, default: false },
isGroup: Boolean,
entity: Object,
dataList: Array // 看板中所有图表信息
@@ -100,8 +88,7 @@ export default {
gridLayoutLoading: false,
gridLayoutShow: false,
rowHeight: 40,
copyDataList: [], // 所有的图表
normalCopyDataList: [], // 非整屏滚动的图表
copyDataList: [],
noData: false, // no data
tempDom: { height: '', width: '' },
stepWidth: null,
@@ -113,8 +100,7 @@ export default {
chartInfo: {}
},
scrollTop: 0,
scrollTopTimer: null,
wholeScreenRouterMapping
scrollTopTimer: null
}
},
methods: {
@@ -126,12 +112,8 @@ export default {
},
reload () {
this.copyDataList.forEach(item => {
if (this.$refs['chart' + item.id]) {
this.$refs['chart' + item.id].getChartData()
}
this.$refs['chart' + item.id].getChartData()
})
this.$refs.dnsScreen.reload()
},
showFullscreen (show, chartInfo) {
this.fullscreen.chartInfo = chartInfo
@@ -144,14 +126,11 @@ export default {
if (item.params.collapse) {
item.h = 1
} else {
item.h = getGroupHeight(item.children) + 0.4 + 1
item.h = getGroupHeight(item.children) + 1.5
}
}
})
this.copyDataList = [...this.copyDataList]
this.normalCopyDataList = this.copyDataList.filter(function (item) {
return item.y >= -1
})
this.emitter.emit('groupParentCalcHeight', { chart, childrenList: this.copyDataList })
},
groupParentCalcHeight (chart, childrenList) {
@@ -160,16 +139,17 @@ export default {
const children = parent.children.find(item => item.id === chart.id)
children.h = chart.h
children.params = chart.params
// 第二个是空隙,第三个是标题的高度
parent.h = getGroupHeight(childrenList) + 0.4 + 1
this.copyDataList = [...this.copyDataList]
this.normalCopyDataList = this.copyDataList.filter(function (item) {
return item.y >= -1
let sumGroup = 0
childrenList.forEach(item => {
if (item.type === 94) {
sumGroup++
}
})
parent.h = getGroupHeight(childrenList) + sumGroup * 0.5
this.copyDataList = [...this.copyDataList]
}, 100)
}
},
computed: {
anchorPoint () {
return function (chart) {
@@ -181,12 +161,6 @@ export default {
}
}
},
setup (props) {
const { currentRoute } = useRouter()
return {
currentPath: currentRoute.value.path
}
},
watch: {
dataList: {
deep: true,
@@ -214,20 +188,25 @@ export default {
})
this.$nextTick(() => {
this.copyDataList = JSON.parse(JSON.stringify(tempList))
this.normalCopyDataList = this.copyDataList.filter(function (item) {
return item.y >= -1
})
setTimeout(() => {
this.gridLayoutShow = true
})
setTimeout(() => {
this.copyDataList.forEach(item => {
if (isGroup(item.type) && !item.firstShow) {
// if (item.type === 95) {
// console.log(item.h, item.name)
// item.children.forEach(children => {
// console.log(children.name, children.h, children.y)
// })
// let parentH = 1.5
// parentH += getGroupHeight(item.children)
// if (parentH !== item.h) {
// item.h = parentH
// }
// }
if (item.type === 94 && !item.firstShow) {
item.firstShow = true
this.copyDataList = [...this.copyDataList]
this.normalCopyDataList = this.copyDataList.filter(function (item) {
return item.y >= -1
})
this.emitter.emit('groupParentCalcHeight', { chart: item, childrenList: this.copyDataList })
}
})

View File

@@ -28,7 +28,7 @@
v-for="(c, i) in table.tableColumns"
show-overflow-tooltip
:key="i"
:label="c"
:label="$t(chartTableOrderOptionsMapping[c])"
:prop="c"
>
<template #default="{ row }">

View File

@@ -1,107 +1,85 @@
<template>
<div class="cn-chart__alarm-info">
<div class="no-data" v-if="isNoData">No data</div>
<template v-else>
<div class="alarm-info__box">
<div
class="box__body"
v-for="(value, index) in chartData ? chartData : []"
:key="index"
>
<div class="body__content">
<div class="content__icon-box">
<div
class="icon-box__icon"
:style="{
background: eventSeverityColor[value.eventSeverity],
opacity: 0.1,
}"
></div>
<i
class="cn-icon cn-icon-alert"
:style="{
color: eventSeverityColor[value.eventSeverity],
opacity: 1,
}"
></i>
<div class="cn-chart-alarm-info">
<div class="cn-chart-alarm-info-mainContent">
<div
class="cn-chart-alarm-content"
v-for="(value, index) in chartData"
:key="index"
>
<div class="cn-alarm-info-main">
<div class="cn-alarm-info-main-left">
<div
class="cn-chart-alarm-info-icon"
:style="{
background: eventSeverityColor[value.eventSeverity],
opacity: 0.1,
}"
></div>
<i
class="cn-icon cn-icon-alert"
:style="{
color: eventSeverityColor[value.eventSeverity],
opacity: 1,
}"
></i>
</div>
<div class="cn-alarm-info-textContent">
<div class="cn-alarm-info-main-title">
<!-- <span v-if="value.entityType === 'domain'">{{ value.domain }}</span>
<span v-if="value.entityType === 'app'">{{ value.appName }}</span>
<span v-if="value.entityType === 'ip'">{{ value.serverIp }}</span> -->
111.111.1.1
</div>
<div class="cn-alarm-info-bottom">
<div
class="cn-alarm-info-bottom-type"
:style="{ 'color': eventSeverityColor[value.eventSeverity] ,'border-color':eventSeverityColor[value.eventSeverity]}"
>
<!-- {{$t(`${value.eventType}`)}} -->
{{ value.eventType }}
</div>
<div class="content__text-box">
<div class="text-box__title">
<div v-if="value.entityType === 'domain'" :title="value.domain">
<span>{{ value.domain }}</span>
</div>
<div v-if="value.entityType === 'app'" :title="value.appName">
<span>{{ value.appName }}</span>
</div>
<div v-if="value.entityType === 'ip'" :title="value.serverIp">
<span>{{ value.serverIp }}</span>
</div>
<div class="cn-alarm-info-bottom-middle">
<i class="cn-icon cn-icon-time2"></i>
<div class="cn-alarm-info-bottom-time">
&nbsp; {{ $t(`dns.startTime`) }}:&nbsp;&nbsp;&nbsp;
</div>
<div>{{ changeDate(value.startTime) }}</div>
</div>
<div class="cn-alarm-info-bottom-right">
<i class="cn-icon cn-icon-time2"></i>
<div class="cn-alarm-info-bottom-time">
&nbsp;{{ $t(`dns.duration`) }}:&nbsp;&nbsp;&nbsp;
</div>
<div class="text-box__text">
<div
class="text__type"
:style="{
color: eventSeverityColor[value.eventSeverity],
'border-color': eventSeverityColor[value.eventSeverity],
}"
:title="value.eventType"
>
{{ value.eventType }}
</div>
<div class="text__time-box">
<i class="cn-icon cn-icon-time2"></i>
<div class="time-box__start-time">
&nbsp; {{ $t(`dns.startTime`) }}:&nbsp;&nbsp;&nbsp;
</div>
<div>
{{
value.startTime
? dayJs
.tz(getMillisecond(value.startTime))
.format('YYYY-MM-DD HH:mm:ss')
: '-'
}}
</div>
</div>
&nbsp;&nbsp;&nbsp;
<div class="text__duration-box">
<i class="cn-icon cn-icon-time2"></i>
<div class="time-box__start-time">
&nbsp;{{ $t(`dns.duration`) }}:&nbsp;&nbsp;&nbsp;
</div>
<div
class="duration-box__circle"
:style="{
background: eventSeverityColor[value.eventSeverity],
}"
></div>
&nbsp;&nbsp;&nbsp;
<div>
{{
unitConvert(value.endTime - value.startTime, 'time').join(
' ',
)
}}
</div>
</div>
<div
class="cn-alarm-info-bottom-circle"
:style="{ background: eventSeverityColor[value.eventSeverity] }"
></div>
&nbsp;&nbsp;&nbsp;
<div>
{{
unitConvert(value.endTime - value.startTime, 'time').join(' ')
}}
</div>
</div>
</div>
</div>
</div>
<chart-table-pagination
ref="tablePagination"
class="alarm-info__pagination"
:total="alarmInfoCount.result"
:pageSizeForAlarm="pageSizeForAlarm"
v-model:currentPage="pageNo"
@pageJump="pageJump"
></chart-table-pagination>
</template>
</div>
</div>
<chart-table-pagination
ref="tablePagination"
class="cn-chart-alarm-info-pagination"
:total="alarmInfoCount.result"
:pageSizeForAlarm="pageSizeForAlarm"
v-model:currentPage="pageNo"
@pageJump="pageJump"
></chart-table-pagination>
</div>
</template>
@@ -111,8 +89,6 @@ import _ from 'lodash'
import unitConvert from '@/utils/unit-convert'
import ChartTablePagination from '@/views/charts/charts/ChartTablePagination'
import { get } from '@/utils/http'
import { getMillisecond } from '@/utils/date-util'
import { api } from '@/utils/api'
export default {
name: 'isAlarmInfo',
@@ -120,119 +96,65 @@ export default {
chartInfo: Object,
chartData: [Array, Object],
tabHandleClickType: String,
queryParams: Object
},
data () {
data() {
return {
pageSizeForAlarm: 9,
eventSeverityColor: eventSeverityColor,
pageNo: 1,
alarmInfoCount: {},
fromChartData: '',
isNoData: false
// result: [
// {
// entityType: 'ip',
// serverIp: '1.2.3.41.2.3.41.2.3.41.2.3.41.2.3.41.2.3.4',
// domain: '',
// appName: 'wechat',
// eventSeverity: 'high',
// eventType: 'type',
// startTime: 1111111111,
// durationMs: 60000,
// endTime: 1111111112,
// },
// ],
}
},
computed: {
isNoData () {
let isNoData = true
if (!this.$_.isEmpty(this.chartData)) {
isNoData = false
}
return isNoData
alarmInfoCount: {
},
fromChartData:''
}
},
watch: {
tabHandleClickType: {
deep: true,
handler (n) {
this.$nextTick(() => {
this.getData(1, n)
})
}
handler(n) {
this.getData(1,n)
},
},
alarmInfoCount: {
deep: true,
handler (n) {}
},
queryParams: {
deep: true,
handler (n) {
if (n.startTime && n.endTime) {
this.getCount(1)
}
}
}
},
created(){
this.getData(1,'All')
},
components: {
ChartTablePagination
ChartTablePagination,
},
methods: {
unitConvert,
getMillisecond,
getCount () {
const countQuery = {
startTime: this.queryParams.startTime,
endTime: this.queryParams.endTime,
eventSeverity:
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType
}
this.$nextTick(() => {
get(api.dashboard.DnsServiceInsights.alarmInfoCount, {
...countQuery
}).then((response) => {
if (response.code === 200) {
this.alarmInfoCount = response.data
}
})
})
},
getData (val, n) {
getData(val,n) {
this.pageNo = val
const now = window.$dayJs.tz().valueOf()
const extraParams = {
pageNo: val,
pageSize: this.pageSizeForAlarm,
eventSeverity: n
? n === 'All'
? ''
: n
: this.tabHandleClickType === 'All'
? ''
: this.tabHandleClickType
eventSeverity: n? (n==='All'?'':n ): this.tabHandleClickType === 'All'?'':this.tabHandleClickType
}
const query = {
startTime: this.queryParams.startTime,
endTime: this.queryParams.endTime,
console.log('extraParams',extraParams);
this.$emit('getAlarmInfo', null, extraParams)
const queryParams = {
startTime: Math.floor(now / 1000 - 3600),
endTime: Math.floor(now / 1000),
eventSeverity:
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType,
}
this.$emit('getAlarmInfo', null, extraParams, false, {
startTime: query.startTime,
endTime: query.endTime
})
get(api.dashboard.DnsServiceInsights.alarmInfoCount, {
...query
get('/interface/dns/alarmInfoCount', {
...queryParams,
}).then((response) => {
if (response.code === 200) {
this.alarmInfoCount = response.data
}
})
},
pageJump (val) {
changeDate(value) {
return window.$dayJs.tz(value).format('YYYY-MM-DD HH:mm:ss')
},
pageJump(val) {
this.getData(val)
}
}
},
},
}
</script>

View File

@@ -4,9 +4,9 @@
<div style="display: flex; justify-content: space-between; width: 100%;">
<el-descriptions :column="1" style="padding: 20px 30px;">
<el-descriptions-item :label="$t('overall.appName') + ':'">{{$_.get(chartData, "name") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.appFullName') + ':'">{{$_.get(chartData, "appLongname") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.technology') + ':'">{{$_.get(chartData, "appTechnology") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.remark') + ':'">{{$_.get(chartData, "appDescription") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.appFullName') + ':'">{{$_.get(chartData, "allName") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.technology') + ':'">{{$_.get(chartData, "tech") || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.remark') + ':'">{{$_.get(chartData, "description") || '-'}}</el-descriptions-item>
</el-descriptions>
<div class="cn-chart__body-single">
<div class="cn-chart__body-single-table">
@@ -15,10 +15,10 @@
</div>
<div class="single-value__content">
<div>
<span style="color: #666;">{{$t('entities.category')}}</span>
<span>{{$t('entities.category')}}</span>
</div>
<div>
<span style="color: #333; font-weight: bold;">{{$_.get(chartData, "category") || '-'}}</span>
<span>{{$_.get(chartData, "category") || '-'}}</span>
</div>
</div>
</div>
@@ -28,10 +28,10 @@
</div>
<div class="single-value__content">
<div>
<span style="color: #666;">{{$t('entities.subcategory')}}</span>
<span>{{$t('entities.subcategory')}}</span>
</div>
<div>
<span style="color: #333; font-weight: bold;">{{$_.get(chartData, "subcategory") || '-'}}</span>
<span>{{$_.get(chartData, "subcategory") || '-'}}</span>
</div>
</div>
</div>
@@ -41,10 +41,10 @@
</div>
<div class="single-value__content">
<div>
<span style="color: #666;">{{$t('entities.reputationLevel')}}</span>
<span>{{$t('entities.reputationLevel')}}</span>
</div>
<div>
<span style="color: #333; font-weight: bold;">{{$_.get(chartData, "risk") || '-'}}</span>
<span>{{$_.get(chartData, "risk") || '-'}}</span>
</div>
</div>
</div>

View File

@@ -10,36 +10,30 @@
<script>
import chartMixin from '@/views/charts/charts/chart-mixin'
import _ from 'lodash'
export default {
name: 'ChartBlock',
mixins: [chartMixin],
props: {
timeFilter: Object
},
data () {
return {
dataList: [],
time: {},
firstShow: false
}
},
mounted () {
this.dataList = JSON.parse(JSON.stringify(this.chartInfo.children))
// this.time = JSON.parse(JSON.stringify(this.timeFilter))
this.firstShow = true
},
methods: {
reload () {
this.dataList = _.cloneDeep(this.dataList)
}
},
setup (props) {
const copyAndSort = dataList => {
const list = _.cloneDeep(dataList)
return list.sort((data1, data2) => {
return data1.x - data2.x
})
}
const dataList = copyAndSort(props.chartInfo.children)
return {
copyAndSort,
dataList
console.log(123132)
this.dataList = JSON.parse(JSON.stringify(this.chartInfo.children))
// this.time = JSON.parse(JSON.stringify(this.timeFilter))
}
}
}

View File

@@ -1,20 +0,0 @@
<template>
<div style="overflow-y: auto; height: 100%; color: #555; white-space: pre;">{{linuxLineSymbolConvert}}</div>
</template>
<script>
export default {
name: 'ChartDomainRecursiveResolve',
props: {
chartInfo: Object,
chartData: String,
resultType: Object,
queryParams: Object
},
computed: {
linuxLineSymbolConvert () {
return this.chartData ? this.chartData.replaceAll(/\n/g, '\r\n') : ''
}
}
}
</script>

View File

@@ -4,27 +4,26 @@
<script>
import unitConvert from '@/utils/unit-convert'
import { lineToSpace, reverseSortBy, humpToSpace } from '@/utils/tools'
import * as echarts from 'echarts'
import { lineToSpace } from '@/utils/tools'
import { unitTypes } from '@/utils/constants'
import chartEchartMixin from './chart-echart-mixin'
import { isEchartsLine, isEchartsPie } from './tools'
import { getOption, isEchartsPie } from './tools'
import { legendMapping } from '@/views/charts/charts/chart-table-title'
import _ from 'lodash'
export default {
name: 'ChartEchart',
mixins: [chartEchartMixin],
data () {
return {}
return {
}
},
props: {
resultType: Object,
chartInfo: Object
resultType: Object
},
setup (props) {
return {
isEchartsPie: isEchartsPie(props.chartInfo.type),
isEchartsLine: isEchartsLine(props.chartInfo.type)
isEchartsPie: isEchartsPie(props.chartInfo.type)
}
},
methods: {
@@ -37,303 +36,47 @@ export default {
this.handleYaxis()
if (this.isEchartsPie) {
if (chartParams.size && chartParams.size === 'small') {
this.chartOption.series[0] = {
...this.chartOption.series[0],
radius: ['30%', '45%'],
label: {
show: false
},
labelLine: {
show: false
}
this.chartOption.series[0].data = this.chartData.map(d => {
return {
name: lineToSpace(d.name),
data: d,
value: parseInt(d.num),
unitType: chartParams.unitType ? chartParams.unitType : 'number'
}
this.chartOption.legend = {
...this.chartOption.legend,
left: '60%',
itemGap: 5,
itemWidth: 8,
itemHeight: 8,
formatter: function (name) {
return name.length > 9 ? name.substr(0, 9) + '...' : name
// return echarts.format.truncateText(name, 6, '…');
},
tooltip: {
show: true
},
textStyle: {
// 图例文字的样式
color: '#666666',
fontSize: 12,
fontWeight: 400
}
}
let chartDataTmp = []
let otherData = []
this.chartData.sort(reverseSortBy('num'))
if (this.chartData.length > 5) {
chartDataTmp = this.chartData.slice(0, 5)
chartDataTmp.forEach((data) => {
if (data.name === '') {
data.name = ' '
}
})
let otherSum = 0
otherData = this.chartData.slice(5)
otherData.forEach((data) => {
otherSum = otherSum + data.num
})
chartDataTmp.push({ num: otherSum, name: 'other' })
} else if (this.chartData.length <= 5) {
chartDataTmp = this.chartData.slice(0, this.chartData.length)
chartDataTmp.forEach((data) => {
if (data.name === '') {
data.name = ' '
}
})
}
this.chartOption.series[0].data = chartDataTmp.map((d) => {
return {
name: lineToSpace(d.name),
data: d,
value: parseInt(d.num),
unitType: chartParams.unitType ? chartParams.unitType : 'number'
}
})
} else {
this.chartOption.series[0].data = this.chartData.map((d) => {
return {
name: lineToSpace(d.name),
data: d,
value: parseInt(d.num),
unitType: chartParams.unitType ? chartParams.unitType : 'number'
}
})
}
})
} else {
const seriesTemplate = this.chartOption.series[0]
this.chartOption.series = this.chartData.map((r) => {
const serie = {
this.chartOption.series = this.chartData.map(r => {
return {
...seriesTemplate,
name: legendMapping[
`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`
]
? legendMapping[
`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`
]
: humpToSpace(r.legend),
data: r.values.map((v) => [
Number(v[0]) * 1000,
Number(v[1]),
chartParams.unitType
])
name: legendMapping[`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`] ? legendMapping[`${this.entity && this.entity.ip ? 'ip_' : ''}${r.legend}`] : lineToSpace(r.legend),
data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType])
}
if (this.isEchartsLine) {
serie.data = serie.data.slice(1, serie.data.length - 2)
if (this.chartData.length === 1) { // 只有一条曲线
if (!_.isNaN(parseFloat(this.chartData[0].aggregation.p50)) && !_.isNaN(parseFloat(this.chartData[0].aggregation.p90))) {
serie.markLine = {
silent: true,
symbol: 'none',
label: {
distance: [-50, 0],
formatter (params) {
const arr = unitConvert(Number(params.value), chartParams.unitType).join(' ')
let desc = ''
switch (params.dataIndex) {
case 0: {
desc = 'P50'
break
}
case 1: {
desc = 'P90'
break
}
default:
break
}
return `${arr} (${desc})`
}
},
data: [
{
name: 'P50',
yAxis: this.chartData[0].aggregation.p50
},
{
name: 'P90',
yAxis: this.chartData[0].aggregation.p90
}
]
}
}
} else if (this.chartData.length > 1) { // 有多条曲线
this.handleLegendClick()// 自定义legend的点击事件
}
}
return serie
})
}
const rows = (this.chartData.length - 1) / 4 + 1 // 根据legend个数动态预留legend空间
const gridTop = 10 + 27 * rows
const gridTemplate = this.chartOption.grid
// option中默认单位是数字当单位是字节、百分比、时间时额外处理
if (chartParams.unitType === unitTypes.byte) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.byte).join('')
this.chartOption.yAxis.axisLabel.formatter = function (value, index, a, b) {
return unitConvert(value, unitTypes.byte).join(' ')
}
this.chartOption.grid = {
...gridTemplate,
top: gridTop,
left: 75
}
} else if (chartParams.unitType === unitTypes.percent) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.percent).join('')
}
} else if (chartParams.unitType === unitTypes.time) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.time).join('')
}
}
if (chartParams.showLegend) {
const rows = (this.chartData.length - 1) / 4 + 1 // 根据legend个数动态预留legend空间
} else {
this.chartOption.grid = {
...this.chartOption.grid,
top: 10 + 27 * rows
...gridTemplate,
top: gridTop
}
}
this.loadEchart()
},
// 点击前高亮legend个数
getSelectedNum (params) {
let selectedNum = 0
const legendItem = params.selected
for (const name in legendItem) {
if (name === params.name) {
if (!legendItem[name]) {
selectedNum = selectedNum + 1
}
} else {
if (legendItem[name]) {
selectedNum = selectedNum + 1
}
}
}
return selectedNum
},
// 点击后高亮legend个数
getAfterSelectedNum (params) {
let selectedNum = 0
const legendItem = params.selected
for (const name in legendItem) {
if (legendItem[name]) {
selectedNum = selectedNum + 1
}
}
return selectedNum
},
// 自定义legend的点击事件:此方法只处理多条曲线的情况单条曲线正常切换legend和曲线
handleLegendClick () {
const self = this
// legend点击事件
this.myChart.off('legendselectchanged')
this.myChart.on('legendselectchanged', function (params) {
const legendNum = Object.keys(params.selected).length
const selectedNum = self.getSelectedNum(params)
const legendItem = params.selected
if (selectedNum === legendNum) { // 点击前:全部曲线高亮
for (const name in legendItem) {
if (name === params.name) {
legendItem[name] = true
} else {
legendItem[name] = false
}
}
} else if (selectedNum === 1 && !params.selected[params.name]) { // 点击前:多条曲线,且只有一条曲线高亮时
for (const name in legendItem) {
legendItem[name] = true
}
}
self.myChart.setOption({
legend: {
selected: legendItem
}
})
if (self.getAfterSelectedNum(params) === 1) { // 点击后只有一条曲线高亮
const chartParams = self.chartInfo.params
// 多条曲线且只有一条曲线高亮时显示P50 P90 分位值,不止一个时隐藏标线
let selectedName = ''
for (const name in legendItem) {
if (legendItem[name]) {
selectedName = name
}
}
const serieArray = []
self.chartOption.series.forEach((item, i) => {
if (item.name === selectedName) {
if (!_.isNaN(parseFloat(self.chartData[i].aggregation.p50)) && !_.isNaN(parseFloat(self.chartData[i].aggregation.p90))) {
const markLine = {
silent: true,
symbol: 'none',
label: {
distance: [-50, 0],
formatter (params) {
const arr = unitConvert(Number(params.value), chartParams.unitType).join(' ')
let desc = ''
switch (params.dataIndex) {
case 0: {
desc = 'P50'
break
}
case 1: {
desc = 'P90'
break
}
default:
break
}
return `${arr} (${desc})`
}
},
data: [
{
name: 'P50',
yAxis: self.chartData[i].aggregation.p50
},
{
name: 'P90',
yAxis: self.chartData[i].aggregation.p90
}
]
}
item.markLine = markLine
}
}
serieArray.push(item)
})
self.myChart.setOption({
series: serieArray
})
} else { // 不止一条线高亮时隐藏标线
const serieArray = []
self.chartOption.series.forEach((item, i) => {
item.markLine = []
serieArray.push(item)
})
self.myChart.setOption({
series: serieArray
})
}
})
}
}
}
</script>

View File

@@ -25,8 +25,6 @@ import {
ipHostedDomain
} from '@/views/charts/charts/options/pie'
import chartEchartMixin from './chart-echart-mixin'
import { get, post } from '@/utils/http'
import { reverseSortBy } from '@/utils/tools'
export default {
name: 'ChartEchartAppRelateDomain',
@@ -40,65 +38,26 @@ export default {
methods: {
initEcharts (id) {
this.initDom(id, 2)
const chartParams = this.chartInfo.params
const domains = this.chartData.toString()
// const domains = "office.com,dbank.com"
this.$emit('showLoading', true)
const typeUrl = chartParams.byCategoryUrl.slice(0, chartParams.byCategoryUrl.indexOf('?'))
const reputationUrlUrl = chartParams.byReputationUrl.slice(0, chartParams.byReputationUrl.indexOf('?'))
const byType = new Promise(resolve => {
get(typeUrl, { domains: domains }).then(response => {
// post(replaceUrlPlaceholder(chartParams.byCategoryUrl, { domains: domains })).then(response => {
if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
// this.noData0 = true
} else {
// this.noData0 = false
// const chartOption = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.sort(reverseSortBy('uniqDomains')).map(d => {
return {
data: d,
name: d.categoryName,
value: parseInt(d.uniqDomains),
unitType: chartParams.unitType
}
})
this.chartOption.series[0].data = data
}
}
}).finally(() => {
resolve()
})
})
const byReputation = new Promise(resolve => {
get(reputationUrlUrl, { domains: domains }).then(response => {
if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
// this.noData1 = true
} else {
// this.noData1 = false
// const chartOption = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.sort(reverseSortBy('uniqDomains')).map(d => {
return {
data: d,
name: d.reputationLevel,
value: parseInt(d.uniqDomains),
unitType: chartParams.unitType
}
})
this.chartOption2.series[0].data = data
// this.myChart2.setOption(chartOption)
}
}
}).finally(() => {
resolve()
})
})
Promise.all([byType, byReputation]).finally(response => {
this.loadEchart(2)
})
this.chartOption.series[0].data = [
{
name: 'test1',
value: 32
},
{
name: 'test2',
value: 21
},
{
name: 'test3',
value: 20
},
{
name: 'test4',
value: 7
}
]
this.loadEchart(2)
}
}
}

View File

@@ -4,7 +4,7 @@
<div class="hosted-domain__list">
<div class="hosted-domain__list-title">{{$t('overall.domain')}}</div>
<div class="hosted-domain__list-body">
<div class="hosted-domain__list-row" v-for="(data, i) in chartData" :key="i">{{data.domain}}</div>
<div class="hosted-domain__list-row" v-for="(data, i) in chartData" :key="i">{{data}}</div>
</div>
</div>
<div class="hosted-domain__chart">
@@ -21,7 +21,11 @@
</template>
<script>
import { replaceUrlPlaceholder, reverseSortBy } from '@/utils/tools'
import * as echarts from 'echarts'
import {
ipHostedDomain
} from '@/views/charts/charts/options/pie'
import { replaceUrlPlaceholder } from '@/utils/tools'
import { get } from '@/utils/http'
import chartEchartMixin from './chart-echart-mixin'
@@ -39,59 +43,57 @@ export default {
initEcharts (id) {
this.initDom(id, 2)
const chartParams = this.chartInfo.params
const domains = this.chartData.map(function (item, i) {
return item.domain
}).join(',')
this.$emit('showLoading', true)
const byType = new Promise(resolve => {
get(replaceUrlPlaceholder(chartParams.byCategoryUrl, { domains: domains })).then(response => {
get(replaceUrlPlaceholder(chartParams.byTypeUrl, { ip: this.entity.ip })).then(response => {
if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
// this.noData0 = true
} else {
// this.noData0 = false
// chartOption = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.sort(reverseSortBy('uniqDomains')).map(d => {
const chartOption = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.map(d => {
return {
data: d,
name: d.categoryName,
value: parseInt(d.uniqDomains),
name: d.category,
value: parseInt(d.count),
unitType: chartParams.unitType
}
})
this.chartOption.series[0].data = data
// this.myChart.setOption(this.chartOption)
chartOption.series[0].data = data
this.myChart.setOption(chartOption)
}
}
resolve()
})
})
const byCredit = new Promise(resolve => {
get(replaceUrlPlaceholder(chartParams.byReputationUrl, { domains: domains })).then(response => {
get(replaceUrlPlaceholder(chartParams.byCreditUrl, { ip: this.entity.ip })).then(response => {
if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
// this.noData1 = true
} else {
// this.noData1 = false
// this.chartOption2 = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.sort(reverseSortBy('uniqDomains')).map(d => {
const chartOption = this.$_.cloneDeep(this.chartOption)
const data = response.data.result.map(d => {
return {
data: d,
name: d.reputationLevel,
value: parseInt(d.uniqDomains),
name: d.reputation,
value: parseInt(d.count),
unitType: chartParams.unitType
}
})
this.chartOption2.series[0].data = data
// this.myChart2.setOption(this.chartOption2)
chartOption.series[0].data = data
this.myChart2.setOption(chartOption)
}
}
resolve()
})
})
Promise.all([byType, byCredit]).finally(response => {
this.loadEchart(2)
setTimeout(() => {
this.$emit('showLoading', false)
}, 1000)
})
}
}

View File

@@ -11,8 +11,6 @@ import {
getChartColor
} from '@/views/charts/charts/tools'
import chartEchartMixin from './chart-echart-mixin'
import unitConvert from '@/utils/unit-convert'
import {unitTypes} from "@/utils/constants";
export default {
name: 'ChartEchartWithStatistics',
@@ -58,246 +56,23 @@ export default {
}
}
})
if (this.statisticsData.length === 1) {
const markLine = {
silent: true,
symbol: 'none',
label: {
distance: [-50, 0],
formatter (params) {
const arr = unitConvert(
Number(params.value),
chartParams.unitType
).join(' ')
let desc = ''
switch (params.dataIndex) {
case 0: {
desc = 'P50'
break
}
case 1: {
desc = 'P90'
break
}
default:
break
}
return `${arr} (${desc})`
}
},
data: [
{
name: 'P50',
yAxis: this.chartData[0].aggregation.p50
? this.chartData[0].aggregation.p50
: 50
},
{
name: 'P90',
yAxis: this.chartData[0].aggregation.p90
? this.chartData[0].aggregation.p90
: 90
}
]
}
const serieTmp = this.chartOption.series[0]
this.chartOption.series[0] = {
...serieTmp,
markLine: markLine
}
}
const gridTemplate = this.chartOption.grid
// option中默认单位是数字当单位是字节、百分比、时间时额外处理
if (chartParams.unitType === unitTypes.byte) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.byte).join('')
}
this.chartOption.grid = {
...gridTemplate,
left: 75
}
} else if (chartParams.unitType === unitTypes.percent) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.percent).join('')
}
} else if (chartParams.unitType === unitTypes.time) {
this.chartOption.yAxis.axisLabel.formatter = function (value) {
return unitConvert(value, unitTypes.time).join('')
}
}
this.loadEchart(1, true)
this.loadEchart()
},
dispatchLegendSelectAction (name) {
this.myChart.dispatchAction({
type: 'legendSelect',
name: name
})
},
dispatchLegendUnSelectAction (name) {
this.myChart.dispatchAction({
type: 'legendUnSelect',
name: name
})
},
toggleStatisticsLegend (index) {
const legendNum = this.statisticsData.length
const chartParams = this.chartInfo.params
if (legendNum > 1) {
const selectedNum = this.statisticsData.filter(item => { return item.active === true }).length // 点击前高亮legend个数
if (selectedNum === legendNum) { // 全部曲线高亮时
this.statisticsData.forEach((item, indexTmp) => {
if (indexTmp === index) {
item.active = true
this.dispatchLegendSelectAction(item.legend)
} else {
item.active = false
this.dispatchLegendUnSelectAction(item.legend)
}
})
} else if (selectedNum === 1 && this.statisticsData[index].active) { // 多条曲线,且只有一条曲线高亮, 且点击的曲线为高亮曲线时
this.statisticsData.forEach((item) => {
item.active = true
this.dispatchLegendSelectAction(item.legend)
this.statisticsData[index].active = !this.statisticsData[index].active
this.statisticsData.forEach((d, i) => {
if (d.active) {
this.myChart.dispatchAction({
type: 'legendSelect',
name: d.legend
})
} else {
this.statisticsData[index].active = !this.statisticsData[index].active
this.statisticsData.forEach((item, i) => {
if (item.active) {
this.dispatchLegendSelectAction(item.legend)
} else {
this.dispatchLegendUnSelectAction(item.legend)
}
this.myChart.dispatchAction({
type: 'legendUnSelect',
name: d.legend
})
}
const selectedAfterNum = this.statisticsData.filter((item, i) => { return item.active === true }).length // 点击后高亮legend个数
if (selectedAfterNum === 1) { // 点击后只有一条曲线高亮
const chartParams = this.chartInfo.params
// 多条曲线且只有一条曲线高亮时显示P50 P90 分位值,不止一个时隐藏标线
const selectedName = this.statisticsData.filter((item, i) => { return item.active === true })[0].legend
const serieArray = []
this.chartOption.series.forEach((item, i) => {
if (item.name === selectedName) {
const markLine = {
silent: true,
symbol: 'none',
label: {
distance: [-50, 0],
formatter (params) {
const arr = unitConvert(
Number(params.value),
chartParams.unitType
).join(' ')
let desc = ''
switch (params.dataIndex) {
case 0: {
desc = 'P50'
break
}
case 1: {
desc = 'P90'
break
}
default:
break
}
return `${arr} (${desc})`
}
},
data: [
{
name: 'P50',
yAxis: this.chartData[i].aggregation.p50
? this.chartData[i].aggregation.p50
: 50
},
{
name: 'P90',
yAxis: this.chartData[i].aggregation.p90
? this.chartData[i].aggregation.p90
: 90
}
]
}
item.markLine = markLine
}
serieArray.push(item)
})
this.myChart.setOption({
series: serieArray
})
} else { // 不止一条线高亮时隐藏标线
const serieArray = []
this.chartOption.series.forEach((item, i) => {
item.markLine = []
serieArray.push(item)
})
this.myChart.setOption({
series: serieArray
})
}
} else {
this.statisticsData[index].active = !this.statisticsData[index].active
this.statisticsData.forEach((item, i) => {
if (item.active) {
this.dispatchLegendSelectAction(item.legend)
} else {
this.dispatchLegendUnSelectAction(item.legend)
}
})
const selectedAfterNum = this.statisticsData.filter((item, i) => { return item.active === true }).length // 点击后高亮legend个数
if (selectedAfterNum === 1) { // 点击后只有一条曲线高亮
const markLine = {
silent: true,
symbol: 'none',
label: {
distance: [-50, 0],
formatter (params) {
const arr = unitConvert(
Number(params.value),
chartParams.unitType
).join(' ')
let desc = ''
switch (params.dataIndex) {
case 0: {
desc = 'P50'
break
}
case 1: {
desc = 'P90'
break
}
default:
break
}
return `${arr} (${desc})`
}
},
data: [
{
name: 'P50',
yAxis: this.chartData[0].aggregation.p50
? this.chartData[0].aggregation.p50
: 50
},
{
name: 'P90',
yAxis: this.chartData[0].aggregation.p90
? this.chartData[0].aggregation.p90
: 90
}
]
}
this.chartOption.series[0].markLine = markLine
} else {
this.chartOption.series[0].markLine = []
}
}
})
}
},
watch: {

View File

@@ -47,7 +47,7 @@ export default {
},
methods: {
handleQueryParams (queryParams) {
return this.timeFilter = {
this.timeFilter = {
startTime: Number(queryParams.startTime) * 1000,
endTime: Number(queryParams.endTime) * 1000
}
@@ -106,11 +106,7 @@ export default {
dataIndex: index
})
self.selectPieChartName = params.name
if (self.chartInfo.params.riskMapping) {
self.loadPieTableData(riskLevelMapping.find(m => params.name === m.name).value)
} else {
self.loadPieTableData(params.name)
}
self.loadPieTableData(params.name)
} else {
self.myChart.dispatchAction({
type: 'unselect',

View File

@@ -1,8 +1,7 @@
<template>
<panel-chart-list
:time-filter="timeFilter"
:query-params="queryParams"
:data-list="dataList"
:data-list="chartInfo.children"
:panel-lock="true"
:entity="entity"
>
@@ -11,25 +10,15 @@
<script>
import chartMixin from '@/views/charts/charts/chart-mixin'
import _ from 'lodash'
export default {
name: 'ChartGroup',
mixins: [chartMixin],
props: {
timeFilter: Object,
queryParams: Object
timeFilter: Object
},
methods: {
reload () {
this.dataList = _.cloneDeep(this.dataList)
}
},
setup (props) {
const dataList = [...props.chartInfo.children]
return {
dataList
}
mounted () {
console.info(this.chartInfo)
}
}
</script>

View File

@@ -1,286 +1,76 @@
<template>
<div class="cn-chart__map">
<div class="map-back" v-show="showMapBackButton" @click="mapBack">&lt; back</div>
<div class="map-drawing" :id="`chart${chartInfo.id}`"></div>
<div class="map-chart__legends" v-if="chartInfo.params.hasLegend">
<div
class="map-chart__legend"
:class="`${currentLegendIndex === index ? 'map-chart__legend--active' : ''}`"
v-for="(legend, index) in legends"
:key="index"
@click="changeLegend(index)"
>
<div
class="legend__circle-marker"
:style="`background-color:${markerColors[index].background};border: 1px solid ${markerColors[index].border};`"
></div>
<div class="legend__value">{{unitConvert(legend.value, unitTypes.number).join(' ')}}</div>
<div class="legend__name">{{legend.name}}</div>
</div>
</div>
</div>
<div class="map-back" v-show="showMapBackButton" @click="mapBack">&lt; back</div>
<div class="chart-drawing" :id="`chart${chartInfo.id}`"></div>
</template>
<script>
import * as am4Core from '@amcharts/amcharts4/core'
import * as am4Maps from '@amcharts/amcharts4/maps'
import { getGeoData, replaceUrlPlaceholder } from '@/utils/tools'
import { storageKey, dnsServerRole, unitTypes } from '@/utils/constants'
import { storageKey, dnsServerRole } from '@/utils/constants'
import { isMapBlock, isMapPoint } from './tools'
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
import { HeatLegend } from '@/components/amcharts/heatLegend'
import { getData } from '@/utils/api'
import chartMixin from './chart-mixin'
import _ from 'lodash'
import { shallowRef } from 'vue'
export default {
name: 'ChartMap',
data () {
return {
unitTypes,
myChart: null,
mapPictureUrl: '/Tiles/{z}/{x}/{y}.png',
showMapBackButton: false,
polygonSeries: null, // 世界地图series
countrySeries: null, // 下钻国家series
worldImageSeries: null, // 世界地图圆点series
countryImageSeries: null, // 下钻国家圆点series
currentLegendIndex: 0,
legends: [
{
name: this.$t('dns.rootDomainServers'),
type: dnsServerRole.RTDNS,
value: 0
},
{
name: this.$t('dns.topLevelDomainServers'),
type: dnsServerRole.TLDNS,
value: 0
},
{
name: this.$t('dns.authoritativeDomainServers'),
type: dnsServerRole.ADNS,
value: 0
},
{
name: this.$t('dns.publicRecursiveDomainServers'),
type: dnsServerRole.OPRDNS,
value: 0
},
{
name: this.$t('dns.selfBuiltDomainServers'),
type: dnsServerRole.SBDNS,
value: 0
}
],
markerColors: [
{
background: '#C0DEFE',
border: '#68AFFC'
},
{
background: '#DBCFFA',
border: '#AA8CF2'
},
{
background: '#A0E8E0',
border: '#1CC9B5'
},
{
background: '#FFE1B5',
border: '#FFB84E'
},
{
background: '#FDC6C6',
border: '#FA7777'
},
{
background: '#ECC6F7',
border: '#B620E0'
}
],
keyMapping: [
{
key: 'sessions',
label: this.$t('overall.sessions'),
unitType: unitTypes.number
},
{
key: 'establishLatency',
label: this.$t('networkAppPerformance.tripTime'),
unitType: unitTypes.time
},
{
key: 'httpResponseLatency',
label: this.$t('networkAppPerformance.httpResponse'),
unitType: unitTypes.time
},
{
key: 'sslConLatency',
label: this.$t('networkAppPerformance.sslResponse'),
unitType: unitTypes.time
},
{
key: 'sequenceGapLossPercent',
label: this.$t('networkAppPerformance.packetLossRate'),
unitType: unitTypes.percent
},
{
key: 'pktRetransPercent',
label: this.$t('networkAppPerformance.retransmissionRate'),
unitType: unitTypes.percent
},
{
key: 'packets',
label: this.$t('overall.packets'),
unitType: unitTypes.number
},
{
key: 'sentBytes',
label: this.$t('overall.sent'),
unitType: unitTypes.byte
},
{
key: 'receivedBytes',
label: this.$t('overall.received'),
unitType: unitTypes.byte
},
{
key: 'count',
label: this.$t('overall.count'),
unitType: unitTypes.number
}
]
countrySeries: null // 下钻国家series
}
},
mixins: [chartMixin],
methods: {
unitConvert,
initMap (id) {
const chart = am4Core.create(id, am4Maps.MapChart)
chart.geodata = getGeoData(storageKey.iso36112WorldLow)
chart.projection = new am4Maps.projections.Miller()
this.myChart = shallowRef(chart)
this.polygonSeries = shallowRef(this.polygonSeriesFactory())
if (this.isMapPoint) {
this.worldImageSeries = shallowRef(this.imageSeriesFactory())
}
this.loadAm4ChartMap(this.polygonSeries, this.worldImageSeries)
// 地图点击事件
if (this.isMapBlock) {
this.polygonSeries.mapPolygons.template.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
const geoData = getGeoData(countryId)
if (geoData) {
this.countrySeries = shallowRef(this.polygonSeriesFactory())
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, null, country, chartData)
}
}
})
} else if (this.isMapPoint) {
this.worldImageSeries.mapImages.template.events.on('hit', async ev => {
const countryId = ev.target.dataItem.dataContext.id
ev.target.isHover = false
if (countryId) {
const targetMapObject = this.polygonSeries.getPolygonById(countryId)
targetMapObject.series.chart.zoomToMapObject(targetMapObject)
const geoData = getGeoData(countryId)
if (geoData) {
this.countrySeries = shallowRef(this.polygonSeriesFactory())
this.countrySeries.geodata = geoData
this.countryImageSeries = shallowRef(this.imageSeriesFactory())
this.polygonSeries.hide()
this.worldImageSeries.hide()
const country = ev.target.dataItem.dataContext.name
const queryParams = { ...this.queryParams, ipLocationCountry: country }
const chartData = await getData(replaceUrlPlaceholder(this.chartInfo.params.url, queryParams))
this.loadAm4ChartMap(this.countrySeries, this.countryImageSeries, country, chartData)
}
}
})
}
// dns地图legend上的数据
if (!_.isEmpty(this.chartInfo.params.legendUrl)) {
setTimeout(() => {
this.chartInfo.params.legendUrl.forEach((url, i) => {
getData(url).then(data => {
this.legends[i].value = data
})
})
})
}
},
polygonSeriesFactory () {
const polygonSeries = this.myChart.series.push(new am4Maps.MapPolygonSeries())
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('#41495D')
polygonSeries.tooltip.background.filters.clear()
polygonSeries.tooltip.background.stroke = '#41495D'
polygonSeries.tooltip.background.fill = am4Core.color('#FFFFFF')
this.polygonSeries = polygonSeries
const polygonTemplate = polygonSeries.mapPolygons.template
polygonTemplate.tooltipHTML = this.generatePolygonTooltipHTML()
polygonTemplate.tooltipHTML = this.generateTooltipHTML()
polygonTemplate.nonScalingStroke = true
polygonTemplate.strokeWidth = 0.5
polygonTemplate.fill = am4Core.color('rgba(176,196,222,.5)')
return polygonSeries
},
imageSeriesFactory (dataField) {
const vm = this
const imageSeries = this.myChart.series.push(new am4Maps.MapImageSeries())
imageSeries.dataFields.value = dataField || 'count'
const imageTemplate = imageSeries.mapImages.template
imageTemplate.nonScaling = true
imageTemplate.adapter.add('latitude', function (latitude, target) {
const polygon = vm.polygonSeries.getPolygonById(target.dataItem.dataContext.id)
if (polygon) {
return polygon.visualLatitude
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)
}
}
return latitude
})
imageTemplate.adapter.add('longitude', function (longitude, target) {
const polygon = vm.polygonSeries.getPolygonById(target.dataItem.dataContext.id)
if (polygon) {
return polygon.visualLongitude
}
return longitude
})
const circle = imageTemplate.createChild(am4Core.Circle)
circle.propertyFields.fill = 'color'
circle.propertyFields.stroke = 'border'
circle.strokeWidth = 1
circle.tooltipHTML = this.generatePolygonTooltipHTML()
imageSeries.tooltip.getFillFromObject = false
imageSeries.tooltip.background.fill = am4Core.color('#41495D')
imageSeries.tooltip.background.filters.clear()
imageSeries.tooltip.background.stroke = '#41495D'
imageSeries.heatRules.push({
target: circle,
property: 'radius',
min: 6,
max: 25,
dataField: 'value'
})
return imageSeries
},
loadAm4ChartMap (polygonSeries, imageSeries, country, chartData) {
loadAm4ChartMap (polygonSeries, country, chartData) {
// chartData不为空是下钻
if (chartData) {
this.$emit('showLoading', true)
@@ -288,7 +78,6 @@ export default {
try {
// 清除数据
polygonSeries.data.splice(0)
// 清除legend
this.myChart.children.each((s, i) => {
if (s && s.className !== 'Container') {
@@ -300,14 +89,27 @@ export default {
const chartParams = this.chartInfo.params
const data = chartData || this.chartData
if (data && this.isMapBlock) {
const seriesData = data.map(r => {
return {
...this.convertMapData(r),
id: r.serverId,
serverCountry: r.serverCountry,
value: r[chartParams.valueColumn]
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(' ') : ''
}))
!this.$_.isEmpty(seriesData) && (polygonSeries.data = [...seriesData])
// 数据全为0的情况legend只显示1个颜色
const sorted = seriesData.sort((a, b) => b.value - a.value)
@@ -342,15 +144,55 @@ export default {
return ''
})
} else if (data && this.isMapPoint) {
imageSeries.data = data.map(r => ({
...this.convertMapData(r),
id: r.ipLocationId,
dnsServerRole: r.dnsServerRole,
name: r.ipLocationCity || r.ipLocationProvince || r.ipLocationCountry,
desc: this.$t(this.dnsTypeI18n(r.dnsServerRole)),
color: this.circleColor[r.dnsServerRole.toUpperCase()].background,
border: this.circleColor[r.dnsServerRole.toUpperCase()].border
}))
const seriesData = []
data.forEach(d => {
seriesData.push({
id: d.ipLocationId,
count: d.count,
dnsServerRole: d.dnsServerRole,
location: d.ipLocationCity || d.ipLocationProvince || d.ipLocationCountry,
desc: this.$t(this.dnsTypeI18n(d.dnsServerRole)),
color: this.circleColor[d.dnsServerRole].background,
border: this.circleColor[d.dnsServerRole].border
})
})
console.info(seriesData)
const imageSeries = this.myChart.series.push(new am4Maps.MapImageSeries())
imageSeries.data = seriesData
imageSeries.dataFields.value = 'count'
const imageTemplate = imageSeries.mapImages.template
imageTemplate.nonScaling = true
imageTemplate.adapter.add('latitude', function (latitude, target) {
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
if (polygon) {
return polygon.visualLatitude
}
return latitude
})
imageTemplate.adapter.add('longitude', function (longitude, target) {
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
if (polygon) {
return polygon.visualLongitude
}
return longitude
})
const circle = imageTemplate.createChild(am4Core.Circle)
circle.propertyFields.fill = 'color'
circle.propertyFields.stroke = 'border'
circle.strokeWidth = 1
circle.tooltipText = '[bold]{location}[/]\n{desc}: {count}'
imageSeries.heatRules.push({
target: circle,
property: 'radius',
min: 6,
max: 25,
dataField: 'value'
})
}
} catch (e) {
console.error(e)
@@ -364,25 +206,15 @@ export default {
},
mapBack () {
this.countrySeries.hide()
if (this.isMapPoint) {
this.countryImageSeries.hide()
}
this.$nextTick(() => {
this.showMapBackButton = false
this.polygonSeries.show()
if (this.isMapPoint) {
this.worldImageSeries.show()
}
this.myChart.goHome()
})
},
changeLegend (index) {
this.currentLegendIndex = index
this.$emit('getChartData', null, { dnsServerRole: this.legends[index].type })
},
dnsTypeI18n (role) {
let i18n = ''
switch (role.toUpperCase()) {
switch (role) {
case dnsServerRole.RTDNS: {
i18n = 'dns.rootDomainServers'
break
@@ -411,23 +243,16 @@ export default {
}
return i18n
},
generatePolygonTooltipHTML () {
let html = `
generateTooltipHTML () {
return `
<div class="map-tooltip" style="padding-bottom: 10px;">
<div class="map-tooltip__title">{name}</div>
<div class="map-tooltip__content">`
this.keyMapping.forEach(mapping => {
html += `
<div class="content-row" style="display: none; display: {${mapping.key}Display}">
<span class="row__label">{${mapping.key}Label}:</span>
<span class="row__value">{${mapping.key}ShowValue}</span>
</div>
`
})
html += `
<div class="map-tooltip__content">
<span>{labelText}</span>
<span>{showValue}</span>
</div>
</div>`
return html
</div>
`
},
getDataKey (r) {
let key = ''
@@ -452,22 +277,6 @@ export default {
labelText = this.$t('overall.sessions')
}
return { key, labelText }
},
convertMapData (data) {
const converted = {}
this.keyMapping.forEach(mapping => {
if (data[mapping.key] || data[mapping.key] === 0) {
converted[mapping.key] = Number(data[mapping.key])
converted[`${mapping.key}Label`] = mapping.label
converted[`${mapping.key}ShowValue`] = valueToRangeValue(data[mapping.key], mapping.unitType).join(' ')
converted[`${mapping.key}Display`] = 'block'
} else {
converted[mapping.key] = ''
converted[`${mapping.key}Label`] = ''
converted[`${mapping.key}Display`] = 'none'
}
})
return converted
}
},
watch: {
@@ -505,7 +314,6 @@ export default {
border: '#BF49DF'
}
return {
myChart: shallowRef(null),
circleColor,
isMapBlock: isMapBlock(props.chartInfo.type),
isMapPoint: isMapPoint(props.chartInfo.type)

View File

@@ -1,29 +1,28 @@
<template>
<div class="cn-chart__one-situation-statistics">
<div class="one-situation-statistics__box">
<div class="box__progress">
<div class="chart-one-situation-statistics">
<div class="situation-statistics-main">
<div class="situation-statistics-main-left">
<el-progress
type="circle"
:color="chartInfo.params.color"
width="76"
:percentage="Math.floor(($_.get(chartData, 'percent', '-') * 100) * 100) / 100"
:percentage="chartData ? chartData.percent : 0"
/>
</div>
<div class="box__count">
<div> {{ $_.get(chartData, 'count', '-') }} </div>
<div>{{ $t(`dns.numberOfNodes`) }}</div>
<div class="situation-statistics-main-right">
<div>{{ chartData ? (chartData.count || '-') : '-' }}</div>
<div class="situation-statistic-main-right-font">{{ $t(`dns.numberOfNodes`) }}</div>
</div>
</div>
</div>
</template>
<script>
import _ from 'lodash'
export default {
name: 'ChartOneSituationStatistics',
props: {
chartInfo: Object,
chartData: [Array, Object]
}
chartData: [Array, Object],
},
}
</script>

View File

@@ -1,147 +1,43 @@
<template>
<div
class="cn-chart__single-value chart-header-position"
:class="singleValueClass(type)"
:style="{ backgroundColor: color }"
>
<div class="single-value-icon__box" v-if="!isCommon3SingleValue(type) && !isDetectionsProtocol(type) ">
<div
class="single-value__icon"
:style="`background-color: ${
chartInfo.params.iconBackgroundColor || ''
}`"
>
<i
:class="icon"
:style="`color: ${chartInfo.params.iconColor || ''}`"
></i>
</div>
<div class="cn-chart__single-value chart-header-position" :class="singleValueClass(type)" :style="{backgroundColor:color}">
<div class="single-value-icon__box" v-if="type !== 54">
<div class="single-value__icon" :style="`background-color: ${chartInfo.params.iconBackgroundColor || ''}`"><i :class="icon" :style="`color: ${chartInfo.params.iconColor || ''}`"></i></div>
</div>
<div class="single-value__content" v-if="isCommonSingleValue(type)">
<div class="single-value__content" v-if="type === 51">
<div class="content__data">
<span>{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span>
<span class="single-value__unit">{{ handleSingleValue[1] }}</span>
<span>{{handleSingleValue[0] || handleSingleValue[0] === 0 ? handleSingleValue[0] : '-'}}</span>
<span class="single-value__unit">{{handleSingleValue[1]}}</span>
</div>
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
</div>
<div class="single-value__content" v-if="isSingleValueWithPercentileRight(type)">
<div class="data__title-in-one">
<div class="content__data">
<span style="white-space: nowrap;">{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span><span class="single-value__unit">{{handleSingleValue[1] }}</span>
</div>
<div class="content__title title-background-color">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
</div>
</div>
<div class="content__percentile">
<div class="circle__content">
<div class="circle circle-p50"></div>
<div><span class="percentile__title-color">P50: </span><span>
{{(handleSingleValue[2] || handleSingleValue[2] === 0)
?handleSingleValue[2]
:'-'}}
</span></div>
</div>
<div class="circle__content">
<div class="circle circle-p90"></div>
<div><span class="percentile__title-color">P90: </span><span>
{{(handleSingleValue[3]|| handleSingleValue[3] === 0)
?handleSingleValue[3]
:'-'}}
</span></div>
</div>
</div>
</div>
<div class="single-value__content" v-if="isSingleValueWithPercentileLeft(type)">
<div class="single-value__content single-value__content--with-chart" v-if="type === 52">
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
</div>
<div class="content__data">
<span>{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span>
<span class="single-value__unit">{{ handleSingleValue[1] }}</span>
</div>
<div class="content__percentile">
<div class="circle__content">
<div class="circle circle-p50"></div>
<div><span class="percentile__title-color">P50: </span><span>
{{(handleSingleValue[2]|| handleSingleValue[2] === 0)
?handleSingleValue[2]
:'-'}}
</span></div>
</div>
<div class="circle__content">
<div class="circle circle-p90"></div>
<div><span class="percentile__title-color">P90: </span><span>
{{(handleSingleValue[3]|| handleSingleValue[3] === 0)
?handleSingleValue[3]
:'-'}}
</span></div>
</div>
</div>
</div>
<div class="single-value__content single-value__content--with-chart" v-if="isSingleValueWithEcharts(type)">
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
<span
v-if="chartInfo.params && chartInfo.params.as"
class="ip-detail-as"
>
as&nbsp;<span style="text-transform: capitalize">{{
chartInfo.params.as
}}</span>
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
<span v-if="chartInfo.params && chartInfo.params.as" class="ip-detail-as">
as&nbsp;<span style="text-transform: capitalize">{{chartInfo.params.as}}</span>
</span>
</div>
<div class="content__data">
<span>{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span>
<span class="single-value__unit">{{ handleSingleValue[1] }}</span>
<span>{{handleSingleValue[0] || handleSingleValue[0] === 0 ? handleSingleValue[0] : '-'}}</span>
<span class="single-value__unit">{{handleSingleValue[1]}}</span>
</div>
<div class="content__chart">
<div class="chart-drawing" :id="`chart${chartInfo.id}`"></div>
</div>
</div>
<div class="single-value__content" v-if="isCommon2SingleValue(type)">
<div class="single-value__content" v-if="type === 53">
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
<div class="content__data">
<span>{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span>
<span class="single-value__unit">{{ handleSingleValue[1] }}</span>
<span>{{handleSingleValue[0] || handleSingleValue[0] === 0 ? handleSingleValue[0] : '-'}}</span>
<span class="single-value__unit">{{handleSingleValue[1]}}</span>
</div>
</div>
<div class="single-value__content" v-if="isCommon3SingleValue(type)">
<div class="single-value-icon__box">
<div class="single-value__content" v-if="type === 54" >
<div class="single-value-icon__box" >
<div class="single-value__icon">
<!-- 使用图标-->
<svg class="cn-icon-svg" aria-hidden="true">
@@ -151,98 +47,27 @@
</div>
<div class="single-value__data">
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
</div>
<div class="content__data">
<span>{{
handleSingleValue[0] || handleSingleValue[0] === 0
? handleSingleValue[0]
: '-'
}}</span>
<span class="single-value__unit">{{ handleSingleValue[1] }}</span>
</div>
</div>
</div>
<div class="single-value__content" v-if="isSingleValueWithPercent(type)">
<div>
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{
chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name
}}</span>
</div>
<div class="content__data">
<div class="content__data__doh">
<div class="content__data__doh__count">
{{ $_.get(chartData, 'count', '-') }}
</div>
<div class="content__data__doh__percent">
{{$t('protocol.proportion')}}<span>{{ $_.get(chartData, 'percent', '-') }}%</span>
</div>
<span>{{handleSingleValue[0] || handleSingleValue[0] === 0 ? handleSingleValue[0] : '-'}}</span>
<span class="single-value__unit">{{handleSingleValue[1]}}</span>
</div>
</div>
</div>
</div>
<div class="single-value__content" v-if="isDetectionsProtocol(type)">
<div class="single-value__data">
<div class="content__title">
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">
{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name }}
</span>
</div>
</div>
<div class="content__data">
<div class="content__data-protocol">
<div class="content__data-protocol-all">
<div class="content__data-protocol-icon" :style="{backgroundColor: chartInfo.params.iconBackgroundColor[0]}">
<i :class="chartInfo.params.icon[0]" :style="{color: chartInfo.params.iconColor[0]}"></i>
</div>
</div>
<div class="content__data-protocol-value">
<div class="content__data-protocol-value-title">{{$t('protocol.requestVolume')}}</div>
<div class="content__data-protocol-value-num">{{unitConvert($_.get(chartData, 'bytes'), chartInfo.params.unitType).join('')}}</div>
</div>
<div class="content__data-protocol-percent"><span>{{$t('protocol.proportion')}}</span>&nbsp;<span>{{unitConvert($_.get(chartData, 'bytesPercent'), unitTypes.percent).join('')}}</span></div>
</div>
<div class="content__data-protocol">
<div class="content__data-protocol-all">
<div class="content__data-protocol-icon" :style="{backgroundColor: chartInfo.params.iconBackgroundColor[1]}">
<i :class="chartInfo.params.icon[1]" :style="{color: chartInfo.params.iconColor[1]}"></i>
</div>
</div>
<div class="content__data-protocol-value">
<div class="content__data-protocol-value-title">{{$t('protocol.totalFlow')}}</div>
<div class="content__data-protocol-value-num">{{unitConvert($_.get(chartData, 'count'), chartInfo.params.unitType).join('')}}</div>
</div>
<div class="content__data-protocol-percent"><span>{{$t('protocol.proportion')}}</span>&nbsp;<span>{{unitConvert($_.get(chartData, 'countPercent'), unitTypes.percent).join('')}}</span></div>
</div>
</div>
</div>
</div>
</template>
<script>
import unitConvert from '@/utils/unit-convert'
import {
unitTypes
} from '@/utils/constants'
import { get } from '@/utils/http'
import { unitTypes } from '@/utils/constants'
import { replaceUrlPlaceholder } from '@/utils/tools'
import * as echarts from 'echarts'
import {
getOption,
getChartColor,
isCommonSingleValue,
isSingleValueWithEcharts,
isSingleValueWithPercentileLeft,
isSingleValueWithPercentileRight,
isCommon2SingleValue,
isSingleValueWithPercent,
isCommon3SingleValue,
isDetectionsProtocol
} from '@/views/charts/charts/tools'
import { getOption, getChartColor } from '@/views/charts/charts/tools'
export default {
name: 'chartSingleValue',
props: {
@@ -252,8 +77,6 @@ export default {
},
data () {
return {
unitConvert,
unitTypes,
icon: '',
color: '',
type: 0,
@@ -274,113 +97,76 @@ export default {
},
computed: {
handleSingleValue () {
let value = null
if (this.isSingleValueWithPercentileLeft(this.chartInfo.type) || this.isSingleValueWithPercentileRight(this.chartInfo.type)) {
value = (this.chartData && (this.chartData.value || this.chartData.value === 0)) ? this.chartData.value : ''
} else {
value = (this.chartData || this.chartData === 0)
? this.chartData
: ''
}
const value = this.$_.isEmpty(this.chartData) || this.$_.get(this, 'chartData') ? this.chartData : ''
const unitType = this.chartInfo.params.unitType
const result = unitConvert(value, unitType)
let p50 = ''
let p90 = ''
if (this.isSingleValueWithPercentileLeft(this.chartInfo.type) || this.isSingleValueWithPercentileRight(this.chartInfo.type)) {
p50 = this.chartData ? unitConvert(this.chartData.p50, unitType) : ''
p90 = this.chartData ? unitConvert(this.chartData.p90, unitType) : ''
}
switch (unitType) {
case unitTypes.percent: {
result[0] = result[0] < 0.01 ? '< 0.01' : result[0]
result[2] = (p50 && (p50[0] || Number(p50[0]) === 0)) ? p50[0] + p50[1] : ''
result[3] = (p90 && (p90[0] || Number(p90[0]) === 0)) ? p90[0] + p90[1] : ''
break
}
case unitTypes.time: {
result[0] = result[0] < 1 ? '< 1' : result[0]
result[2] = (p50 && (p50[0] || Number(p50[0]) === 0)) ? p50[0] + p50[1] : ''
result[3] = (p90 && (p90[0] || Number(p90[0]) === 0)) ? p90[0] + p90[1] : ''
break
}
default:
break
default: break
}
return result
},
singleValueClass () {
return function (type) {
let c
if (this.isCommonSingleValue(type)) {
c = 'cn-chart__single-value--icon-left'
} else if (this.isSingleValueWithEcharts(type)) {
c = 'cn-chart__single-value--chart'
} else if (this.isSingleValueWithPercentileLeft(type)) {
c = 'cn-chart__single-value--percentile-left'
} else if (this.isSingleValueWithPercentileRight(type)) {
c = 'cn-chart__single-value--percentile-right'
} else if (this.isCommon2SingleValue(type)) {
c = 'cn-chart__single-value--icon-right'
} else if (this.isCommon3SingleValue(type)) {
c = 'cn-chart__single-value--icon-right--color'
} else if (this.isSingleValueWithPercent(type)) {
c = 'cn-chart__single-value--icon-doh'
} else if (this.isDetectionsProtocol(type)) {
c = 'cn-chart__single-value--protocol'
switch (type) {
case 51: {
c = 'cn-chart__single-value--icon-left'
break
}
case 55:
case 52: {
c = 'cn-chart__single-value--chart'
break
}
case 53: {
c = 'cn-chart__single-value--icon-right'
break
}
case 54: {
c = 'cn-chart__single-value--icon-right--color'
break
}
default: break
}
return c
}
}
},
methods: {
isCommonSingleValue,
isSingleValueWithEcharts,
isSingleValueWithPercentileLeft,
isSingleValueWithPercentileRight,
isCommon2SingleValue,
isCommon3SingleValue,
isSingleValueWithPercent,
isDetectionsProtocol,
chartSingleValueTotal () {
const chartParams = this.$_.get(this.chartInfo, 'params') || {}
if (isSingleValueWithEcharts(this.type)) {
if (this.type === 52) {
const dom = document.getElementById(`chart${this.chartInfo.id}`)
const myChart = echarts.init(dom)
this.chartOption = this.$_.cloneDeep(getOption(this.type))
get(replaceUrlPlaceholder(chartParams.urlChart, this.queryParams)).then(
(response) => {
const seriesTemplate = this.chartOption.series[0]
const result = response.data.result
this.chartOption.series = result.map((r, i) => {
return {
...seriesTemplate,
name: r.legend,
data: r.values.map((v) => [
Number(v[0]) * 1000,
Number(v[1]),
chartParams.unitType
]),
lineStyle: {
color: getChartColor[i]
}
get(replaceUrlPlaceholder(chartParams.urlChart, this.queryParams)).then(response => {
const seriesTemplate = this.chartOption.series[0]
const result = response.data.result
this.chartOption.series = result.map((r, i) => {
return {
...seriesTemplate,
name: r.legend,
data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), chartParams.unitType]),
lineStyle: {
color: getChartColor[i]
}
})
myChart.setOption(this.chartOption)
}
)
}
})
myChart.setOption(this.chartOption)
})
}
}
},
mounted () {
this.$nextTick(
() =>
(this.timer = setTimeout(() => {
this.chartSingleValueTotal()
}, 200))
)
this.$nextTick(() => this.timer = setTimeout(() => { this.chartSingleValueTotal() }, 200))
},
deactivated () {
clearTimeout(this.timer)

View File

@@ -12,7 +12,7 @@
v-for="(c, i) in table.tableColumns.common"
show-overflow-tooltip
:key="i"
:label="$t(chartTableColumnMapping[c] || c)"
:label="$t(chartTableColumnMapping[c])"
:prop="c"
>
</el-table-column>
@@ -20,10 +20,10 @@
v-for="(c, i) in table.tableColumns.order"
show-overflow-tooltip
:key="i"
:label="$t(chartTableColumnMapping[c] || c)"
:label="$t(chartTableColumnMapping[c])"
:prop="c"
>
<template #header>{{$t(chartTableColumnMapping[c] || c)}}</template>
<template #header>{{$t(chartTableColumnMapping[c])}}</template>
<template #default="{ row }">
<span v-if="c === 'bytes'">
{{unitConvert(row[c], unitTypes.byte).join(' ')}}
@@ -31,12 +31,6 @@
<span v-else-if="c === 'packets' || c === 'sessions'">
{{unitConvert(row[c], unitTypes.number).join(' ')}}
</span>
<span v-else-if="c === 'responseFailRate'">
{{unitConvert(row[c], unitTypes.percent).join(' ')}}
</span>
<span v-else-if="c === 'dnsLatency'">
{{unitConvert(row[c], unitTypes.time).join(' ')}}
</span>
<span v-else>
{{row[c]}}
</span>

View File

@@ -19,16 +19,17 @@ export default {
name: 'ChartTablePagination',
props: {
total: Number,
pageSizeForAlarm: Number
pageSizeForAlarm:Number
},
data () {
return {
pageSize: this.pageSizeForAlarm ? this.pageSizeForAlarm : chartTableDefaultPageSize,
pageSize: this.pageSizeForAlarm?this.pageSizeForAlarm:chartTableDefaultPageSize,
pageNo: 1
}
},
computed: {
totalPage () {
console.log(this.total,this.pageSize);
const remainder = this.total % this.pageSize
if (remainder) {
return parseInt(this.total / this.pageSize) + 1
@@ -37,14 +38,6 @@ export default {
}
}
},
watch: {
pageSizeForAlarm: {
deep: true
},
total: {
deep: true
}
},
methods: {
current (val) {
this.$emit('pageJump', val)

View File

@@ -6,7 +6,7 @@
:ref="`chart-${chartInfo.id}`"
>
<el-tab-pane
v-for="tab in dataList"
v-for="tab in chartInfo.children"
:label="tab.i18n ? $t(tab.i18n) : tab.name" :name="`${tab.id}`"
:key="tab.id"
:ref="`chart-${chartInfo.id}`"
@@ -29,6 +29,14 @@ import chartMixin from '@/views/charts/charts/chart-mixin'
export default {
name: 'ChartTabs',
computed: {
timeFilter () {
return {
startTime: this.queryParams.startTime,
endTime: this.queryParams.endTime
}
}
},
mixins: [chartMixin],
methods: {
showFullscreen () {
@@ -36,9 +44,6 @@ export default {
},
changeTab (tab) {
this.activeTab = tab.paneName
},
reload () {
this.dataList = _.cloneDeep(this.dataList)
}
},
setup (props) {
@@ -46,10 +51,8 @@ export default {
if (!_.isEmpty(props.chartInfo.children)) {
activeTab = `${props.chartInfo.children[0].id}`
}
const dataList = [...props.chartInfo.children]
return {
activeTab,
dataList
activeTab
}
}
}

View File

@@ -1,22 +1,22 @@
<template>
<div class="cn-chart__two-situation-statistics">
<div class="chart-two-situation-statistics">
<div
class="two-situation-statistics__box"
v-for="(value, key,index) in result ? result : []"
class="situation-statistics-main"
v-for="(value, index) in chartData"
:key="index"
>
<div class="box__body">
<div class="body__progress">
<div class="situation-statistics-top">
<div class="situation-statistics-main-left">
<el-progress
type="circle"
:color="chartInfo.params.color[index]"
:color="chartInfo.params.color[0]"
width="76"
:percentage="value.percent ? value.percent : 0"
:percentage="value.percent"
/>
</div>
<div class="body__count">
<div>{{ value.count ? value.count : '-' }}</div>
<div>{{ $t(`dns.numberOfNodesSupporting${key}Protocol`) }}</div>
<div class="situation-statistics-main-right">
<div>{{ value.count }}</div>
<div>{{ $t(`dns.numberOfNodesSupporting${index}Protocol`)}}</div>
</div>
</div>
</div>
@@ -28,21 +28,8 @@ export default {
name: 'ChartTwoSituationStatistics',
props: {
chartInfo: Object,
chartData: [Array, Object]
chartData: [Array, Object],
},
data () {
return {
result: {
doh: {
count: 111,
percent: 0.85
},
dot: {
count: 111,
percent: 80.85
}
}
}
}
}
</script>

View File

@@ -1,21 +1,12 @@
<template>
<div class="cn-chart__ip-basic">
<div class="cn-chart__ip-basic-info">
<el-descriptions :column="1">
<el-descriptions-item label="ASN:">{{(chartData && chartData.asn) || '-'}}</el-descriptions-item>
<el-descriptions-item label="AS Org:">{{(chartData && chartData.asOrganization) || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('entities.asSubnet') + ':'">{{(chartData && chartData.asSubnet) || '-'}}</el-descriptions-item>
<el-descriptions-item label="ISP:">{{(chartData && chartData.isp) || '-'}}</el-descriptions-item>
<el-descriptions-item label="DNS PTR:">{{(chartData && chartData.dnsPtr) || '-'}}</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" v-if="detectionsData.dnsServerRole">
<el-descriptions-item :label="$t('overall.dnsServerInfo.role') + ':'">{{$_.get(detectionsData, 'dnsServerRole') || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.dnsServerInfo.mechanism') + ':'">{{$_.get(detectionsData, 'dnsServerOrg') || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.dnsServerInfo.software') + ':'">{{$_.get(detectionsData, 'dnsServerSoftware') || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.dnsServerInfo.system') + ':'">{{$_.get(detectionsData, 'dnsServerOs') || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('overall.dnsServerInfo.protocol') + ':'">{{detectionIpSupporting(detectionsData)}}</el-descriptions-item>
</el-descriptions>
</div>
<el-descriptions :column="1">
<el-descriptions-item label="ASN:">{{(chartData && chartData.asn) || '-'}}</el-descriptions-item>
<el-descriptions-item label="AS Org:">{{(chartData && chartData.asOrganization) || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('entities.asSubnet') + ':'">{{(chartData && chartData.asSubnet) || '-'}}</el-descriptions-item>
<el-descriptions-item label="ISP:">{{(chartData && chartData.isp) || '-'}}</el-descriptions-item>
<el-descriptions-item label="DNS PTR:">{{(chartData && chartData.dnsPtr) || '-'}}</el-descriptions-item>
</el-descriptions>
<div class="chart-location">
<el-descriptions :column="1">
<el-descriptions-item :label="$t('overall.location') + ':'">{{location}}</el-descriptions-item>
@@ -31,22 +22,18 @@ import * as L from 'leaflet'
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import 'leaflet/dist/leaflet.css'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
export default {
name: 'IpBasicInfo',
mixins: [chartMixin],
data () {
return {
myChart: null,
mapPictureUrl: '/Tiles/{z}/{x}/{y}.png',
entityDetectionsIpUrl: api.entityDetectionsIp,
detectionsData: {}
mapPictureUrl: '/Tiles/{z}/{x}/{y}.png'
}
},
computed: {
location () {
this.$_.get()
let location = ''
if (this.chartInfo) {
if (this.chartInfo.country) {
@@ -70,25 +57,6 @@ export default {
}
}
return location
},
detectionIpSupporting () {
return function (detectionsData) {
let result = ''
if (detectionsData.dnssecSupport) {
result += 'DNSSec/'
}
if (detectionsData.dohSupport) {
result += 'DoH/'
}
if (detectionsData.dotSupport) {
result += 'Dot/'
}
result = result.substr(0, result.length - 1)
if (!result) {
result = '-'
}
return result
}
}
},
methods: {
@@ -133,20 +101,8 @@ export default {
})
L.marker([this.chartData.latitude, this.chartData.longitude], { icon: myIcon }).addTo(this.myChart)
}
},
queryDetection () {
get(this.entityDetectionsIpUrl, this.queryParams).then(response => {
if (response.code === 200) {
this.detectionsData = response.data.result
}
})
}
},
mounted () {
this.$nextTick(() => {
this.queryDetection()
})
},
watch: {
chartData: {
deep: true,

View File

@@ -5,17 +5,13 @@
<div class="table__below-title">Name</div>
<div class="table__below-statistics">Avg</div>
<div class="table__below-statistics">Max</div>
<div class="table__below-statistics">P50</div>
<div class="table__below-statistics">P90</div>
</div>
<div class="chart__table-below">
<div v-for="(item, index) in data" :key="index" class="table-below-box" :class="{'table-below-box--inactivated': !item.active}" @click="toggleLegend(index)">
<div class="table__below-color"><div :style="{backgroundColor: getChartColor(index)}"></div></div>
<div class="table__below-title" :title="item.legend">{{item.legend}}</div>
<div class="table__below-statistics" :title="valueToRangeValue(item.aggregation.avg, chartInfo.params.unitType).join('')">{{valueToRangeValue(item.aggregation.avg, chartInfo.params.unitType).join('')}}</div>
<div class="table__below-statistics" :title="valueToRangeValue(item.aggregation.max, chartInfo.params.unitType).join('')">{{valueToRangeValue(item.aggregation.max, chartInfo.params.unitType).join('')}}</div>
<div class="table__below-statistics" :title="valueToRangeValue(item.aggregation.p50, chartInfo.params.unitType).join('')">{{valueToRangeValue(item.aggregation.p50, chartInfo.params.unitType).join('')}}</div>
<div class="table__below-statistics" :title="valueToRangeValue(item.aggregation.p90, chartInfo.params.unitType).join('')">{{valueToRangeValue(item.aggregation.p90, chartInfo.params.unitType).join('')}}</div>
<div class="table__below-statistics" :title="item.aggregation.avg">{{valueToRangeValue(item.aggregation.avg, chartInfo.params.unitType).join(' ')}}</div>
<div class="table__below-statistics" :title="item.aggregation.max">{{valueToRangeValue(item.aggregation.max, chartInfo.params.unitType).join(' ')}}</div>
</div>
</div>
</div>

View File

@@ -31,8 +31,7 @@ export default {
},
data () {
return {
chartOption: null,
chartOption2: null
chartOption: null
}
},
methods: {
@@ -42,7 +41,6 @@ export default {
const dom2 = document.getElementById(id + '-1')
!this.myChart && (this.myChart = echarts.init(dom))
!this.myChart2 && (this.myChart2 = echarts.init(dom2))
this.chartOption2 = this.$_.cloneDeep(getOption(this.chartInfo.type))
} else {
const dom = document.getElementById(id)
!this.myChart && (this.myChart = echarts.init(dom))
@@ -77,23 +75,13 @@ export default {
return allZero
}
},
loadEchart (chartNum, refresh = false) {
loadEchart (chartNum) {
this.$emit('showLoading', true)
try {
this.myChart.setOption(this.chartOption, refresh)
this.$store.commit('setChartList', this.$_.cloneDeep(this.myChart))
this.myChart.setOption(this.chartOption)
if (chartNum && chartNum == 2) {
this.myChart2.setOption(this.chartOption2, refresh)
this.$store.commit('setChartList', this.$_.cloneDeep(this.myChart2))
this.myChart2.setOption(this.chartOption)
}
const _this = this
window.addEventListener('resize', function () {
_this.$store.getters.getChartList.forEach(chart => {
if (chart) {
chart.resize()
}
})
})
} finally {
setTimeout(() => {
this.$emit('showLoading', false)

View File

@@ -3,7 +3,6 @@ export default {
chartInfo: Object,
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
entity: Object,
timeFilter: Object,
queryParams: Object // 接口请求参数
}
}

View File

@@ -1,47 +0,0 @@
<template>
<el-pagination
small
ref="pagination"
:current-page="pageObj.pageNo"
:page-size="pageObj.pageSize"
layout="total,prev,jumper,slot,next"
class="chart-table-pagination"
:total="pageObj.total"
@current-change="currentChange"
>
<span>/&nbsp;{{totalPage}}</span>
</el-pagination>
</template>
<script>
export default {
name: 'chartDetectionPagination',
props: {
pageObj: Object
},
data () {
return {
}
},
computed: {
totalPage () {
const remainder = this.pageObj.total % this.pageObj.pageSize
if (remainder) {
return parseInt(this.pageObj.total / this.pageObj.pageSize) + 1
} else {
return parseInt(this.pageObj.total / this.pageObj.pageSize)
}
}
},
methods: {
currentChange: function (val) {
this.$emit('pageJump', val)
this.pageObj.pageNo = val
}
},
mounted () {
this.$el.querySelector('.el-pagination__jump').childNodes[0].nodeValue = ''
}
}
</script>

View File

@@ -1,85 +0,0 @@
<template>
<div class="security cn-detection--list">
<div class="cn-detection-table">
<chart-detections-table
v-for="(data, index) in chartData"
:detection="data"
:timeFilter="timeFilter"
:key="index"
:security="true"
:ref="`detectionRow${index}`"
:index="index"
></chart-detections-table>
</div>
<div class="cn-detection__footer">
<chart-detection-pagination
ref="pagination"
:page-obj="pageObj"
@pageJump="pageJump"
:pageSizeForAlarm="pageObj.pageSize"
></chart-detection-pagination>
</div>
</div>
</template>
<script>
import chartDetectionsTable from '@/views/charts/charts/chartDetectionsTable'
import chartDetectionPagination from '@/views/charts/charts/chartDetectionPagination'
import { get } from '@/utils/http'
import { replaceUrlPlaceholder } from '@/utils/tools'
export default {
name: 'chartDetectionSecurity',
props: {
chartInfo: Object,
chartData: Array,
resultType: Object,
queryParams: Object,
timeFilter: Object
},
components: {
chartDetectionPagination,
chartDetectionsTable
},
watch: {
},
data () {
return {
pageObj: {
pageNo: 1,
pageSize: 6,
total: 0,
resetPageNo: true
}
}
},
methods: {
securityCount () {
const requestUrl = this.chartInfo.params.countUrl
get(replaceUrlPlaceholder(requestUrl, this.queryParams)).then(response => {
this.pageObj.total = response.data.result
})
},
getDetectionData (val) {
this.pageObj.pageNo = val
const extraParams = {
pageNo: val,
pageSize: this.pageSize
}
this.$emit('getDetectionData', this.chartInfo.params.url, extraParams, false, {
startTime: this.queryParams.startTime,
endTime: this.queryParams.endTime
})
const requestUrl = this.chartInfo.params.countUrl
get(replaceUrlPlaceholder(requestUrl, this.queryParams)).then(response => {
this.pageObj.total = response.data.result
})
},
pageJump (val) {
this.getDetectionData(val)
}
},
mounted () {
this.securityCount()
}
}
</script>

Some files were not shown because too many files have changed in this diff Show More