Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80130e046b | ||
|
|
bddc366f05 | ||
|
|
4b04433194 | ||
|
|
f46ec514f0 | ||
|
|
f915c51254 | ||
|
|
4290ef2ceb | ||
|
|
766b777bc6 | ||
|
|
14125d549d | ||
|
|
ee338b247d | ||
|
|
d640c656fa | ||
|
|
5edd569148 | ||
|
|
f486c53945 | ||
|
|
95dc133dac | ||
|
|
01c393fee2 | ||
|
|
f334746a70 | ||
|
|
19ca35b738 | ||
|
|
96e7a935ee | ||
|
|
dce3921beb | ||
|
|
ae7f72a72b | ||
|
|
3823ea3dc4 | ||
|
|
4b7a559af7 | ||
|
|
ba8dfaf0d4 | ||
|
|
e489e568e9 | ||
|
|
c0f6a47da4 | ||
|
|
7b4070f06a | ||
|
|
97ae64943b | ||
|
|
4855944e44 | ||
|
|
22b805791a | ||
|
|
80992f0b30 | ||
|
|
1405d6b3fe | ||
|
|
607ab78fc1 | ||
|
|
5fcfdc4244 | ||
|
|
86c14ae560 | ||
|
|
c558bdb952 | ||
|
|
d7b6a4f735 | ||
|
|
4114c3fa36 | ||
|
|
049622fd4b | ||
|
|
d0c4565eef | ||
|
|
446bd4431e | ||
|
|
9c46e1af47 | ||
|
|
87cd43dde2 | ||
|
|
53b4085111 | ||
|
|
697cc1da2d | ||
|
|
d841118ad9 | ||
|
|
07156f9e03 | ||
|
|
35004f419a | ||
|
|
5da5f55b80 | ||
|
|
dff5135d88 | ||
|
|
f724477934 | ||
|
|
24864ca1be | ||
|
|
0789dbcbfb | ||
|
|
17f0701c27 | ||
|
|
617ee131ec | ||
|
|
6d6f863ae7 | ||
|
|
bdee548bc1 | ||
|
|
5eed8baac1 | ||
|
|
e474003376 | ||
|
|
76b409d95d | ||
|
|
09c83e215c | ||
|
|
e8e8bd3462 | ||
|
|
0e752cb3a3 | ||
|
|
30883802cb | ||
|
|
4c38f1c913 | ||
|
|
a0fe66089f | ||
|
|
57609406be | ||
|
|
f38b5c7947 | ||
|
|
09b37512c9 | ||
|
|
7f15139a38 | ||
|
|
5ee3351ba7 | ||
|
|
df89c61a65 | ||
|
|
ab1b551642 | ||
|
|
38bc1ec729 | ||
|
|
dee401c9f2 | ||
|
|
eb611bdac9 | ||
|
|
468026b3fa |
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@amcharts/amcharts4": "^4.10.24",
|
||||
"@amcharts/amcharts4-geodata": "^4.1.20",
|
||||
"@antv/g6": "^4.8.17",
|
||||
"axios": "^0.21.1",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"codemirror": "^5.65.1",
|
||||
@@ -40,7 +41,9 @@
|
||||
"@babel/cli": "^7.12.1",
|
||||
"@babel/core": "^7.11.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@babel/plugin-proposal-private-methods": "^7.12.1",
|
||||
"@babel/plugin-transform-runtime": "^7.12.1",
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.12.1",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@babel/preset-typescript": "^7.10.4",
|
||||
"@commitlint/cli": "^9.1.2",
|
||||
|
||||
@@ -1,302 +1,304 @@
|
||||
.el-drawer.rtl {
|
||||
width: 700px !important;
|
||||
}
|
||||
.el-drawer__body {
|
||||
.common-right-box {
|
||||
height: 100%;
|
||||
}
|
||||
.right-box, .right-sub-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.el-date-editor {
|
||||
.el-input__inner {
|
||||
padding-left: 32px;
|
||||
}
|
||||
.el-drawer__body {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
padding: 0 20px;
|
||||
border-bottom: 1px solid $--right-box-border-color;
|
||||
.right-box, .right-sub-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.header__title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
.header__operation {
|
||||
i {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-box__container {
|
||||
height: calc(100% - 130px);
|
||||
padding: 0 30px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
.el-textarea__inner {
|
||||
padding: 5px 70px 4px 15px;
|
||||
}
|
||||
.container__form-width.container__form{
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 530px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: -40px;
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
.el-date-editor {
|
||||
.el-input__inner {
|
||||
padding-left: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item__content {
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 517px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: -40px;
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.right-box__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
padding: 0 20px;
|
||||
border-bottom: 1px solid $--right-box-border-color;
|
||||
|
||||
.header__title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
.header__operation {
|
||||
i {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-row-item {
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 466px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: 0;
|
||||
|
||||
.right-box__container {
|
||||
height: calc(100% - 130px);
|
||||
padding: 0 30px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
.el-textarea__inner {
|
||||
padding: 5px 70px 4px 15px;
|
||||
}
|
||||
.container__form-width.container__form{
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 530px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: -40px;
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
.el-input__count {
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
.el-form-item__content {
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 517px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: -40px;
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
.el-input--small.not-fixed-height {
|
||||
height: 32px;
|
||||
.form-row-item {
|
||||
.input-box {
|
||||
.el-textarea {
|
||||
.el-textarea__inner {
|
||||
width: 466px;
|
||||
height: 32px;
|
||||
padding: 5px 70px 4px 10px;
|
||||
}
|
||||
.el-input__count {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
.el-input__count {
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-input__inner, .el-textarea__inner {
|
||||
padding: 0 10px;
|
||||
border-radius: $--border-radius-primary;
|
||||
border: 1px solid $--right-box-border-color;
|
||||
}
|
||||
.el-textarea__inner {
|
||||
padding: 5px 70px 4px 15px;
|
||||
}
|
||||
.el-form {
|
||||
padding-top: 20px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 16px;
|
||||
.el-form-item__label{
|
||||
padding-bottom: 6px;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.el-input__inner:hover {
|
||||
border-color: darken($--right-box-border-color, 10%);
|
||||
}
|
||||
.el-input__inner:focus {
|
||||
border-color: darken($--right-box-border-color, 20%);
|
||||
.el-input--small.not-fixed-height {
|
||||
height: 32px;
|
||||
.el-input__count {
|
||||
line-height: 29px;
|
||||
height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item.is-error .el-input__inner, .el-form-item.is-error .el-input__inner:focus, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner:focus, .el-message-box__input input.invalid, .el-message-box__input input.invalid:focus {
|
||||
border-color: #F56C6C
|
||||
}
|
||||
|
||||
.form__sub-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.el-input__inner, .el-textarea__inner {
|
||||
padding: 0 10px;
|
||||
margin-bottom: 20px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
background-color: #F6F6F6;
|
||||
}
|
||||
/* 虚线框类型的form-item */
|
||||
.form__dotted-item {
|
||||
padding: 10px 10px 6px 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px dashed $--border-color-primary;
|
||||
border-radius: $--border-radius-primary;
|
||||
border: 1px solid $--right-box-border-color;
|
||||
}
|
||||
.el-textarea__inner {
|
||||
padding: 5px 70px 4px 15px;
|
||||
}
|
||||
.el-form {
|
||||
padding-top: 20px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 0;
|
||||
|
||||
.el-form-item__label {
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
.el-form-item__label{
|
||||
padding-bottom: 6px;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
color: #666;
|
||||
}
|
||||
.form__labels-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.el-input__inner:hover {
|
||||
border-color: darken($--right-box-border-color, 10%);
|
||||
}
|
||||
.el-input__inner:focus {
|
||||
border-color: darken($--right-box-border-color, 20%);
|
||||
}
|
||||
}
|
||||
.el-form-item.is-error .el-input__inner, .el-form-item.is-error .el-input__inner:focus, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner:focus, .el-message-box__input input.invalid, .el-message-box__input input.invalid:focus {
|
||||
border-color: #F56C6C
|
||||
}
|
||||
|
||||
.form__sub-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 20px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
background-color: #F6F6F6;
|
||||
}
|
||||
/* 虚线框类型的form-item */
|
||||
.form__dotted-item {
|
||||
padding: 10px 10px 6px 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px dashed $--border-color-primary;
|
||||
border-radius: $--border-radius-primary;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 0;
|
||||
|
||||
.el-form-item__label {
|
||||
width: 100%;
|
||||
}
|
||||
.form__labels-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
.form__create-btn {
|
||||
margin-bottom: 20px;
|
||||
width: 300px;
|
||||
height: 28px;
|
||||
border: 1px solid lighten($--color-primary, 60%);
|
||||
border-radius: $--border-radius-primary;
|
||||
background-color: lighten($--color-primary, 95%);
|
||||
|
||||
i {
|
||||
color: $--color-primary;
|
||||
}
|
||||
}
|
||||
.form__flex-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.one-third-form-item-left{
|
||||
display: inline-block;
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
.one-third-form-item-right{
|
||||
display: inline-block;
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
.form-item--half-width-other-two{
|
||||
display: inline-block;
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
.form-item--half-width-other{
|
||||
display: inline-block;
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
}
|
||||
.form__create-btn {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.right-box__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 70px;
|
||||
box-shadow: -3px 0 8px -3px rgba(205,205,205,0.77);
|
||||
|
||||
.footer__btn {
|
||||
margin: 0 15px;
|
||||
height: 30px;
|
||||
min-width: 74px;
|
||||
padding: 0 15px;
|
||||
color: white;
|
||||
background-color: $--color-primary;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background-color linear .2s, color linear .1s;
|
||||
}
|
||||
.footer__btn:hover:not(.footer__btn--disabled) {
|
||||
background-color: lighten($--color-primary, 10%);
|
||||
}
|
||||
.footer__btn--light {
|
||||
background-color: white;
|
||||
border: 1px solid $--border-color-primary;
|
||||
color: #333;
|
||||
}
|
||||
.footer__btn.footer__btn--light:hover:not(.footer__btn--disabled) {
|
||||
background-color: white;
|
||||
border-color: lighten($--color-primary, 40%);
|
||||
color: $--color-primary;
|
||||
}
|
||||
.footer__btn--disabled {
|
||||
opacity: .6;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
/* 隐藏label新增按钮处级联选择器的input */
|
||||
.hide-casc-input {
|
||||
position: relative;
|
||||
|
||||
.hide-input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 300px;
|
||||
height: 28px;
|
||||
border: 1px solid lighten($--color-primary, 60%);
|
||||
border-radius: $--border-radius-primary;
|
||||
background-color: lighten($--color-primary, 95%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.label__multi-text {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.right-box__select {
|
||||
width: 100%;
|
||||
}
|
||||
.el-select-last.right-box-select-dropdown {
|
||||
left: 1698px;
|
||||
}
|
||||
.limit-height .el-cascader-menu {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
color: $--color-primary;
|
||||
.form-items--half-width-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.form-item--half-width {
|
||||
width: calc(50% - 10px);
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.form__flex-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.one-third-form-item-left{
|
||||
display: inline-block;
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
.one-third-form-item-right{
|
||||
display: inline-block;
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
.form-item--half-width-other-two{
|
||||
display: inline-block;
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
.form-item--half-width-other{
|
||||
display: inline-block;
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-box__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 70px;
|
||||
box-shadow: -3px 0 8px -3px rgba(205,205,205,0.77);
|
||||
|
||||
.footer__btn {
|
||||
margin: 0 15px;
|
||||
height: 30px;
|
||||
min-width: 74px;
|
||||
padding: 0 15px;
|
||||
color: white;
|
||||
background-color: $--color-primary;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background-color linear .2s, color linear .1s;
|
||||
}
|
||||
.footer__btn:hover:not(.footer__btn--disabled) {
|
||||
background-color: lighten($--color-primary, 10%);
|
||||
}
|
||||
.footer__btn--light {
|
||||
background-color: white;
|
||||
border: 1px solid $--border-color-primary;
|
||||
color: #333;
|
||||
}
|
||||
.footer__btn.footer__btn--light:hover:not(.footer__btn--disabled) {
|
||||
background-color: white;
|
||||
border-color: lighten($--color-primary, 40%);
|
||||
color: $--color-primary;
|
||||
}
|
||||
.footer__btn--disabled {
|
||||
opacity: .6;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
/* 隐藏label新增按钮处级联选择器的input */
|
||||
.hide-casc-input {
|
||||
position: relative;
|
||||
|
||||
.hide-input {
|
||||
.cn-icon-minus-position {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 300px;
|
||||
opacity: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
height: 100%;
|
||||
transform: translateY(-50%);
|
||||
justify-content: space-between;
|
||||
}
|
||||
.form-item--end-with-btn { // 末尾留出btn宽度空间的form item
|
||||
|
||||
}
|
||||
.el-form-item__content .el-autocomplete .el-input-group {
|
||||
vertical-align: unset;
|
||||
}
|
||||
}
|
||||
.label__multi-text {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.right-box__select {
|
||||
width: 100%;
|
||||
}
|
||||
.el-select-last.right-box-select-dropdown {
|
||||
left: 1698px;
|
||||
}
|
||||
.limit-height .el-cascader-menu {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.form-items--half-width-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.form-item--half-width {
|
||||
width: calc(50% - 10px);
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.cn-icon-minus-position {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
height: 100%;
|
||||
transform: translateY(-50%);
|
||||
justify-content: space-between;
|
||||
}
|
||||
.form-item--end-with-btn { // 末尾留出btn宽度空间的form item
|
||||
|
||||
}
|
||||
.el-form-item__content .el-autocomplete .el-input-group {
|
||||
vertical-align: unset;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
right: 10px;
|
||||
|
||||
.search__suffix {
|
||||
margin-left: 8px; // 新版实体列表改版,后续记得解开
|
||||
// margin-left: 8px;
|
||||
|
||||
.cn-icon-search-advance, .cn-icon-search-normal {
|
||||
//.cn-icon-search-advance, .cn-icon-search-normal, .cn-icon-filter {
|
||||
.cn-icon-search-advance, .cn-icon-search-normal, .cn-icon-filter {
|
||||
color: #A6AAAE;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
@@ -85,3 +85,6 @@
|
||||
@import 'views/charts2/entityDetailTabs';
|
||||
@import 'views/charts2/digitalCertificate';
|
||||
@import 'views/charts2/entityDetailBasicInfo';
|
||||
|
||||
@import "views/charts2/graphRightListBlock";
|
||||
@import "views/charts2/graphRightDetailBlock";
|
||||
|
||||
@@ -33,8 +33,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.more{
|
||||
margin-bottom:20px;
|
||||
.button {
|
||||
color:#909399;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.type-content {
|
||||
margin-bottom:15px;
|
||||
margin-bottom:0px;
|
||||
display:flex;
|
||||
flex-flow: row wrap;
|
||||
width:100%;
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
display: flex;
|
||||
height: 134px;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.analysis-entry-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 70px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -69,7 +70,7 @@
|
||||
|
||||
.dividing-line {
|
||||
height: 1px;
|
||||
width: calc(100% - 60px);
|
||||
width: 100%;
|
||||
margin-top: 21px;
|
||||
background-color: #EFF2F5;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
$font-size: 12px;
|
||||
.graph-detail-basic-info {
|
||||
position: relative;
|
||||
padding-bottom: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
//height: 100%;
|
||||
|
||||
.graph-detail-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.entity-graph-type {
|
||||
font-size: 12px;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.entity-type {
|
||||
color: #717171;
|
||||
}
|
||||
|
||||
.graph-basic-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.graph-basic-info-name__block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.graph-basic-info-name {
|
||||
padding-right: 10px;
|
||||
max-width: 260px;
|
||||
font-size: 20px;
|
||||
color: #353636;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.graph-basic-info-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
border-radius: 50%;
|
||||
background-color: #EFF1F4;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
i {
|
||||
color: #717171;
|
||||
font-size: 10px;
|
||||
-webkit-transform: scale(0.8); // 强制给文字进行缩放,达到12px以下小字体的效果
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-detail__icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: #F3F7FA;
|
||||
|
||||
i {
|
||||
font-size: 26px;
|
||||
color: #4E84B4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-close {
|
||||
color: #575757;
|
||||
font-size: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.graph-basic-info__block {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 18px;
|
||||
|
||||
.graph-header__icon {
|
||||
width: 3px !important;
|
||||
height: 14px !important;
|
||||
}
|
||||
|
||||
.graph-basic-info__block-content {
|
||||
|
||||
.graph-content-item, .graph-content-relationship-item {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.graph-content-item {
|
||||
|
||||
.graph-content-item-label, .graph-content-item-value {
|
||||
width: 130px;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: $font-size;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
padding-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.graph-content-item-value {
|
||||
width: 230px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
overflow-wrap: break-word;
|
||||
line-height: normal;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-content-relationship-item {
|
||||
justify-content: space-between;
|
||||
line-height: 24px;
|
||||
|
||||
.graph-relationship-item-label, .graph-relationship-item-value {
|
||||
font-size: $font-size;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
//height: 40px;
|
||||
display: flex;
|
||||
align-items: center !important;
|
||||
padding-top: 1px;
|
||||
|
||||
.graph-relationship-item-label-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-relationship-item-value {
|
||||
color: #717171;
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-tag-list {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
margin: 6px 0;
|
||||
|
||||
.graph-tag-item {
|
||||
margin-bottom: 10px;
|
||||
margin-right: 9px;
|
||||
padding: 0 8px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
|
||||
span {
|
||||
margin-top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.padding-b-10 {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.padding-b-4 {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
//修改popover样式
|
||||
.graph-popover {
|
||||
width: auto !important;
|
||||
background: #303133 !important;
|
||||
color: #fff !important;
|
||||
font-size: 12px !important;
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.graph-popover .el-popper__arrow::before {
|
||||
background: #303133 !important;
|
||||
}
|
||||
|
||||
.graph-expand-relationship__icon {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.graph-basic-info__block-title {
|
||||
font-size: 13px;
|
||||
color: #353636;
|
||||
font-weight: 600;
|
||||
}
|
||||
154
src/assets/css/components/views/charts2/graphRightListBlock.scss
Normal file
@@ -0,0 +1,154 @@
|
||||
$font-size: 12px;
|
||||
.graph-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.graph-list-header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
color: #353636;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.graph-list-header-icon {
|
||||
font-size: 21px;
|
||||
color: #717171;
|
||||
margin-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-header-number {
|
||||
font-size: 12px;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-expand-btn-block {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.graph-list-expand-btn {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
background: #38ACD2;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
padding: 14px 10px;
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(46,136,166,0.85);
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
&.graph-list-expand-btn--disabled {
|
||||
opacity: .4;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-content-header {
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.graph-list-content {
|
||||
padding: 0 10px;
|
||||
|
||||
.graph-list-item-ip {
|
||||
margin-bottom: 10px;
|
||||
font-size: $font-size;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.graph-list-item-block {
|
||||
width: 100%;
|
||||
background: rgba(247, 247, 247, 1);
|
||||
border: 1px solid rgba(226, 229, 236, 1);
|
||||
border-radius: 2px;
|
||||
padding: 10px 15px;
|
||||
|
||||
.graph-list-item, .graph-list-item__app {
|
||||
display: flex;
|
||||
|
||||
.graph-list-item-label, .graph-list-item-label__app {
|
||||
width: 72px;
|
||||
//margin-right: 15px;
|
||||
font-size: $font-size;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.graph-list-item-label__app {
|
||||
width: 83px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.graph-list-country-flag {
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.graph-list-item-value {
|
||||
font-size: $font-size;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.graph-list-item-value1 {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-list-item {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.padding-b-20 {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.padding-b-16 {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.padding-b-12 {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.graph-list-dividing-line {
|
||||
width: 300px;
|
||||
height: 1px;
|
||||
background: #ECECEC;
|
||||
margin: 11px 0;
|
||||
}
|
||||
@@ -1,19 +1,13 @@
|
||||
.information-aggregation__table {
|
||||
.intelligence-content {
|
||||
padding-top:10px !important;
|
||||
padding-bottom:4px !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
.information-aggregation-tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
justify-content: left;
|
||||
align-items: flex-start;
|
||||
margin-bottom:6px;
|
||||
padding-top:10px !important;
|
||||
padding-bottom:4px !important;
|
||||
}
|
||||
}
|
||||
.information-aggregation__valid {
|
||||
background: #eff3e9;
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
.el-input__inner {
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
background-color: #F5F8FA;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.common-select {
|
||||
top: 32px !important;
|
||||
|
||||
@@ -222,3 +222,10 @@
|
||||
padding: 0 4px;
|
||||
//color: white;
|
||||
}
|
||||
|
||||
.performance-event-remark {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 12px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@@ -117,9 +117,9 @@
|
||||
|
||||
.overview-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 30px;
|
||||
padding: 0 0 0 30px;
|
||||
|
||||
.overview-left-span {
|
||||
font-size: 16px;
|
||||
@@ -141,12 +141,14 @@
|
||||
.overview-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 30px;
|
||||
justify-content: center;
|
||||
padding: 0 15px;
|
||||
|
||||
.right-row {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
height: 18px;
|
||||
align-items: center;
|
||||
color: #666666;
|
||||
|
||||
.right-label-loading {
|
||||
position: relative;
|
||||
@@ -168,7 +170,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
i {
|
||||
padding-right: 10px;
|
||||
padding-right: 4px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.cn-icon-increase {
|
||||
|
||||
@@ -1,104 +1,100 @@
|
||||
.entity-filter-case {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 280px;
|
||||
margin-right: 10px;
|
||||
width: 320px;
|
||||
margin-right: 20px;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
border: 1px solid rgba(226, 229, 236, 1) !important;
|
||||
border-radius: 4px !important;
|
||||
|
||||
.filter-case__header {
|
||||
background-color: #E1E6ED;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 8px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
.entity-filter {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #E7EAED;
|
||||
margin-bottom: 10px;
|
||||
background-color: white;
|
||||
|
||||
.filter__header {
|
||||
height: 46px;
|
||||
margin: 0 15px;
|
||||
line-height: 46px;
|
||||
border-bottom: 1px solid #EFF2F5;
|
||||
padding-left: 8px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
background: #F7F7F7;
|
||||
box-shadow: 0 1px 0 0 rgba(226,229,236,1);
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
.filter__body {
|
||||
padding: 11px 0 21px 0;
|
||||
.filter__row {
|
||||
padding: 0 15px;
|
||||
|
||||
.filter__header {
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
margin: 0 20px;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filter__body {
|
||||
width: calc(100% - 40px);
|
||||
margin: 0 20px;
|
||||
|
||||
.filter-hr {
|
||||
width: calc(100% + 20px);
|
||||
margin-left: -10px;
|
||||
margin-top: 10px;
|
||||
height: 1px;
|
||||
background: #EFF2F5;
|
||||
//background: #000;
|
||||
}
|
||||
|
||||
.filter__body-item {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
|
||||
.filter__body-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all linear .2s;
|
||||
.filter__row-popover {
|
||||
display: flex;
|
||||
line-height: 26px;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
|
||||
.filter-country-flag {
|
||||
width: 18px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
&:hover, &.filter__row--active {
|
||||
background-color: #F3F7FA;
|
||||
}
|
||||
.row__label {
|
||||
font-size: 14px;
|
||||
flex: 8;
|
||||
display: flex;
|
||||
i {
|
||||
color: #8FA1BE;
|
||||
}
|
||||
span {
|
||||
padding-left: 6px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
.row__value {
|
||||
color: #666;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
.filter__body-item-left-index {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
.chart__loading img {
|
||||
left: unset;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.filter__row-popover {
|
||||
.pop-title {
|
||||
i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.entity-pop-custom {
|
||||
.filter-top-box {
|
||||
.chart__loading {
|
||||
height: calc(100% - 65px);
|
||||
top: 64px;
|
||||
}
|
||||
.top-table-percent{
|
||||
display:grid;
|
||||
grid-template-columns: 50% auto;
|
||||
grid-template-rows: 100%;
|
||||
grid-row-gap: 0px;
|
||||
grid-column-gap: 0px;
|
||||
.top-table-progress{
|
||||
align-content: center;
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
.customer-no-border-table {
|
||||
.el-table__body-wrapper {
|
||||
height: calc(100% - 36px);
|
||||
background: #EFF2F5;
|
||||
border-radius: 2px;
|
||||
margin-right: 6px;
|
||||
font-family: NotoSansHans-Black;
|
||||
font-size: 9px;
|
||||
color: #96A2B0;
|
||||
font-weight: 900;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.filter__body-item-left-label {
|
||||
max-width: 180px;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.filter__body-item-right {
|
||||
flex-shrink: 0;
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 12px;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
background: #FFFFFF;
|
||||
border-radius: 2px;
|
||||
transition: all .2s;
|
||||
//border: 1px solid #E2E5EC; 新版实体列表改版,后续记得解开
|
||||
border: 1px solid #E2E5EC;
|
||||
|
||||
&:hover .cn-entity__header .header__content {
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
.overview__title {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.overview__content-loading.overview__content {
|
||||
position: relative;
|
||||
@@ -130,6 +131,9 @@
|
||||
background-color: #F6C738;
|
||||
}
|
||||
}
|
||||
&.row__content--width90 {
|
||||
width: 90px;
|
||||
}
|
||||
&.row__content--width200 {
|
||||
width: 200px;
|
||||
}
|
||||
@@ -144,7 +148,7 @@
|
||||
}
|
||||
.row__contents {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//flex-direction: column;
|
||||
|
||||
.row__content {
|
||||
padding: 2px 0;
|
||||
@@ -156,15 +160,26 @@
|
||||
&:last-of-type {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.el-popper {
|
||||
min-width: 90px !important;
|
||||
}
|
||||
}
|
||||
.row__content-accept {
|
||||
margin-left: 39px;
|
||||
}
|
||||
.row__charts-msg {
|
||||
width: auto;
|
||||
padding-right: 20px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.new-row__charts-msg {
|
||||
width: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.row__charts {
|
||||
height: 20px;
|
||||
width: 60px;
|
||||
padding-left: 5px;
|
||||
//padding-left: 5px;
|
||||
}
|
||||
}
|
||||
.row__charts {
|
||||
@@ -176,6 +191,12 @@
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.overview__row-related {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.overview__content.domain__content {
|
||||
@@ -292,3 +313,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.margin-l-140 {
|
||||
margin-left: 140px;
|
||||
}
|
||||
|
||||
.line-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.entity-list {
|
||||
width: calc(100% - 290px);
|
||||
width: 100%;
|
||||
height: calc(100% - 42px);
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
.cn-entity--list {
|
||||
display: flex;
|
||||
//border: 1px #E2E5EC solid;
|
||||
//margin-bottom: 10px;
|
||||
//border-radius: 4px;
|
||||
// 新版实体列表改版,后续记得解开
|
||||
border: 1px #E2E5EC solid;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 4px;
|
||||
|
||||
.cn-entity__collapse {
|
||||
margin-bottom: 1px;
|
||||
@@ -13,8 +12,8 @@
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
background-color: #F3F7FA;
|
||||
//border-radius: 4px 0 0 4px;
|
||||
// 新版实体列表改版,后续记得解开
|
||||
border-radius: 4px 0 0 4px;
|
||||
|
||||
span {
|
||||
transform: rotate(0);
|
||||
transition: all linear .2s;
|
||||
@@ -41,12 +40,12 @@
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
//align-content: center;
|
||||
align-content: center;
|
||||
padding: 16px 0;
|
||||
margin-bottom: 1px;
|
||||
background-color: white;
|
||||
//border-radius: 0 4px 4px 0;
|
||||
// 新版实体列表改版,后续记得解开
|
||||
border-radius: 0 4px 4px 0;
|
||||
|
||||
.cn-entity__icon {
|
||||
margin-left: 26px;
|
||||
margin-right: 10px;
|
||||
@@ -77,13 +76,12 @@
|
||||
font-size: 16px;
|
||||
padding-bottom: 3px;
|
||||
color: #333333;
|
||||
//.cn-entity__header-title {
|
||||
// margin-right: 10px;
|
||||
//}
|
||||
//.cn-entity__header-tag {
|
||||
//
|
||||
//}
|
||||
// 新版实体列表改版,后续记得解开
|
||||
.cn-entity__header-title {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.cn-entity__header-tag {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.cn-entity__body {
|
||||
@@ -140,7 +138,7 @@
|
||||
.row__charts {
|
||||
height: 19px;
|
||||
width: 60px;
|
||||
padding-left: 5px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,31 +160,46 @@
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.show-detail {
|
||||
flex-shrink: 0;
|
||||
padding: 0 30px;
|
||||
font-size: 12px;
|
||||
color: #3976CB;
|
||||
//color: #2C72C6;
|
||||
//font-weight: 400;
|
||||
//margin-top: -17px;
|
||||
// 新版实体列表改版,后续记得解开
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
.row-item-label {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 14px;
|
||||
color: #717171;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
//i {
|
||||
// font-size: 12px;
|
||||
// margin-right: 5px;
|
||||
//}
|
||||
.row-item-value {
|
||||
font-family: NotoSansSChineseRegular;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-show-detail {
|
||||
flex-shrink: 0;
|
||||
padding: 0 30px;
|
||||
font-size: 12px;
|
||||
color: #2C72C6;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cn-entity__detail-overview {
|
||||
flex-basis: 100%;
|
||||
padding: 0 10px;
|
||||
|
||||
@@ -682,8 +682,9 @@
|
||||
}
|
||||
|
||||
.el-collapse {
|
||||
width: 655px;
|
||||
width: 855px;
|
||||
margin-left: 5px;
|
||||
padding-right: 200px;
|
||||
border: none;
|
||||
|
||||
.el-collapse-item.upload-collapse {
|
||||
@@ -721,6 +722,7 @@
|
||||
.el-collapse-item__wrap {
|
||||
padding-left: 35px;
|
||||
border: none;
|
||||
overflow: visible;
|
||||
}
|
||||
.el-collapse-item__content {
|
||||
position: relative;
|
||||
@@ -814,13 +816,20 @@
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
.form-select__disable {
|
||||
width: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
background-color: #F5F8FA;
|
||||
}
|
||||
}
|
||||
.form-select__enable {
|
||||
width: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
background-color: white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.skeleton-border {
|
||||
@@ -866,6 +875,22 @@
|
||||
&.imported-table-box--error {
|
||||
border-color: $--color-danger;
|
||||
}
|
||||
.entity-format-tip {
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
padding-left: 10px;
|
||||
width: 200px;
|
||||
color: #353636;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
span {
|
||||
padding-right: 10px;
|
||||
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
.imported-table {
|
||||
padding: 0 12px;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "cn-icon"; /* Project id 2614877 */
|
||||
src: url('iconfont.woff2?t=1687167070241') format('woff2'),
|
||||
url('iconfont.woff?t=1687167070241') format('woff'),
|
||||
url('iconfont.ttf?t=1687167070241') format('truetype');
|
||||
src: url('iconfont.woff2?t=1689317280458') format('woff2'),
|
||||
url('iconfont.woff?t=1689317280458') format('woff'),
|
||||
url('iconfont.ttf?t=1689317280458') format('truetype');
|
||||
}
|
||||
|
||||
.cn-icon {
|
||||
@@ -13,6 +13,46 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.cn-icon-add-knowledge-base:before {
|
||||
content: "\e802";
|
||||
}
|
||||
|
||||
.cn-icon-update-knowledge-base:before {
|
||||
content: "\e803";
|
||||
}
|
||||
|
||||
.cn-icon-zoom-out:before {
|
||||
content: "\e7fd";
|
||||
}
|
||||
|
||||
.cn-icon-to-default:before {
|
||||
content: "\e7fe";
|
||||
}
|
||||
|
||||
.cn-icon-reset:before {
|
||||
content: "\e7ff";
|
||||
}
|
||||
|
||||
.cn-icon-next-step:before {
|
||||
content: "\e800";
|
||||
}
|
||||
|
||||
.cn-icon-pre-step:before {
|
||||
content: "\e801";
|
||||
}
|
||||
|
||||
.cn-icon-zoom-in:before {
|
||||
content: "\e7f";
|
||||
}
|
||||
|
||||
.cn-icon-expand-continue:before {
|
||||
content: "\e7fc";
|
||||
}
|
||||
|
||||
.cn-icon-domain1:before {
|
||||
content: "\e7fb";
|
||||
}
|
||||
|
||||
.cn-icon-expand-relationship:before {
|
||||
content: "\e7f8";
|
||||
}
|
||||
|
||||
1
src/assets/img/entity-symbol2/app-colored.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687771200531" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7765" width="36" height="36" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M723.84487531 71.54166698c60.46291698 0 110.11458302 49.45145802 110.11458302 110.11458302v12.21270802h10.05045802c27.58870802 0 49.77179198 22.30320802 49.77179198 49.73175v256.78720896c0 27.42854198-22.34325 49.73175-49.77179198 49.73175h-10.05045802v292.22408302c0 60.50295802-49.4915 110.11458302-110.11458302 110.11458302H310.89516635a110.394875 110.394875 0 0 1-110.11458302-110.11458302v-292.22408302h-10.0905A49.81183302 49.81183302 0 0 1 140.95833333 500.38791698V243.60070802c0-27.42854198 22.30320802-49.73175 49.73175-49.73175h10.0905V181.65625C200.78058333 121.15329198 250.23204135 71.54166698 310.89516635 71.54166698z m54.97720802 688.31625H255.75779135v82.48583302a55.2575 55.2575 0 0 0 55.137375 55.137375h412.94970896a55.2575 55.2575 0 0 0 55.09733302-55.137375l-0.120125-82.48583302z m-261.47208302 27.508625c22.02291698 0 41.24291698 19.22 41.24291604 41.28295802 0 22.02291698-19.22 41.24291698-41.24291604 41.24291698-21.90279198 0-41.24291698-19.22-41.24291698-41.24291698s19.22-41.24291698 41.24291698-41.24291698z m261.59220802-237.246875H255.87791635v154.56083302h523.06429198v-154.56083302z m61.06354198-302.47475H194.73429135v248.65875h645.27145896v-248.65875z m-518.53958396 23.78475c12.41291698 0 23.5445 7.52783302 28.10925 18.97975l60.903375 150.55666604a24.865875 24.865875 0 0 1-23.10404104 34.27566698 25.106125 25.106125 0 0 1-23.26420896-15.8565l-6.56683302-16.697375H284.78800031l-6.32658396 16.53720802a25.14616698 25.14616698 0 1 1-46.76866604-18.41916604l61.70420802-150.55666698a30.43166698 30.43166698 0 0 1 28.10925-18.81958302z m217.82666698 0c40.722375 0 71.63454198 31.47275 71.63454198 69.6725 0 38.15970802-31.19245802 69.071875-74.4775 69.071875h-20.70154198v40.32195802a24.66566698 24.66566698 0 0 1-24.74575 24.74575 24.82583302 24.82583302 0 0 1-24.74575-24.74575V296.17541698a24.66566698 24.66566698 0 0 1 24.74575-24.74575z m190.878625 0c40.722375 0 71.67458302 31.47275 71.67458302 69.6725 0 38.15970802-31.2325 69.071875-74.4775 69.071875h-20.74158302v40.32195802a24.66566698 24.66566698 0 0 1-24.74575 24.74575 24.66566698 24.66566698 0 0 1-24.70570802-24.74575V296.17541698a24.66566698 24.66566698 0 0 1 24.70570802-24.74575zM321.10579135 348.30966698l-20.181 52.05416604H341.16666635l-20.02083302-52.05416604z m215.46420896-27.3885h-20.70154198v47.16908302h18.17891698c18.65941698 0 27.3885-11.57204198 27.3885-25.14616698 0-11.01145802-6.68695802-22.02291698-24.82583396-22.02291604z m190.7585 0h-20.70154198v47.16908302h18.138875c18.69945802 0 27.42854198-11.57204198 27.42854198-25.14616698 0-11.01145802-6.727-22.02291698-24.82583396-22.02291604z m-3.3635-194.40229198H311.01529135A55.2575 55.2575 0 0 0 255.87791635 181.65625v12.21270802h523.22445896V181.65625a55.2575 55.2575 0 0 0-55.137375-55.137375z" p-id="7766" fill="#E5A219"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
1
src/assets/img/entity-symbol2/app.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688290120782" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7911" xmlns:xlink="http://www.w3.org/1999/xlink" width="36" height="36"><path d="M723.84487531 71.54166698c60.46291698 0 110.11458302 49.45145802 110.11458302 110.11458302v12.21270802h10.05045802c27.58870802 0 49.77179198 22.30320802 49.77179198 49.73175v256.78720896c0 27.42854198-22.34325 49.73175-49.77179198 49.73175h-10.05045802v292.22408302c0 60.50295802-49.4915 110.11458302-110.11458302 110.11458302H310.89516635a110.394875 110.394875 0 0 1-110.11458302-110.11458302v-292.22408302h-10.0905A49.81183302 49.81183302 0 0 1 140.95833333 500.38791698V243.60070802c0-27.42854198 22.30320802-49.73175 49.73175-49.73175h10.0905V181.65625C200.78058333 121.15329198 250.23204135 71.54166698 310.89516635 71.54166698z m54.97720802 688.31625H255.75779135v82.48583302a55.2575 55.2575 0 0 0 55.137375 55.137375h412.94970896a55.2575 55.2575 0 0 0 55.09733302-55.137375l-0.120125-82.48583302z m-261.47208302 27.508625c22.02291698 0 41.24291698 19.22 41.24291604 41.28295802 0 22.02291698-19.22 41.24291698-41.24291604 41.24291698-21.90279198 0-41.24291698-19.22-41.24291698-41.24291698s19.22-41.24291698 41.24291698-41.24291698z m261.59220802-237.246875H255.87791635v154.56083302h523.06429198v-154.56083302z m61.06354198-302.47475H194.73429135v248.65875h645.27145896v-248.65875z m-518.53958396 23.78475c12.41291698 0 23.5445 7.52783302 28.10925 18.97975l60.903375 150.55666604a24.865875 24.865875 0 0 1-23.10404104 34.27566698 25.106125 25.106125 0 0 1-23.26420896-15.8565l-6.56683302-16.697375H284.78800031l-6.32658396 16.53720802a25.14616698 25.14616698 0 1 1-46.76866604-18.41916604l61.70420802-150.55666698a30.43166698 30.43166698 0 0 1 28.10925-18.81958302z m217.82666698 0c40.722375 0 71.63454198 31.47275 71.63454198 69.6725 0 38.15970802-31.19245802 69.071875-74.4775 69.071875h-20.70154198v40.32195802a24.66566698 24.66566698 0 0 1-24.74575 24.74575 24.82583302 24.82583302 0 0 1-24.74575-24.74575V296.17541698a24.66566698 24.66566698 0 0 1 24.74575-24.74575z m190.878625 0c40.722375 0 71.67458302 31.47275 71.67458302 69.6725 0 38.15970802-31.2325 69.071875-74.4775 69.071875h-20.74158302v40.32195802a24.66566698 24.66566698 0 0 1-24.74575 24.74575 24.66566698 24.66566698 0 0 1-24.70570802-24.74575V296.17541698a24.66566698 24.66566698 0 0 1 24.70570802-24.74575zM321.10579135 348.30966698l-20.181 52.05416604H341.16666635l-20.02083302-52.05416604z m215.46420896-27.3885h-20.70154198v47.16908302h18.17891698c18.65941698 0 27.3885-11.57204198 27.3885-25.14616698 0-11.01145802-6.68695802-22.02291698-24.82583396-22.02291604z m190.7585 0h-20.70154198v47.16908302h18.138875c18.69945802 0 27.42854198-11.57204198 27.42854198-25.14616698 0-11.01145802-6.727-22.02291698-24.82583396-22.02291604z m-3.3635-194.40229198H311.01529135A55.2575 55.2575 0 0 0 255.87791635 181.65625v12.21270802h523.22445896V181.65625a55.2575 55.2575 0 0 0-55.137375-55.137375z" p-id="7912" fill="#778391"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
1
src/assets/img/entity-symbol2/domain-colored.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688298522321" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7364" xmlns:xlink="http://www.w3.org/1999/xlink" width="36" height="36"><path d="M512 61.06201172a450.93798828 450.93798828 0 1 1 0 901.87597656 450.93798828 450.93798828 0 0 1 0-901.87597656z m0 45.09379883a405.84418945 405.84418945 0 1 0 0 811.6883789 405.84418945 405.84418945 0 0 0 0-811.6883789z" p-id="7365" fill="#38ACD2"></path><path d="M229.64344446 586.23133044l15.95626722-52.586307c4.64812962-15.19314186 8.18625866-30.6637832 10.54501134-46.41192491h0.69375048c3.1912538 18.3150199 6.17438209 31.77378466 10.12876124 46.48129978l15.05439124 52.51693213h46.82817591l49.11755284-149.36453686h-48.77067761l-13.73626514 59.24631408c-3.60750391 17.06626868-6.93750745 33.855037-9.22688438 50.99068056h-0.69375136a864.41343565 864.41343565 0 0 0-11.79376257-50.64380531l-15.95626721-59.59318933h-39.33566772l-17.06626869 61.39694129c-3.88500427 14.63814112-8.46375903 31.70440892-11.79376256 48.84005335h-0.69375049A890.56783897 890.56783897 0 0 0 199.81216237 497.84748474l-12.7650143-61.05006603h-50.78255506l46.55067554 149.36453685h46.82817591zM570.27506324 496.04373279c-3.53812904 17.20501843-6.86813258 33.99378674-9.1575104 51.06005543h-0.69375047c-3.1912538-17.13564355-7.49250818-33.855037-11.79376257-50.64380531l-15.95626721-59.59318933H493.26872999l-17.06626869 61.39694129c-3.88500427 14.63814112-8.46375903 31.77378466-11.79376256 48.84005335h-0.69375137a904.30410413 904.30410413 0 0 0-9.08813463-49.18692861l-12.83438917-61.05006603h-50.78255417l46.48129978 149.29516199h46.89755078l16.09501783-52.51693213c4.57875475-15.26251673 8.11688379-30.73315807 10.40626074-46.48130068h0.69375136c3.33000354 18.38439477 6.24375697 31.84315955 10.19813611 46.48130068l15.05439124 52.51693212h46.82817502l49.11755373-149.29516198H584.15007813l-13.73626514 59.24631408zM825.22846423 496.04373279c-3.60750391 17.20501843-6.93750745 33.99378674-9.15751039 51.06005543h-0.69375048c-3.26062867-17.13564355-7.56188305-33.855037-11.79376256-50.64380531l-16.02564208-59.59318933h-39.33566773l-16.99689381 61.39694129a710.40076917 710.40076917 0 0 0-11.79376257 48.84005335h-0.69375049a893.96721827 893.96721827 0 0 0-9.15751038-49.18692861l-12.76501342-61.05006603H645.89389464l46.55067554 149.29516199h46.82817591l16.09501784-52.51693213a328.14410573 328.14410573 0 0 0 10.47563559-46.48130068h0.69375136c3.26062867 18.38439477 6.24375697 31.84315955 10.12876036 46.48130068l15.05439124 52.51693212h46.82817591l49.1869286-149.29516198h-48.84005337l-13.73626426 59.24631408z" p-id="7366" fill="#38ACD2"></path><path d="M320.17791736 643.11889184c28.65190576 164.34955323 107.87824195 274.72529762 191.82208264 274.72529761 81.30758763 0 158.24454601-103.7157373 189.04707984-259.80965612l2.42812756-12.83438916 44.40004835 7.90875828C715.4077206 835.28784972 623.34699522 962.93798828 512 962.93798828c-109.26574291 0-200.07771705-123.00200805-233.93275317-299.56157396l-2.28937782-12.48751393 44.40004835-7.70063368zM512 61.06201172c109.40449353 0 200.14709193 123.14075868 234.00212804 299.83907432l2.28937782 12.48751393-44.40004834 7.70063369C675.10080202 216.67030556 595.94384069 106.15581055 512 106.15581055c-82.07071387 0-159.56267298 105.58886413-189.81020519 263.62528552l-2.28937782 12.69563854-44.40004834-7.63125792C307.06602784 190.65465198 399.7511288 61.06201172 512 61.06201172z" p-id="7367" fill="#38ACD2"></path><path d="M549.60129065 647.28139648V962.93798828h-60.14819006V647.28139648h60.14819006z m0-586.21938476v315.6565918h-60.14819006V61.06201172h60.14819006z" p-id="7368" fill="#38ACD2"></path><path d="M151.24960938 241.43720703h721.50078124v45.09379883H151.24960938V241.43720703z m0 496.03178711h721.50078124v45.09379883H151.24960938v-45.09379883z" p-id="7369" fill="#38ACD2"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
src/assets/img/entity-symbol2/domain-colored2.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687771150463" class="icon" viewBox="0 0 1228 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7479" width="35.9765625" height="30" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M1099.86729167 250.4559668V115.17457031H125.84123698v135.28139649h974.02605469z m0 54.11255859H125.84123698v595.23814453h974.02605469V304.56852539zM71.72867839 61.06201172h1082.25117187v892.8572168H71.72867839V61.06201172z m324.31460117 504.74992185v44.34223492c0.1803752 10.31144837 2.1344401 18.12770712 5.89225608 23.50890074 3.72775374 5.38119362 11.15319987 8.05675843 22.27633663 8.05675844h99.65729541v44.34223581h-119.73906657c-20.14189651 0-34.15103728-4.65969284-41.99735827-13.9490154-7.81625876-9.28932256-11.7243877-23.32852556-11.72438769-42.14767035v-82.61183945c0-18.81914567 3.90812893-32.85834779 11.72438769-42.14767034 7.81625876-9.31938479 21.82539863-13.9490154 41.99735827-13.9490154h119.73906657v44.34223581h-99.65729541c-11.12313675 0-18.54858288 2.70562793-22.27633663 8.05675842-3.75781686 5.38119362-5.71188089 12.7465135-5.89225608 22.1560868z m327.98223044 64.15344416c0 18.12770712-3.72775374 32.01659717-11.21332523 41.66667012-7.4855706 9.62001071-21.40452288 14.43001562-41.7267946 14.43001563h-66.76888539c-20.17195963 0-34.18109951-4.65969284-41.99735738-13.9490154-7.81625876-9.28932256-11.7243877-23.32852556-11.7243877-42.14767035v-82.61183945c0-18.81914567 3.90812893-32.85834779 11.7243877-42.14767034 7.81625876-9.31938479 21.82539863-13.9490154 41.99735738-13.9490154h66.73882227c20.35233483 0 34.27128711 4.81000491 41.75685772 14.43001562 7.4855706 9.62001071 11.21332435 23.53896299 11.21332523 41.66667012v82.61183945zM678.39058559 611.20635742v-44.67292307c0-10.76238636-1.74362659-18.60870736-5.23088067-23.50890076-3.48725407-4.93025564-11.21332435-7.39538301-23.20827572-7.395383h-25.55315237c-11.12313675 0-18.57864512 2.70562793-22.30639886 8.05675842-3.72775374 5.38119362-5.6216933 12.98701406-5.62169418 22.84752534v44.31217268c0 9.86051038 1.89393956 17.4663317 5.62169418 22.84752444 3.72775374 5.38119362 11.18326211 8.05675843 22.30639886 8.05675932h25.55315237c11.99495049 0 19.63083405-2.46512737 22.93771293-7.39538301 3.30687888-4.90019251 5.14069306-12.62626367 5.50144346-23.14815036z m241.37207356-119.91944264c20.32227171 0 34.27128711 4.81000491 41.72679548 14.43001562 7.4855706 9.62001071 11.21332435 23.53896299 11.21332434 41.66667012v138.7085252h-45.63492441v-119.55869137c0-10.76238636-1.74362659-18.60870736-5.23088066-23.50890076-3.48725407-4.93025564-11.21332435-7.39538301-23.20827484-7.395383h-14.61039082v150.46297513h-46.17605l-0.24050055-150.46297513h-13.04713943c-11.12313675 0-18.54858288 2.70562793-22.30639886 8.05675842-3.72775374 5.38119362-5.59163105 12.98701406-5.59163105 22.84752534v119.55869137h-45.90548721v-138.7085252c0-18.81914567 3.90812893-32.85834779 11.72438769-42.14767035 7.81625876-9.31938479 21.82539863-13.9490154 41.99735828-13.94901539h115.28981204zM244.88886589 637.36076074h48.70130273v48.70130274H244.88886589v-48.70130274z" p-id="7480" fill="#38ACD2"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
1
src/assets/img/entity-symbol2/domain.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688290376101" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8107" xmlns:xlink="http://www.w3.org/1999/xlink" width="36" height="36"><path d="M512 61.06201172a450.93798828 450.93798828 0 1 1 0 901.87597656 450.93798828 450.93798828 0 0 1 0-901.87597656z m0 45.09379883a405.84418945 405.84418945 0 1 0 0 811.6883789 405.84418945 405.84418945 0 0 0 0-811.6883789z" p-id="8108" fill="#778391"></path><path d="M229.64344446 586.23133044l15.95626722-52.586307c4.64812962-15.19314186 8.18625866-30.6637832 10.54501134-46.41192491h0.69375048c3.1912538 18.3150199 6.17438209 31.77378466 10.12876124 46.48129978l15.05439124 52.51693213h46.82817591l49.11755284-149.36453686h-48.77067761l-13.73626514 59.24631408c-3.60750391 17.06626868-6.93750745 33.855037-9.22688438 50.99068056h-0.69375136a864.41343565 864.41343565 0 0 0-11.79376257-50.64380531l-15.95626721-59.59318933h-39.33566772l-17.06626869 61.39694129c-3.88500427 14.63814112-8.46375903 31.70440892-11.79376256 48.84005335h-0.69375049A890.56783897 890.56783897 0 0 0 199.81216237 497.84748474l-12.7650143-61.05006603h-50.78255506l46.55067554 149.36453685h46.82817591zM570.27506324 496.04373279c-3.53812904 17.20501843-6.86813258 33.99378674-9.1575104 51.06005543h-0.69375047c-3.1912538-17.13564355-7.49250818-33.855037-11.79376257-50.64380531l-15.95626721-59.59318933H493.26872999l-17.06626869 61.39694129c-3.88500427 14.63814112-8.46375903 31.77378466-11.79376256 48.84005335h-0.69375137a904.30410413 904.30410413 0 0 0-9.08813463-49.18692861l-12.83438917-61.05006603h-50.78255417l46.48129978 149.29516199h46.89755078l16.09501783-52.51693213c4.57875475-15.26251673 8.11688379-30.73315807 10.40626074-46.48130068h0.69375136c3.33000354 18.38439477 6.24375697 31.84315955 10.19813611 46.48130068l15.05439124 52.51693212h46.82817502l49.11755373-149.29516198H584.15007813l-13.73626514 59.24631408zM825.22846423 496.04373279c-3.60750391 17.20501843-6.93750745 33.99378674-9.15751039 51.06005543h-0.69375048c-3.26062867-17.13564355-7.56188305-33.855037-11.79376256-50.64380531l-16.02564208-59.59318933h-39.33566773l-16.99689381 61.39694129a710.40076917 710.40076917 0 0 0-11.79376257 48.84005335h-0.69375049a893.96721827 893.96721827 0 0 0-9.15751038-49.18692861l-12.76501342-61.05006603H645.89389464l46.55067554 149.29516199h46.82817591l16.09501784-52.51693213a328.14410573 328.14410573 0 0 0 10.47563559-46.48130068h0.69375136c3.26062867 18.38439477 6.24375697 31.84315955 10.12876036 46.48130068l15.05439124 52.51693212h46.82817591l49.1869286-149.29516198h-48.84005337l-13.73626426 59.24631408z" p-id="8109" fill="#778391"></path><path d="M320.17791736 643.11889184c28.65190576 164.34955323 107.87824195 274.72529762 191.82208264 274.72529761 81.30758763 0 158.24454601-103.7157373 189.04707984-259.80965612l2.42812756-12.83438916 44.40004835 7.90875828C715.4077206 835.28784972 623.34699522 962.93798828 512 962.93798828c-109.26574291 0-200.07771705-123.00200805-233.93275317-299.56157396l-2.28937782-12.48751393 44.40004835-7.70063368zM512 61.06201172c109.40449353 0 200.14709193 123.14075868 234.00212804 299.83907432l2.28937782 12.48751393-44.40004834 7.70063369C675.10080202 216.67030556 595.94384069 106.15581055 512 106.15581055c-82.07071387 0-159.56267298 105.58886413-189.81020519 263.62528552l-2.28937782 12.69563854-44.40004834-7.63125792C307.06602784 190.65465198 399.7511288 61.06201172 512 61.06201172z" p-id="8110" fill="#778391"></path><path d="M549.60129065 647.28139648V962.93798828h-60.14819006V647.28139648h60.14819006z m0-586.21938476v315.6565918h-60.14819006V61.06201172h60.14819006z" p-id="8111" fill="#778391"></path><path d="M151.24960938 241.43720703h721.50078124v45.09379883H151.24960938V241.43720703z m0 496.03178711h721.50078124v45.09379883H151.24960938v-45.09379883z" p-id="8112" fill="#778391"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
src/assets/img/entity-symbol2/ip-colored.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687770782238" class="icon" viewBox="0 0 1109 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7446" width="35.7392578125" height="33" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M306.07165232 286.53100586h88.45900173v402.31184159H306.07165232V286.53100586z m254.70480646 258.08684225h92.9683825c25.1773713 0 46.59692575-3.68265995 64.25866333-10.97282467 17.66173758-7.36532077 32.01659717-16.9853306 43.06457788-29.01034421 11.12313675-12.02501272 19.1648645-25.85377829 24.27549445-41.48629492a152.94313406 152.94313406 0 0 0 0-95.44854056 111.6071521 111.6071521 0 0 0-24.27549445-41.18566989 120.25012991 120.25012991 0 0 0-43.06457788-29.01034333A167.59861869 167.59861869 0 0 0 653.74484128 286.53100586H472.31745703v402.31184159h88.45900175v-144.30015625z m0-189.39395508h68.7680432c10.14610474 0 19.84127148 0.75156302 29.31096924 2.25468995a68.39226126 68.39226126 0 0 1 24.80158936 8.79329077 47.72427072 47.72427072 0 0 1 17.13564355 18.33814456 64.48413233 64.48413233 0 0 1 6.46344479 30.96440824c0 12.77657663-2.1795339 23.07299344-6.46344479 30.96440911a47.6491138 47.6491138 0 0 1-17.21079959 18.33814456 68.09163623 68.09163623 0 0 1-24.80158936 8.71813474c-9.39454172 1.50312692-19.08970846 2.25468994-29.31096923 2.25468994H560.85161569V355.29904907z" p-id="7447" fill="#7E9F54"></path><path d="M997.43474439 61.06201172H101.72158671C79.2498442 61.06201172 61.06201172 80.60265817 61.06201172 104.65268362v814.69463276c0 24.05002634 18.18783249 43.5906719 40.65957499 43.5906719h895.71315768c22.47174337 0 40.65957499-19.54064646 40.65957497-43.5906719V104.65268362c0-24.05002634-18.18783249-43.5906719-40.65957497-43.5906719z m-20.36736551 835.73840524H122.0889531V126.44802001h854.97842578v770.35239695z" p-id="7448" fill="#7E9F54"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
1
src/assets/img/entity-symbol2/ip.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688290403407" class="icon" viewBox="0 0 1109 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8307" xmlns:xlink="http://www.w3.org/1999/xlink" width="38.98828125" height="36"><path d="M306.07165232 286.53100586h88.45900173v402.31184159H306.07165232V286.53100586z m254.70480646 258.08684225h92.9683825c25.1773713 0 46.59692575-3.68265995 64.25866333-10.97282467 17.66173758-7.36532077 32.01659717-16.9853306 43.06457788-29.01034421 11.12313675-12.02501272 19.1648645-25.85377829 24.27549445-41.48629492a152.94313406 152.94313406 0 0 0 0-95.44854056 111.6071521 111.6071521 0 0 0-24.27549445-41.18566989 120.25012991 120.25012991 0 0 0-43.06457788-29.01034333A167.59861869 167.59861869 0 0 0 653.74484128 286.53100586H472.31745703v402.31184159h88.45900175v-144.30015625z m0-189.39395508h68.7680432c10.14610474 0 19.84127148 0.75156302 29.31096924 2.25468995a68.39226126 68.39226126 0 0 1 24.80158936 8.79329077 47.72427072 47.72427072 0 0 1 17.13564355 18.33814456 64.48413233 64.48413233 0 0 1 6.46344479 30.96440824c0 12.77657663-2.1795339 23.07299344-6.46344479 30.96440911a47.6491138 47.6491138 0 0 1-17.21079959 18.33814456 68.09163623 68.09163623 0 0 1-24.80158936 8.71813474c-9.39454172 1.50312692-19.08970846 2.25468994-29.31096923 2.25468994H560.85161569V355.29904907z" p-id="8308" fill="#778391"></path><path d="M997.43474439 61.06201172H101.72158671C79.2498442 61.06201172 61.06201172 80.60265817 61.06201172 104.65268362v814.69463276c0 24.05002634 18.18783249 43.5906719 40.65957499 43.5906719h895.71315768c22.47174337 0 40.65957499-19.54064646 40.65957497-43.5906719V104.65268362c0-24.05002634-18.18783249-43.5906719-40.65957497-43.5906719z m-20.36736551 835.73840524H122.0889531V126.44802001h854.97842578v770.35239695z" p-id="8309" fill="#778391"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -15,9 +15,9 @@
|
||||
allow-create
|
||||
filterable
|
||||
size="mini"
|
||||
v-model="meta.column.name"
|
||||
v-model="meta.column.label"
|
||||
ref="columnSelect"
|
||||
:placeholder="meta.column.name || ''"
|
||||
:placeholder="meta.column.label || ''"
|
||||
@blur="columnBlur(meta, index)"
|
||||
@change="(value) => selectColumn(value, meta)"
|
||||
>
|
||||
@@ -25,7 +25,7 @@
|
||||
v-for="(column, index) in columnList"
|
||||
:key="index"
|
||||
:label="column.label"
|
||||
:value="column.name"
|
||||
:value="column.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
@@ -75,13 +75,20 @@
|
||||
</div>
|
||||
<div class="tag-search__add" @click="addCondition">{{$t('entities.advancedSearch.add')}}</div>
|
||||
<div class="search__suffixes search__suffixes--tag-mode">
|
||||
<div class="search__suffix" @click="changeMode">
|
||||
<!-- 新版实体列表改版,后续记得解开-->
|
||||
<!-- <div class="search__suffix" style="margin-right: 12px" @click="changeMode">-->
|
||||
<i class="cn-icon cn-icon-search-normal"></i>
|
||||
<div class="search__suffix" style="margin-right: 12px">
|
||||
<el-popover
|
||||
popper-class="my-popper-class"
|
||||
placement="top"
|
||||
:popper-style="{border: '1px red solid'}"
|
||||
trigger="hover"
|
||||
:content="$t('entity.switchToBasicSearch')"
|
||||
>
|
||||
<template #reference>
|
||||
<i class="cn-icon cn-icon-search-normal" @click="changeMode"></i>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="search__suffix" @click="search">
|
||||
<!-- <div class="search__suffix new-search__suffix" @click="search">-->
|
||||
<div class="search__suffix new-search__suffix" @click="search">
|
||||
<i class="el-icon-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -157,6 +164,18 @@ export default {
|
||||
} else {
|
||||
this.metaList.splice(index - 1, 2)
|
||||
}
|
||||
|
||||
if (this.metaList.length > 0) {
|
||||
const parser = new Parser(this.columnList)
|
||||
const errorList = parser.validateMeta(this.metaList)
|
||||
if (_.isEmpty(errorList)) {
|
||||
this.reloadUrl({ q: parser.parseMeta(this.metaList).q })
|
||||
}
|
||||
} else {
|
||||
const routeQuery = this.$route.query
|
||||
delete routeQuery.q
|
||||
this.reloadUrl(routeQuery, 'cleanOldParams')
|
||||
}
|
||||
},
|
||||
// 选择搜索条件的事件
|
||||
selectColumn (value, meta) {
|
||||
@@ -168,7 +187,7 @@ export default {
|
||||
meta.resetValue()
|
||||
} else {
|
||||
const selectedColumn = this.columnList.find(column => {
|
||||
return column.name === value
|
||||
return column.label === value
|
||||
})
|
||||
meta.column.label = selectedColumn.label
|
||||
meta.column.type = selectedColumn.type
|
||||
@@ -194,7 +213,7 @@ export default {
|
||||
},
|
||||
columnBlur (meta, index) {
|
||||
setTimeout(() => {
|
||||
meta.column.name = meta.column.name.replace(/"/g, '')
|
||||
meta.column.label = meta.column.label.replace(/"/g, '')
|
||||
meta.column.isEditing = false
|
||||
if (meta.isEmpty()) {
|
||||
if (this.metaList.length > 1) {
|
||||
@@ -295,7 +314,7 @@ export default {
|
||||
// 判断是否是用户自己添加的内容,用于判断是否是全局搜索
|
||||
isCustomized (value) {
|
||||
return !this.columnList.some(meta => {
|
||||
return meta.name === value
|
||||
return meta.label === value
|
||||
})
|
||||
},
|
||||
enterSearch () {
|
||||
@@ -352,10 +371,10 @@ export default {
|
||||
addParams (params) {
|
||||
params.forEach(param => {
|
||||
const column = this.columnList.find(column => {
|
||||
return column.name === param.column
|
||||
return column.label === param.column
|
||||
})
|
||||
const meta = new Meta()
|
||||
meta.column.name = param.column
|
||||
meta.column.label = param.column
|
||||
meta.column.type = column ? column.type : columnType.string
|
||||
meta.column.label = column ? column.label : param.column
|
||||
meta.operator.value = '='
|
||||
@@ -369,16 +388,16 @@ export default {
|
||||
changeParams (params) {
|
||||
params.forEach(param => {
|
||||
const oldColumn = this.columnList.find(column => {
|
||||
return column.name === param.oldParam.column
|
||||
return column.label === param.oldParam.column
|
||||
})
|
||||
const newColumn = this.columnList.find(column => {
|
||||
return column.name === param.newParam.column
|
||||
return column.label === param.newParam.column
|
||||
})
|
||||
const meta = this.metaList.find(m => m.column && m.column.name === oldColumn.name && m.operator.value === param.oldParam.operator && m.value.value === this.handleValue(param.oldParam.value, oldColumn, param.oldParam.operator))
|
||||
const meta = this.metaList.find(m => m.column && m.column.label === oldColumn.label && m.operator.value === param.oldParam.operator && m.value.value === this.handleValue(param.oldParam.value, oldColumn, param.oldParam.operator))
|
||||
if (meta) {
|
||||
meta.column.name = newColumn.name
|
||||
meta.column.label = newColumn.label
|
||||
meta.column.type = newColumn.type
|
||||
meta.column.label = newColumn.label ? newColumn.label : newColumn.name
|
||||
meta.column.label = newColumn.label ? newColumn.label : newColumn.label
|
||||
meta.operator.value = param.newParam.operator
|
||||
meta.value.value = this.handleValue(param.newParam.value, newColumn, param.newParam.operator)
|
||||
meta.value.label = meta.value.value
|
||||
@@ -388,9 +407,9 @@ export default {
|
||||
removeParams (params) {
|
||||
params.forEach(param => {
|
||||
const column = this.columnList.find(c => {
|
||||
return c.name === param.column
|
||||
return c.label === param.column
|
||||
})
|
||||
const metaIndex = this.metaList.findIndex(m => m.column && m.column.name === param.column && m.operator.value === param.operator && m.value.value === this.handleValue(param.value, column, param.operator))
|
||||
const metaIndex = this.metaList.findIndex(m => m.column && m.column.label === param.column && m.operator.value === param.operator && m.value.value === this.handleValue(param.value, column, param.operator))
|
||||
// 不是在首位,则删除时顺带删除前一个index(and或or),否则顺带删除后一个index
|
||||
if (metaIndex > 0) {
|
||||
this.metaList.splice(metaIndex - 1, 2)
|
||||
@@ -440,20 +459,22 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--// 新版实体列表改版,后续记得解开-->
|
||||
<!--<style lang="scss">-->
|
||||
<!--.new-search__suffix {-->
|
||||
<!-- width: 41px;-->
|
||||
<!-- height: 41px;-->
|
||||
<!-- line-height: 41px;-->
|
||||
<!-- background: #38ACD2;-->
|
||||
<!-- text-align: center;-->
|
||||
<!-- margin-top: -10px;-->
|
||||
<!-- margin-right: -10px;-->
|
||||
<style lang="scss">
|
||||
.new-search__suffix {
|
||||
width: 41px;
|
||||
height: 41px;
|
||||
line-height: 41px;
|
||||
background: #38ACD2;
|
||||
text-align: center;
|
||||
margin-top: -10px;
|
||||
margin-right: -10px;
|
||||
|
||||
<!-- .el-icon-search {-->
|
||||
<!-- color: #fff !important;-->
|
||||
<!-- margin-top: 9px !important;-->
|
||||
<!-- }-->
|
||||
<!--}-->
|
||||
<!--</style>-->
|
||||
.el-icon-search {
|
||||
color: #fff !important;
|
||||
margin-top: 9px !important;
|
||||
}
|
||||
}
|
||||
.my-popper-class .el-popper__arrow {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,14 +3,22 @@
|
||||
ref="textSearch"
|
||||
></textarea>
|
||||
<div class="search__suffixes search__suffixes--text-mode">
|
||||
<div class="search__suffix" @click="changeMode">
|
||||
<i class="cn-icon cn-icon-search-advance"></i>
|
||||
<div class="search__suffix">
|
||||
<el-popover
|
||||
popper-class="my-popper-class"
|
||||
placement="top"
|
||||
trigger="hover"
|
||||
:content="$t('entity.switchToAdvancedSearch')"
|
||||
>
|
||||
<template #reference>
|
||||
<i class="cn-icon cn-icon-filter" @click="changeMode"></i>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
<!-- <div class="search__suffix-close" @click="cleanParams">-->
|
||||
<!-- <i class="el-icon-error"></i>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="search__suffix new-search__suffix" @click="search">-->
|
||||
<div class="search__suffix" @click="search">
|
||||
<div class="search__suffix-close" @click="cleanParams">
|
||||
<i class="el-icon-error"></i>
|
||||
</div>
|
||||
<div class="search__suffix new-search__suffix" @click="search">
|
||||
<i class="el-icon-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,9 +51,12 @@ export default {
|
||||
},
|
||||
emits: ['changeMode', 'search'],
|
||||
methods: {
|
||||
// cleanParams () {
|
||||
// toRaw(this.codeMirror).setValue('')
|
||||
// },
|
||||
cleanParams () {
|
||||
toRaw(this.codeMirror).setValue('')
|
||||
const routeQuery = this.$route.query
|
||||
delete routeQuery.q
|
||||
this.reloadUrl(routeQuery, 'cleanOldParams')
|
||||
},
|
||||
initCodeMirror () {
|
||||
this.codeMirror = CodeMirror.fromTextArea(this.$refs.textSearch, {
|
||||
mode: {
|
||||
@@ -110,7 +121,7 @@ export default {
|
||||
addParams (params) {
|
||||
let current = this.codeMirror.getValue()
|
||||
params.forEach(param => {
|
||||
const column = this.columnList.find(c => c.name === param.column)
|
||||
const column = this.columnList.find(c => c.label === param.column)
|
||||
current = `${current ? current + ' AND ' : ''}${param.column}${handleOperatorSpace(param.operator)}${this.handleValue(param.value, column, param.operator)}`
|
||||
})
|
||||
toRaw(this.codeMirror).setValue(current.trim())
|
||||
@@ -118,7 +129,7 @@ export default {
|
||||
removeParams (params) {
|
||||
let current = this.codeMirror.getValue()
|
||||
params.forEach(param => {
|
||||
const column = this.columnList.find(c => c.name === param.column)
|
||||
const column = this.columnList.find(c => c.label === param.column)
|
||||
// 将对应内容替换为空串
|
||||
const sqlPiece = `${param.column}${handleOperatorSpace(param.operator)}${this.handleValue(param.value, column, param.operator)}`.trim()
|
||||
const sqlPieceWithConnection = [` AND ${sqlPiece}`, ` OR ${sqlPiece}`, `${sqlPiece} AND `, `${sqlPiece} OR `, sqlPiece]
|
||||
@@ -131,8 +142,8 @@ export default {
|
||||
changeParams (params) {
|
||||
let current = this.codeMirror.getValue()
|
||||
params.forEach(param => {
|
||||
const oldColumn = this.columnList.find(c => c.name === param.oldParam.column)
|
||||
const newColumn = this.columnList.find(c => c.name === param.newParam.column)
|
||||
const oldColumn = this.columnList.find(c => c.label === param.oldParam.column)
|
||||
const newColumn = this.columnList.find(c => c.label === param.newParam.column)
|
||||
// 将oldParam内容替换为newParam
|
||||
const oldSqlPiece = `${param.oldParam.column}${handleOperatorSpace(param.oldParam.operator)}${this.handleValue(param.oldParam.value, oldColumn, param.oldParam.operator)}`.trim()
|
||||
const newSqlPiece = `${param.newParam.column}${handleOperatorSpace(param.newParam.operator)}${this.handleValue(param.newParam.value, newColumn, param.newParam.operator)}`.trim()
|
||||
@@ -166,9 +177,18 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
// 如果地址栏包含参数q,则将参数q回显到搜索栏内
|
||||
const { q } = this.$route.query
|
||||
let { q } = this.$route.query
|
||||
this.initCodeMirror()
|
||||
if (q) {
|
||||
// 为避免地址栏任意输入导致全查询的q带QUERY,解析时不识别导致的语法错误
|
||||
// 如地址栏输入116.178.222.171,此时的q很长,刷新界面时需要把q里的116.178.222.171拿出来进行搜索
|
||||
if (q.indexOf('QUERY') > -1) {
|
||||
const strList = q.split(' ')
|
||||
if (strList.length > 0) {
|
||||
// 此时strList[1]为ip_addr:116.178.222.171,获取116.178.222.171
|
||||
q = strList[1].slice(8)
|
||||
}
|
||||
}
|
||||
toRaw(this.codeMirror).setValue(q)
|
||||
}
|
||||
|
||||
@@ -180,28 +200,28 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--<style lang="scss">-->
|
||||
<!--.search__suffix-close {-->
|
||||
<!-- .el-icon-error {-->
|
||||
<!-- font-size: 17px;-->
|
||||
<!-- color: #C4C4C4;-->
|
||||
<!-- margin: 0 12px;-->
|
||||
<!-- cursor: pointer;-->
|
||||
<!-- }-->
|
||||
<!--}-->
|
||||
<style lang="scss">
|
||||
.search__suffix-close {
|
||||
.el-icon-error {
|
||||
font-size: 17px;
|
||||
color: #C4C4C4;
|
||||
margin: 0 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
<!--.new-search__suffix {-->
|
||||
<!-- width: 41px;-->
|
||||
<!-- height: 41px;-->
|
||||
<!-- line-height: 41px;-->
|
||||
<!-- background: #38ACD2;-->
|
||||
<!-- text-align: center;-->
|
||||
<!-- margin-top: -10px;-->
|
||||
<!-- margin-right: -10px;-->
|
||||
.new-search__suffix {
|
||||
width: 41px;
|
||||
height: 41px;
|
||||
line-height: 41px;
|
||||
background: #38ACD2;
|
||||
text-align: center;
|
||||
margin-top: -10px;
|
||||
margin-right: -10px;
|
||||
|
||||
<!-- .el-icon-search {-->
|
||||
<!-- color: #fff !important;-->
|
||||
<!-- margin-top: 9px !important;-->
|
||||
<!-- }-->
|
||||
<!--}-->
|
||||
<!--</style>-->
|
||||
.el-icon-search {
|
||||
color: #fff !important;
|
||||
margin-top: 9px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class Meta {
|
||||
|
||||
isEmpty () {
|
||||
if (this.meta === condition) {
|
||||
return _.isEmpty(this.column.name)
|
||||
return _.isEmpty(this.column.label)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
@@ -73,8 +73,8 @@ export default class Meta {
|
||||
isCompleteCondition () {
|
||||
if (this.meta === condition) {
|
||||
return (this.column.type === columnType.fullText)
|
||||
? !_.isEmpty(this.column.name)
|
||||
: !_.isEmpty(this.column.name) && !_.isEmpty(this.operator.value) && (!_.isEmpty(this.value.value) || (_.isNumber(this.value.value) && !_.isNaN(this.value.value)))
|
||||
? !_.isEmpty(this.column.label)
|
||||
: !_.isEmpty(this.column.label) && !_.isEmpty(this.operator.value) && (!_.isEmpty(this.value.value) || (_.isNumber(this.value.value) && !_.isNaN(this.value.value)))
|
||||
} else if (this.meta === connection) {
|
||||
return !!this.value
|
||||
}
|
||||
|
||||
@@ -80,9 +80,9 @@ export default class Parser {
|
||||
str += `${meta.value.toUpperCase()} `
|
||||
} else if (meta.meta === condition) {
|
||||
if (meta.column.type === columnType.fullText) {
|
||||
str += `'${meta.column.name}' `
|
||||
str += `'${meta.column.label}' `
|
||||
} else if (meta.column.type === columnType.array) {
|
||||
str += `${meta.column.name} ${meta.operator.value} (`
|
||||
str += `${meta.column.label} ${meta.operator.value} (`
|
||||
meta.value.value.forEach((s, j) => {
|
||||
str += `'${s}'`
|
||||
if (j < meta.value.value.length) {
|
||||
@@ -93,13 +93,13 @@ export default class Parser {
|
||||
str += ') '
|
||||
} else if (meta.column.type === columnType.string) {
|
||||
if (meta.operator.value.toLowerCase().indexOf('like') > -1 || meta.operator.value.toLowerCase().indexOf('in') > -1) {
|
||||
str += `${meta.column.name} ${meta.operator.value} '${meta.value.value}' `
|
||||
str += `${meta.column.label} ${meta.operator.value} '${meta.value.value}' `
|
||||
} else {
|
||||
str += `${meta.column.name}${meta.operator.value}'${meta.value.value}' `
|
||||
str += `${meta.column.label}${meta.operator.value}'${meta.value.value}' `
|
||||
}
|
||||
} else if (meta.column.type === columnType.number) {
|
||||
if (_.isNumber(Number(meta.value.value))) {
|
||||
str += `${meta.column.name}${meta.operator.value}${meta.value.value} `
|
||||
str += `${meta.column.label}${meta.operator.value}${meta.value.value} `
|
||||
} else {
|
||||
this.errorList.push(new ParserError(i, errorTypes.typeError, errorDesc.typeError.number))
|
||||
return
|
||||
@@ -125,11 +125,11 @@ export default class Parser {
|
||||
if (meta.column.type === columnType.fullText) {
|
||||
str += "QUERY('"
|
||||
this.columnList.forEach(column => {
|
||||
str += `${column.name}:${meta.column.name} `
|
||||
str += `${column.label}:${meta.column.label} `
|
||||
})
|
||||
str += "') "
|
||||
} else if (meta.column.type === columnType.array) {
|
||||
str += `${meta.column.name} ${meta.operator.value} (`
|
||||
str += `${meta.column.label} ${meta.operator.value} (`
|
||||
meta.value.value.forEach((s, j) => {
|
||||
str += `'${s}'`
|
||||
if (j < meta.value.value.length) {
|
||||
@@ -140,13 +140,13 @@ export default class Parser {
|
||||
str += ') '
|
||||
} else if (meta.column.type === columnType.string) {
|
||||
if (meta.operator.value.toLowerCase().indexOf('like') > -1 || meta.operator.value.toLowerCase().indexOf('in') > -1) {
|
||||
str += `${meta.column.name} ${meta.operator.value} '${meta.value.value}' `
|
||||
str += `${meta.column.label} ${meta.operator.value} '${meta.value.value}' `
|
||||
} else {
|
||||
str += `${meta.column.name}${meta.operator.value}'${meta.value.value}' `
|
||||
str += `${meta.column.label}${meta.operator.value}'${meta.value.value}' `
|
||||
}
|
||||
} else if (meta.column.type === columnType.number) {
|
||||
if (_.isNumber(Number(meta.value.value))) {
|
||||
str += `${meta.column.name}${meta.operator.value}${meta.value.value} `
|
||||
str += `${meta.column.label}${meta.operator.value}${meta.value.value} `
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -566,12 +566,12 @@ export default class Parser {
|
||||
// 前面是连接符或空,后面是操作符,不在单引号内,则是key
|
||||
// 前面是连接符或操作符或空后面是连接符或空,或在单引号内,是value
|
||||
if (isInApostrophe) {
|
||||
if (meta.column.name) {
|
||||
if (meta.column.label) {
|
||||
meta.value.value = token.value
|
||||
meta.column.type = columnType.string
|
||||
} else {
|
||||
meta.column.type = columnType.fullText
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
}
|
||||
} else {
|
||||
let isColumn = true
|
||||
@@ -579,14 +579,14 @@ export default class Parser {
|
||||
if (prevToken) {
|
||||
if (prevToken.type === types.connection && [types.commonOperator, types.letterOperator].indexOf(nextToken.type) > -1) {
|
||||
meta.column.type = columnType.string
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
} else {
|
||||
isColumn = false
|
||||
}
|
||||
} else {
|
||||
if ([types.commonOperator, types.letterOperator].indexOf(nextToken.type) > -1) {
|
||||
meta.column.type = columnType.string
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
} else {
|
||||
isColumn = false
|
||||
}
|
||||
@@ -604,7 +604,7 @@ export default class Parser {
|
||||
meta.column.type = columnType.string
|
||||
} else if (prevToken && (!prevToken.prevToken || prevToken.prevToken.type === types.connection)) {
|
||||
meta.column.type = columnType.fullText
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
} else {
|
||||
errorList.push(new ParserError(token.end, errorTypes.syntaxError, errorDesc.syntaxError.unexpectedString))
|
||||
break
|
||||
@@ -631,14 +631,14 @@ export default class Parser {
|
||||
meta.value.value = token.value
|
||||
}
|
||||
} else if (prevToken.type === types.connection) {
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
meta.column.type = columnType.fullText
|
||||
} else {
|
||||
errorList.push(new ParserError(token.end, errorTypes.syntaxError, errorDesc.syntaxError.unexpectedString))
|
||||
break
|
||||
}
|
||||
} else {
|
||||
meta.column.name = token.value
|
||||
meta.column.label = token.value
|
||||
meta.column.type = columnType.fullText
|
||||
}
|
||||
} else {
|
||||
@@ -707,10 +707,10 @@ export default class Parser {
|
||||
if (meta.column.type === columnType.fullText) {
|
||||
meta.operator.show = false
|
||||
meta.value.show = false
|
||||
meta.column.label = meta.column.name
|
||||
// meta.column.label = meta.column.name
|
||||
metaList.push(meta)
|
||||
} else {
|
||||
const column = this.columnList.find(c => c.name === meta.column.name)
|
||||
const column = this.columnList.find(c => c.label === meta.column.label)
|
||||
if (column) {
|
||||
meta.operator.show = true
|
||||
meta.value.show = true
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
style="position: absolute;top: -53px;left: -536px;"
|
||||
:clearable="false"
|
||||
:default-time="defaultTime"
|
||||
:unlink-panels="true"
|
||||
type="datetimerange"
|
||||
@change="timeArrChange"
|
||||
/>
|
||||
@@ -251,6 +252,7 @@ export default {
|
||||
* 重置时间,将时间存入缓存,并触发方法请求接口刷新界面
|
||||
*/
|
||||
const returnValue = () => {
|
||||
store.commit('setTimeFilter', { startTime: myStartTime.value, endTime: myEndTime.value, range: dateRangeValue.value })
|
||||
cancelHttp()
|
||||
rangeHistory.value.unshift({
|
||||
start: myStartTime.value,
|
||||
|
||||
@@ -20,10 +20,7 @@ export default {
|
||||
entityDetectionStyle () {
|
||||
const route = this.$route.name !== undefined ? this.$route.name : this.$route
|
||||
if (listScrollPath.indexOf(route.path) > -1) {
|
||||
// 新版实体列表改版,后续记得解开
|
||||
const style = route.path === listScrollPath[0] ? 'overflow:auto;background-color: #EFF2F5;' : 'overflow:auto;'
|
||||
// const style = 'overflow:auto;'
|
||||
return style
|
||||
return 'overflow:auto;'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -192,26 +192,27 @@ import { get, put } from '@/utils/http'
|
||||
import {
|
||||
curTabState,
|
||||
entityType,
|
||||
fromRoute,
|
||||
networkTable,
|
||||
operationType,
|
||||
storageKey,
|
||||
wholeScreenRouterMapping,
|
||||
fromRoute
|
||||
wholeScreenRouterMapping
|
||||
} from '@/utils/constants'
|
||||
import { api } from '@/utils/api'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
combineDrilldownTableWithUserConfig,
|
||||
combineTabList,
|
||||
getDefaultCurTab,
|
||||
getTabList,
|
||||
overwriteUrl,
|
||||
urlParamsHandler,
|
||||
combineDrilldownTableWithUserConfig,
|
||||
getDnsMapData,
|
||||
handleSpecialValue
|
||||
getTabList,
|
||||
handleSpecialValue,
|
||||
overwriteUrl,
|
||||
urlParamsHandler
|
||||
} from '@/utils/tools'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
import _ from 'lodash'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'Header',
|
||||
@@ -223,6 +224,13 @@ export default {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const validateFiveLength = (rule, value, callback) => {
|
||||
if (value.length < 5) {
|
||||
callback(new Error(this.$t('validate.atLeastFive')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
username: localStorage.getItem(storageKey.username),
|
||||
language: localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : 'en',
|
||||
@@ -243,11 +251,17 @@ export default {
|
||||
required: true,
|
||||
message: this.$t('validate.required'),
|
||||
trigger: 'blur'
|
||||
}, {
|
||||
validator: validateFiveLength,
|
||||
trigger: 'change'
|
||||
}],
|
||||
newPwd2: [{
|
||||
required: true,
|
||||
message: this.$t('validate.required'),
|
||||
trigger: 'blur'
|
||||
}, {
|
||||
validator: validateFiveLength,
|
||||
trigger: 'change'
|
||||
}, {
|
||||
validator: passwordComparison,
|
||||
trigger: 'blur'
|
||||
@@ -359,6 +373,11 @@ export default {
|
||||
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
|
||||
}
|
||||
}
|
||||
},
|
||||
'$store.getters.timeFilter': function (newVal) {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
this.chartTimeFilter = newVal
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
@@ -375,16 +394,24 @@ export default {
|
||||
this.initDropdownList()
|
||||
},
|
||||
setup () {
|
||||
const dateRangeValue = 60
|
||||
const {
|
||||
startTime,
|
||||
endTime
|
||||
} = getNowTime(dateRangeValue)
|
||||
const chartTimeFilter = ref({
|
||||
startTime,
|
||||
endTime,
|
||||
dateRangeValue
|
||||
})
|
||||
const { query } = useRoute()
|
||||
// 获取url携带的range、startTime、endTime
|
||||
const rangeParam = query.range
|
||||
const startTimeParam = query.startTime
|
||||
const endTimeParam = query.endTime
|
||||
// 若url携带了,使用携带的值,否则使用默认值。
|
||||
|
||||
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
|
||||
const chartTimeFilter = ref({ dateRangeValue })
|
||||
if (!startTimeParam || !endTimeParam) {
|
||||
const { startTime, endTime } = getNowTime(60)
|
||||
chartTimeFilter.value.startTime = startTime
|
||||
chartTimeFilter.value.endTime = endTime
|
||||
} else {
|
||||
chartTimeFilter.value.startTime = parseInt(startTimeParam)
|
||||
chartTimeFilter.value.endTime = parseInt(endTimeParam)
|
||||
}
|
||||
|
||||
return {
|
||||
chartTimeFilter,
|
||||
entityType // 所有entity类型,用于header下拉框选择
|
||||
@@ -592,6 +619,15 @@ export default {
|
||||
this.showChangePin = false
|
||||
} else if (res.code === 518005) {
|
||||
this.$message.error('密码错误')
|
||||
} else {
|
||||
this.$message.error(res.message)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
if (e.response.data && e.response.data.message) {
|
||||
this.$message.error(e.response.data.message)
|
||||
} else {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -376,7 +376,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -386,7 +386,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -64,6 +64,18 @@ export default {
|
||||
detail: Boolean
|
||||
},
|
||||
data () {
|
||||
const validateName = (rule, value, callback) => {
|
||||
let validate = true
|
||||
const reg = /^[a-zA-Z0-9\u4e00-\u9fa5\u30a1-\u30f6\u3041-\u3093\uFF00-\uFFFF\u4e00-\u9fa5\u0400-\u04FF\s]{2,64}$/
|
||||
validate = reg.test(value)
|
||||
if (value.length < 2) {
|
||||
callback(new Error(this.$t('validate.atLeastTwo')))
|
||||
} else if (!validate) {
|
||||
callback(new Error(this.$t('validate.name')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
editRole: {},
|
||||
url: api.role,
|
||||
@@ -71,7 +83,7 @@ export default {
|
||||
rules: { // 表单校验规则
|
||||
name: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ pattern: /^[a-zA-Z0-9]{2,64}$/, message: this.$t('validate.atLeastTwo') } // 目前仅对长度要求在2-64之间,后续有需求再添加
|
||||
{ validator: validateName, trigger: 'change' }
|
||||
]
|
||||
},
|
||||
menus: [],
|
||||
@@ -174,7 +186,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -184,7 +196,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -132,17 +132,41 @@ export default {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const validateName = (rule, value, callback) => {
|
||||
let validate = true
|
||||
const reg = /^[a-zA-Z0-9\u4e00-\u9fa5\u30a1-\u30f6\u3041-\u3093\uFF00-\uFFFF\u4e00-\u9fa5\u0400-\u04FF\s]{2,64}$/
|
||||
validate = reg.test(value)
|
||||
if (value.length < 2) {
|
||||
callback(new Error(this.$t('validate.atLeastTwo')))
|
||||
} else if (!validate) {
|
||||
callback(new Error(this.$t('validate.name')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const validateUserName = (rule, value, callback) => {
|
||||
let validate = true
|
||||
const reg = /^[a-zA-Z0-9_]{2,64}$/
|
||||
validate = reg.test(value)
|
||||
if (value.length < 2) {
|
||||
callback(new Error(this.$t('validate.atLeastTwo')))
|
||||
} else if (!validate) {
|
||||
callback(new Error(this.$t('validate.userName')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
url: api.user,
|
||||
loginName: localStorage.getItem(storageKey.username),
|
||||
rules: { // 表单校验规则
|
||||
name: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ pattern: /^[a-zA-Z0-9]{2,64}$/, message: this.$t('validate.atLeastTwo') }
|
||||
{ validator: validateName, trigger: 'change' }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ pattern: /^[a-zA-Z0-9]{2,64}$/, message: this.$t('validate.atLeastTwo') }
|
||||
{ validator: validateUserName, trigger: 'change' }
|
||||
],
|
||||
pin: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
@@ -217,7 +241,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -227,7 +251,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { storageKey } from '@/utils/constants'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
import { storageKey, dbTableColumnCustomizeConfigPre } from '@/utils/constants'
|
||||
import { get } from '@/utils/http'
|
||||
export default {
|
||||
props: {
|
||||
customTableTitle: Array, // 自定义的title
|
||||
@@ -70,15 +72,15 @@ export default {
|
||||
return {
|
||||
custom: [],
|
||||
dragIndex: -1,
|
||||
selectList: [],
|
||||
lastIndex: -1
|
||||
selectList: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
/*
|
||||
const localStorageTitle = JSON.parse(localStorage.getItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId))
|
||||
if (localStorageTitle) {
|
||||
localStorage.setItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId, JSON.stringify(localStorageTitle))
|
||||
}
|
||||
} */
|
||||
},
|
||||
watch: {
|
||||
customTableTitle: {
|
||||
@@ -95,19 +97,13 @@ export default {
|
||||
this.selectList = this.custom.filter(item => item.show)
|
||||
// 最少保留一个选项
|
||||
if (this.selectList.length === 1) {
|
||||
let index = -1
|
||||
this.custom.find((item, i) => {
|
||||
index = i
|
||||
return item.prop === this.selectList[0].prop
|
||||
})
|
||||
this.lastIndex = index
|
||||
this.custom[index].disabled = true
|
||||
} else if (this.lastIndex > -1) {
|
||||
const obj = this.custom.find(item => item.prop === this.selectList[0].prop)
|
||||
obj.disabled = true
|
||||
} else if (this.selectList.length > 1) {
|
||||
this.custom.forEach(item => {
|
||||
// 该方案仅用于原始table列表无禁用的情况,目前无原始列表禁用的情况,后续有原始列表禁用的情况再修改
|
||||
item.disabled = false
|
||||
})
|
||||
this.lastIndex = -1
|
||||
}
|
||||
this.save()
|
||||
},
|
||||
@@ -154,10 +150,30 @@ export default {
|
||||
}
|
||||
},
|
||||
// 点击第二个cancel
|
||||
save () {
|
||||
async save () {
|
||||
this.$emit('update', this.custom)
|
||||
localStorage.setItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId, JSON.stringify(this.custom))
|
||||
// this.esc()
|
||||
const userId = localStorage.getItem(storageKey.userId)
|
||||
const tableName = dbTableColumnCustomizeConfigPre + '-' + this.tableId
|
||||
|
||||
const defaultConfigInDb = await indexedDBUtils.selectTable(tableName).get({ id: userId })
|
||||
let fullVersion = ''
|
||||
if (defaultConfigInDb && defaultConfigInDb.version) {
|
||||
const oldVersion = defaultConfigInDb.version
|
||||
if (oldVersion.startsWith(BASE_CONFIG.version)) {
|
||||
const realVersion = Number(oldVersion.substring(BASE_CONFIG.version.length + 1))
|
||||
fullVersion = BASE_CONFIG.version + '.' + (realVersion + 1)
|
||||
} else {
|
||||
fullVersion = BASE_CONFIG.version + '.1'
|
||||
}
|
||||
} else {
|
||||
fullVersion = BASE_CONFIG.version + '.1'
|
||||
}
|
||||
|
||||
await indexedDBUtils.selectTable(tableName).put({
|
||||
id: userId,
|
||||
version: fullVersion,
|
||||
config: _.cloneDeep(this.custom)
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div class="col-resize-area"></div>
|
||||
</template>
|
||||
<template #default="scope" :column="item">
|
||||
<span>{{scope.row[item.prop]}}</span>
|
||||
<span>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
</el-table-column><template v-slot:empty >
|
||||
<div class="table-no-data" v-if="isNoData">
|
||||
|
||||
@@ -43,15 +43,15 @@
|
||||
{{$t('operationLog.state.fail')}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{scope.row[item.prop]}}
|
||||
{{scope.row[item.prop] || '-'}}
|
||||
</template>
|
||||
</span>
|
||||
<span v-else-if="item.prop === 'username'">{{formatUsername(scope.row)}}</span>
|
||||
<span v-else-if="item.prop === 'ctime'">{{dateFormatByAppearance(scope.row[item.prop])}}</span>
|
||||
<template v-else-if="item.prop === 'params' || item.prop === 'response'">
|
||||
<span>{{scope.row[item.prop]}}</span>
|
||||
<span>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template v-slot:empty >
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<span>-</span>
|
||||
</template>
|
||||
</template>
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template v-slot:empty >
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'lastLoginTime'">
|
||||
<template v-if="scope.row[item.prop]">
|
||||
{{dateFormatByAppearance(scope.row[item.prop])}}
|
||||
{{dateFormatByAppearance(scope.row[item.prop]) || '-'}}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>-</span>
|
||||
@@ -60,7 +60,7 @@
|
||||
@change="()=>{statusChange(scope.row)}">
|
||||
</el-switch>
|
||||
</template>
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template v-slot:empty >
|
||||
|
||||
@@ -117,9 +117,7 @@
|
||||
{{ handleTimeRange(scope.row) }}
|
||||
</span>
|
||||
<span v-else-if="item.prop === 'categoryId'">
|
||||
<span v-for="(item, i) in categoryList" :key="i">
|
||||
<span v-if="scope.row.categoryId === item.id">{{ item.name }}</span>
|
||||
</span>
|
||||
<span>{{ getCategoryName(scope.row.categoryId) }}</span>
|
||||
</span>
|
||||
<span v-else-if="item.prop === 'timePlan'">
|
||||
<template v-if="scope.row.config && scope.row.config.isScheduler === 0">
|
||||
@@ -768,6 +766,16 @@ export default {
|
||||
}
|
||||
}
|
||||
this.configCustom = str
|
||||
},
|
||||
getCategoryName (id) {
|
||||
let name = '-'
|
||||
for (let i = 0; i < this.categoryList.length; i++) {
|
||||
if (id === this.categoryList[i].id) {
|
||||
name = this.categoryList[i].name
|
||||
break
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { dbName, dbGeoDataTableName, dbDrilldownTableConfig } from '@/utils/constants'
|
||||
import { dbName, dbGeoDataTableName, dbDrilldownTableConfig, dbUserTableColumnCustomizeConfig, dbRoleTableColumnCustomizeConfig, dbOperationLogTableColumnCustomizeConfig, dbChartTableColumnCustomizeConfig, dbI18nTableColumnCustomizeConfig, dbReportTableColumnCustomizeConfig, dbGalaxySettingTableColumnCustomizeConfig } from '@/utils/constants'
|
||||
import Dexie from 'dexie'
|
||||
/* https://dexie.org/ */
|
||||
|
||||
const db = new Dexie(dbName)
|
||||
db.version(3).stores({
|
||||
db.version(4).stores({
|
||||
[dbGeoDataTableName]: '++name, geo',
|
||||
[dbDrilldownTableConfig]: '++id, config',
|
||||
[dbUserTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbRoleTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbOperationLogTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbChartTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbI18nTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbReportTableColumnCustomizeConfig]: '++id, config',
|
||||
[dbGalaxySettingTableColumnCustomizeConfig]: '++id, config',
|
||||
test: '++id, name'
|
||||
})
|
||||
function selectTable (tableName) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { tableSort } from '@/utils/tools'
|
||||
import { defaultPageSize, fromRoute, position, storageKey } from '@/utils/constants'
|
||||
import { defaultPageSize, fromRoute, position, storageKey, dbTableColumnCustomizeConfigPre } 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 Loading from '@/components/common/Loading'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -104,14 +105,12 @@ export default {
|
||||
if (isAll) {
|
||||
this.searchLabel = null
|
||||
} else if (isClearType) {
|
||||
// this.searchLabel.tagType = ''
|
||||
this.searchLabel.type = ''// 换新接口需要修改的属性名称
|
||||
}
|
||||
if (params) {
|
||||
this.searchLabel = { ...this.searchLabel, ...params }
|
||||
}
|
||||
this.searchLabel = { ...this.searchLabel, ...this.pageObj }
|
||||
//this.tableData = []
|
||||
this.isNoData = false
|
||||
this.toggleLoading(true)
|
||||
delete this.searchLabel.total
|
||||
@@ -123,6 +122,11 @@ export default {
|
||||
if (response.code === 200) {
|
||||
this.tableData = response.data.list
|
||||
this.pageObj.total = response.data.total
|
||||
if (!this.tableData || this.tableData.length === 0) {
|
||||
this.isNoData = true
|
||||
} else {
|
||||
this.isNoData = false
|
||||
}
|
||||
} else {
|
||||
console.error(response)
|
||||
this.isNoData = true
|
||||
@@ -132,13 +136,10 @@ export default {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isNoData = true
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
if (!this.tableData || this.tableData.length === 0) {
|
||||
this.isNoData = true
|
||||
} else {
|
||||
this.isNoData = false
|
||||
}
|
||||
})
|
||||
},
|
||||
del (row) {
|
||||
@@ -216,6 +217,7 @@ export default {
|
||||
},
|
||||
pageSize (val) {
|
||||
this.pageObj.pageSize = val
|
||||
this.pageObj.pageNo = 1
|
||||
localStorage.setItem(storageKey.pageSize + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId, val)
|
||||
this.getTableData()
|
||||
},
|
||||
@@ -261,8 +263,14 @@ export default {
|
||||
if (this.$refs.dataTable.loadingTableId === u.id) { // 列表单个下载
|
||||
return
|
||||
}
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
if (localStorage.getItem(storageKey.s3Enable) == 1) {
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (u.state !== 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
let fileName = ''
|
||||
let url = ''
|
||||
@@ -323,8 +331,14 @@ export default {
|
||||
if (this.$refs.dataTable.loadingPreviewId === u.id) { // 列表单个下载
|
||||
return
|
||||
}
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
if (localStorage.getItem(storageKey.s3Enable) == 1) {
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (u.state !== 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
const params = {
|
||||
id: u.id
|
||||
@@ -395,13 +409,21 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
async mounted () {
|
||||
const pageSize = localStorage.getItem(storageKey.pageSize + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId)
|
||||
if (pageSize && pageSize !== 'undefined') {
|
||||
this.pageObj.pageSize = pageSize
|
||||
}
|
||||
let localStorageTableTitle = localStorage.getItem(storageKey.tableTitle + '-' + localStorage.getItem(storageKey.username) + '-' + this.tableId)
|
||||
localStorageTableTitle = localStorageTableTitle ? JSON.parse(localStorageTableTitle) : this.$refs.dataTable.tableTitle
|
||||
const userId = localStorage.getItem(storageKey.userId)
|
||||
const tableName = dbTableColumnCustomizeConfigPre + '-' + this.tableId
|
||||
let localStorageTableTitle = []
|
||||
if (indexedDBUtils.selectTable(tableName)) {
|
||||
localStorageTableTitle = await indexedDBUtils.selectTable(tableName).get({ id: userId })
|
||||
}
|
||||
|
||||
localStorageTableTitle = localStorageTableTitle && localStorageTableTitle.config
|
||||
? localStorageTableTitle.config
|
||||
: (this.$refs.dataTable && this.$refs.dataTable.tableTitle ? this.$refs.dataTable.tableTitle : [])
|
||||
// this.tools.customTableTitle = this.$refs.dataTable.tableTitle.map((item, index) => { // 修复切换中英文的问题
|
||||
// if (localStorageTableTitle[index]) {
|
||||
// item.show = localStorageTableTitle[index].show
|
||||
|
||||
@@ -19,7 +19,12 @@ export default {
|
||||
this.loadingRelationshipOne = true
|
||||
get(relationshipUrlOne, this.getQueryParams()).then(response => {
|
||||
if (response.code === 200) {
|
||||
const relationshipDataOne = response.data.result
|
||||
const relationshipDataOne = []
|
||||
if (response.data.result.length > 0) {
|
||||
response.data.result.forEach(item => {
|
||||
relationshipDataOne.push({ value: item, show: true })
|
||||
})
|
||||
}
|
||||
// 将请求数据 传入方法中
|
||||
this.relatedServerWidth(relationshipDataOne, refOne, 1)
|
||||
}
|
||||
@@ -30,7 +35,12 @@ export default {
|
||||
this.loadingRelationshipTwo = true
|
||||
get(relationshipUrlTow, this.getQueryParams()).then(response => {
|
||||
if (response.code === 200) {
|
||||
const relationshipDataTwo = response.data.result
|
||||
const relationshipDataTwo = []
|
||||
if (response.data.result.length > 0) {
|
||||
response.data.result.forEach(item => {
|
||||
relationshipDataTwo.push({ value: item, show: true })
|
||||
})
|
||||
}
|
||||
// 将请求数据 传入方法中
|
||||
this.relatedServerWidth(relationshipDataTwo, refTow, 2)
|
||||
}
|
||||
@@ -45,7 +55,7 @@ export default {
|
||||
let flag = true
|
||||
data.forEach((item) => {
|
||||
// 每条数据的宽度
|
||||
const width = getTextRect(item.appName || item.domain || item.ip).width + 67
|
||||
const width = getTextRect(item.value).width + 67
|
||||
if (width > 67 && width !== 0) {
|
||||
sum += width
|
||||
if (flag && sum >= relatedServerWidth && num === 1) {
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.esc(true)
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
this.$message.error(res.msg || res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -451,6 +451,300 @@ if (openMock) {
|
||||
}
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/query/list.*`), 'get', function (requestObj) {
|
||||
const result = {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
total: 3,
|
||||
list: [
|
||||
{ entityValue: '192.168.12.34', entityType: 'ip' },
|
||||
{ entityValue: 'gdbzkz.com', entityType: 'domain' },
|
||||
{ entityValue: 'qqvideo', entityType: 'app' }
|
||||
]
|
||||
}
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/basic.*`), 'get', function (requestObj) {
|
||||
const entityType = getEntityType(requestObj.url)
|
||||
let result = {}
|
||||
switch (entityType) {
|
||||
case ('domain'): {
|
||||
result = {
|
||||
whois: {
|
||||
registrarName: 'Beijing Baidu Company',
|
||||
registrantOrg: 'Beijing Baidu Netcom Science Technology Co., Ltd.',
|
||||
registrantCountry: 'China',
|
||||
email: '信息已设置隐私保护',
|
||||
createDate: 1685329698,
|
||||
expireDate: 1685329698
|
||||
},
|
||||
icp: {
|
||||
icpSiteLicense: '京ICP证030173号',
|
||||
icpCompanyName: '北京百度网讯科技有限公司',
|
||||
icpCompanyType: '企业'
|
||||
},
|
||||
category: {
|
||||
name: '门户网站',
|
||||
group: '互联网',
|
||||
reputationLevel: 'Trustworthy'
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('ip'): {
|
||||
result = {
|
||||
asn: { id: 2, asn: '14061', organization: 'DIGITALOCEAN-ASN - DigitalOcean, LLC, US' },
|
||||
location: {
|
||||
continent: 'North America',
|
||||
country: 'United States',
|
||||
province: 'New York',
|
||||
city: '',
|
||||
lngwgs: '-74.006',
|
||||
latwgs: '40.713',
|
||||
isp: 'dba Omsoft',
|
||||
owner: 'tie net'
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
result = {
|
||||
category: {
|
||||
appName: 'QQ',
|
||||
appId: 333,
|
||||
appCategory: '娱乐',
|
||||
appSubcategory: '聊天',
|
||||
appRisk: '1',
|
||||
appDescription: '聊天社交软件',
|
||||
appLongname: 'Tencent qq',
|
||||
appTechnology: 'socket',
|
||||
appCompany: 'tencent',
|
||||
appCompanyCategory: '互联网'
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/kb/intelligence/tag.*`), 'get', function (requestObj) {
|
||||
const entityType = getEntityType(requestObj.url)
|
||||
let result = {}
|
||||
switch (entityType) {
|
||||
case ('domain'): {
|
||||
result = {
|
||||
malware: {
|
||||
threatType: 'command and control',
|
||||
malwareName: '情报攻击',
|
||||
malwareAlias: '攻击'
|
||||
},
|
||||
darkweb: {
|
||||
nodeType: 'mtproxy'
|
||||
},
|
||||
userDefinedTags: [
|
||||
{
|
||||
id: 1,
|
||||
tagValue: '门户网站'
|
||||
}
|
||||
]
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('ip'): {
|
||||
result = {
|
||||
malware: {
|
||||
threatType: 'command and control',
|
||||
malwareName: 'IcedID',
|
||||
malwareAlias: 'BokBot,IceID'
|
||||
},
|
||||
darkweb: {
|
||||
nodeType: '12p'
|
||||
},
|
||||
psiphon3Ip: {
|
||||
type: 'high',
|
||||
method: 'passive_ml',
|
||||
confidence: 88,
|
||||
confidenceLevel: 'confirmed'
|
||||
},
|
||||
userDefinedTags: [
|
||||
{
|
||||
id: 1,
|
||||
tagValue: '门户网站'
|
||||
}
|
||||
]
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
result = {
|
||||
userDefinedTags: [
|
||||
{
|
||||
id: 1,
|
||||
tagValue: '门户网站'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
tagValue: '新闻软件'
|
||||
}
|
||||
]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/domain/relate.*`), 'get', function (requestObj) {
|
||||
const relateType = getRelateType(requestObj.url)
|
||||
let result = {}
|
||||
switch (relateType) {
|
||||
case ('ip'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['bittorrent', 'qq_web', 'wechat', 'tencent', 'outlook']
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['192.107.175.180', '192.107.175.180', '192.107.175.180', '192.107.175.180', '192.107.175.180']
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/ip/relate.*`), 'get', function (requestObj) {
|
||||
const relateType = getRelateType(requestObj.url)
|
||||
let result = {}
|
||||
switch (relateType) {
|
||||
case ('domain'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['bittorrent', 'qq_web', 'wechat', 'tencent', 'outlook']
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com']
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/app/relate.*`), 'get', function (requestObj) {
|
||||
const relateType = getRelateType(requestObj.url)
|
||||
let result = {}
|
||||
switch (relateType) {
|
||||
case ('ip'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com', 'gdbzkz.com']
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
result = {
|
||||
total: 5,
|
||||
result: ['192.107.175.180', '192.107.175.180', '192.107.175.180', '192.107.175.180', '192.107.175.180']
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/detail/traffic/performance.*`), 'get', function (requestObj) {
|
||||
const result = {
|
||||
resultType: 'object',
|
||||
result: {
|
||||
httpResponseLatencyValue: null,
|
||||
httpResponseLatencyP50: null,
|
||||
httpResponseLatencyP90: null,
|
||||
httpResponseLatencyP99: null,
|
||||
sslConLatencyValue: 191,
|
||||
sslConLatencyP50: 137,
|
||||
sslConLatencyP90: 311,
|
||||
sslConLatencyP99: 1610,
|
||||
establishLatencyValue: 42,
|
||||
establishLatencyP50: 33,
|
||||
establishLatencyP90: 54,
|
||||
establishLatencyP99: 177,
|
||||
sequenceGapLossPercentValue: 0.001,
|
||||
sequenceGapLossPercentP50: 0,
|
||||
sequenceGapLossPercentP90: 0.0038,
|
||||
sequenceGapLossPercentP99: 0.0087,
|
||||
pktRetransPercentValue: 0.0124,
|
||||
pktRetransPercentP50: 0.0096,
|
||||
pktRetransPercentP90: 0.0183,
|
||||
pktRetransPercentP99: 0.0769
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: result
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/overview/active.*`), 'get', function (requestObj) {
|
||||
const data = { domainCount: 755, ipCount: 8373, appCount: 263 }
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: data
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/overview/new.*`), 'get', function (requestObj) {
|
||||
const data = { domainCount: 262, ipCount: 4201, appCount: 43 }
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: data
|
||||
}
|
||||
})
|
||||
Mock.mock(new RegExp(`${urlAndVersion}/entity/explorer/overview/total.*`), 'get', function (requestObj) {
|
||||
const data = { domainCount: 7686274, ipCount: 2169957, appCount: 856 }
|
||||
|
||||
return {
|
||||
msg: 'success',
|
||||
code: 200,
|
||||
data: data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getQuery = (url) => {
|
||||
@@ -467,3 +761,31 @@ const getQuery = (url) => {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const getEntityType = (url) => {
|
||||
let entityType = ''
|
||||
if (url.indexOf('/domain?') > -1) {
|
||||
entityType = 'domain'
|
||||
}
|
||||
if (url.indexOf('/ip?') > -1) {
|
||||
entityType = 'ip'
|
||||
}
|
||||
if (url.indexOf('/app?') > -1) {
|
||||
entityType = 'app'
|
||||
}
|
||||
return entityType
|
||||
}
|
||||
|
||||
const getRelateType = (url) => {
|
||||
let entityType = ''
|
||||
if (url.indexOf('/domains?') > -1) {
|
||||
entityType = 'domain'
|
||||
}
|
||||
if (url.indexOf('/ips?') > -1) {
|
||||
entityType = 'ip'
|
||||
}
|
||||
if (url.indexOf('/apps?') > -1) {
|
||||
entityType = 'app'
|
||||
}
|
||||
return entityType
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ const user = {
|
||||
menuList: [],
|
||||
buttonList: [],
|
||||
roleList: [],
|
||||
drilldownTableConfigList: []
|
||||
drilldownTableConfigList: [],
|
||||
timeFilter: {}
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
@@ -33,6 +34,9 @@ const user = {
|
||||
state.menuList = []
|
||||
state.buttonList = []
|
||||
state.roleList = []
|
||||
},
|
||||
setTimeFilter (state, data) {
|
||||
state.timeFilter = data
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -47,6 +51,9 @@ const user = {
|
||||
},
|
||||
drilldownTableConfigList (state) {
|
||||
return state.drilldownTableConfigList
|
||||
},
|
||||
timeFilter (state) {
|
||||
return state.timeFilter
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -252,7 +252,58 @@ export const api = {
|
||||
openPortOfApp: apiVersion + '/entity/detail/app/relate/ports',
|
||||
basicInfo: apiVersion + '/entity/detail/basic',
|
||||
tags: apiVersion + '/entity/detail/kb/intelligence/tag',
|
||||
informationAggregation: apiVersion + '/entity/detail/kb/intelligence/list'
|
||||
informationAggregation: apiVersion + '/entity/detail/kb/intelligence/list',
|
||||
// 实体关系
|
||||
entityGraph: {
|
||||
basicInfo: apiVersion + '/entity/graph/relation/basic',
|
||||
tags: apiVersion + '/entity/graph/relation/kb/intelligence/tag',
|
||||
relatedEntityCount: apiVersion + '/entity/graph/relation/summaryCount',
|
||||
domainRelatedIp: apiVersion + '/entity/graph/relation/domain/relate/ips',
|
||||
domainRelatedApp: apiVersion + '/entity/graph/relation/domain/relate/apps',
|
||||
domainRelatedSubdomain: apiVersion + '/entity/graph/relation/domain/relate/subdomains',
|
||||
ipRelatedDomain: apiVersion + '/entity/graph/relation/ip/relate/domains',
|
||||
ipRelatedApp: apiVersion + '/entity/graph/relation/ip/relate/apps',
|
||||
appRelatedIp: apiVersion + '/entity/graph/relation/app/relate/ips',
|
||||
appRelatedDomain: apiVersion + '/entity/graph/relation/app/relate/domains'
|
||||
},
|
||||
entityList: {
|
||||
list: apiVersion + '/entity/explorer/query/list', // 实体列表
|
||||
domainBasicInfo: apiVersion + '/entity/explorer/detail/basic/domain', // Domain实体响应结果
|
||||
ipBasicInfo: apiVersion + '/entity/explorer/detail/basic/ip', // ip实体响应
|
||||
appBasicInfo: apiVersion + '/entity/explorer/detail/basic/app', // app实体响应
|
||||
domainTags: apiVersion + '/entity/explorer/detail/kb/intelligence/tag/domain', // Domain实体标签响应结果
|
||||
ipTags: apiVersion + '/entity/explorer/detail/kb/intelligence/tag/ip', // ip实体标签响应结果
|
||||
appTags: apiVersion + '/entity/explorer/detail/kb/intelligence/tag/app', // app实体标签响应结果
|
||||
domainThroughput: apiVersion + '/entity/explorer/detail/traffic/throughput/domain', // 实体流量信息
|
||||
ipThroughput: apiVersion + '/entity/explorer/detail/traffic/throughput/ip', // 实体流量信息
|
||||
appThroughput: apiVersion + '/entity/explorer/detail/traffic/throughput/app', // 实体流量信息
|
||||
domainPerformance: apiVersion + '/entity/explorer/detail/traffic/performance/domain', // domain网络质量
|
||||
ipPerformance: apiVersion + '/entity/explorer/detail/traffic/performance/ip', // ip网络质量
|
||||
appPerformance: apiVersion + '/entity/explorer/detail/traffic/performance/app', // app网络质量
|
||||
domainRelatedApp: apiVersion + '/entity/explorer/detail/domain/relate/apps', // 域名相关app
|
||||
domainRelatedIp: apiVersion + '/entity/explorer/detail/domain/relate/ips', // 域名相关ip
|
||||
appRelatedDomain: apiVersion + '/entity/explorer/detail/app/relate/domains', // app相关域名
|
||||
appRelatedIp: apiVersion + '/entity/explorer/detail/app/relate/ips', // app相关ip
|
||||
ipRelatedApp: apiVersion + '/entity/explorer/detail/ip/relate/apps', // ip相关app
|
||||
ipRelatedDomain: apiVersion + '/entity/explorer/detail/ip/relate/domains', // ip相关域名
|
||||
ipRelatedPort: apiVersion + '/entity/explorer/detail/ip/relate/ports', // ip开放端口
|
||||
domainTrafficMap: apiVersion + '/entity/explorer/detail/traffic/map/domain', // domain流量地图
|
||||
ipTrafficMap: apiVersion + '/entity/explorer/detail/traffic/map/ip', // ip流量地图
|
||||
appTrafficMap: apiVersion + '/entity/explorer/detail/traffic/map/app', // app流量地图
|
||||
summaryCount: apiVersion + '/entity/explorer/query/summaryCount', // 实体基数统计
|
||||
aggCountry: apiVersion + '/entity/explorer/top/aggCountry', // 国家实体基数统计
|
||||
aggAsn: apiVersion + '/entity/explorer/top/aggAsn', // ASN实体基数统计
|
||||
aggCity: apiVersion + '/entity/explorer/top/aggCity', // 城市实体基数统计
|
||||
domainSecurity: apiVersion + '/entity/explorer/detail/event/security/domain', // domain安全事件详情
|
||||
ipSecurity: apiVersion + '/entity/explorer/detail/event/security/domain', // ip安全事件详情
|
||||
appSecurity: apiVersion + '/entity/explorer/detail/event/security/domain', // app安全事件详情
|
||||
domainEventPerformance: apiVersion + '/entity/explorer/detail/event/performance/domain', // domain服务质量详情
|
||||
ipEventPerformance: apiVersion + '/entity/explorer/detail/event/performance/ip', // ip服务质量详情
|
||||
appEventPerformance: apiVersion + '/entity/explorer/detail/event/performance/app', // app服务质量详情
|
||||
entityActive: apiVersion + '/entity/explorer/overview/active', // entity首页active数据概览
|
||||
entityNew: apiVersion + '/entity/explorer/overview/new', // entity首页new数据概览
|
||||
entityTotal: apiVersion + '/entity/explorer/overview/total' // entity首页total数据概览
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@ export const dbName = 'cn-db'
|
||||
// indexedDB表名
|
||||
export const dbGeoDataTableName = 'geodata'
|
||||
export const dbDrilldownTableConfig = 'cn-drilldown-table-config'
|
||||
export const dbTableColumnCustomizeConfigPre = 'cn-table-column-customize-config'
|
||||
export const dbUserTableColumnCustomizeConfig = 'cn-table-column-customize-config-userTable'
|
||||
export const dbRoleTableColumnCustomizeConfig = 'cn-table-column-customize-config-rolesTable'
|
||||
export const dbOperationLogTableColumnCustomizeConfig = 'cn-table-column-customize-config-operationLogTable'
|
||||
export const dbChartTableColumnCustomizeConfig = 'cn-table-column-customize-config-chartTable'
|
||||
export const dbI18nTableColumnCustomizeConfig = 'cn-table-column-customize-config-i18nTable'
|
||||
export const dbReportTableColumnCustomizeConfig = 'cn-table-column-customize-config-reportTable'
|
||||
export const dbGalaxySettingTableColumnCustomizeConfig = 'cn-table-column-customize-config-galaxySettingTable'
|
||||
export const storageKey = {
|
||||
iso36112Capital: 'cn-iso3611-2-capital',
|
||||
iso36112WorldLow: 'cn-iso3611-2-world-low',
|
||||
@@ -97,6 +105,8 @@ export const entityDetailTabsName = {
|
||||
performanceEvent: 'performanceEvent'
|
||||
}
|
||||
|
||||
export const entityDetailRelatedEntitiesShowSize = 100
|
||||
|
||||
export const echartsFontSize = {
|
||||
legendFirstFontSize: 12, // <1920
|
||||
legendSecondFontSize: 14, // >=1920 && <2560
|
||||
|
||||
@@ -272,179 +272,66 @@ export const dataForNpmNetworkQuantity = {
|
||||
}
|
||||
export const columnList = [
|
||||
{
|
||||
name: 'entity_type',
|
||||
name: 'ip',
|
||||
type: 'string',
|
||||
label: 'Entity type'
|
||||
label: 'IP',
|
||||
doc: {
|
||||
constraints: {
|
||||
type: 'ip',
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ip_addr',
|
||||
name: 'fqdn',
|
||||
type: 'string',
|
||||
label: 'IP.Address'
|
||||
},
|
||||
{
|
||||
name: 'ip_location_country',
|
||||
type: 'string',
|
||||
label: 'IP.Country'
|
||||
},
|
||||
{
|
||||
name: 'ip_location_province',
|
||||
type: 'string',
|
||||
label: 'IP.Province'
|
||||
},
|
||||
{
|
||||
name: 'ip_location_city',
|
||||
type: 'string',
|
||||
label: 'IP.City'
|
||||
},
|
||||
{
|
||||
name: 'ip_asn',
|
||||
type: 'string',
|
||||
label: 'IP.ASN'
|
||||
},
|
||||
{
|
||||
name: 'dns_server_role',
|
||||
type: 'string',
|
||||
label: 'IP.DNS server role'
|
||||
},
|
||||
{
|
||||
name: 'dns_server_org',
|
||||
type: 'string',
|
||||
label: 'IP.DNS server organization'
|
||||
},
|
||||
{
|
||||
name: 'dns_server_os',
|
||||
type: 'string',
|
||||
label: 'IP.Operating system'
|
||||
},
|
||||
{
|
||||
name: 'dns_server_software',
|
||||
type: 'string',
|
||||
label: 'IP.DNS server software'
|
||||
},
|
||||
{
|
||||
name: 'domain_name',
|
||||
type: 'string',
|
||||
label: 'Domain.Name'
|
||||
},
|
||||
{
|
||||
name: 'domain_category',
|
||||
type: 'string',
|
||||
label: 'Domain.Category'
|
||||
},
|
||||
{
|
||||
name: 'domain_category_group',
|
||||
type: 'string',
|
||||
label: 'Domain.Category group'
|
||||
},
|
||||
{
|
||||
name: 'domain_reputation_level',
|
||||
type: 'string',
|
||||
label: 'Domain.Reputation'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_email',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois email'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_name_servers',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois nameserver'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_registrar',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois registrar'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_org',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois organization'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_address',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois address'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_city',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois city'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_state',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois state'
|
||||
},
|
||||
{
|
||||
name: 'domain_whois_country',
|
||||
type: 'string',
|
||||
label: 'Domain.Whois country'
|
||||
},
|
||||
{
|
||||
name: 'domain_icp_owner',
|
||||
type: 'string',
|
||||
label: 'Domain.ICP owner'
|
||||
},
|
||||
{
|
||||
name: 'domain_icp_company_name',
|
||||
type: 'string',
|
||||
label: 'Domain.ICP company'
|
||||
},
|
||||
{
|
||||
name: 'domain_icp_company_type',
|
||||
type: 'string',
|
||||
label: 'Domain.ICP company type'
|
||||
},
|
||||
{
|
||||
name: 'domain_icp_site_license',
|
||||
type: 'string',
|
||||
label: 'Domain.ICP site license'
|
||||
},
|
||||
{
|
||||
name: 'domain_icp_site_name',
|
||||
type: 'string',
|
||||
label: 'Domain.ICP site'
|
||||
label: 'Domain',
|
||||
doc: {
|
||||
constraints: {
|
||||
type: 'domain',
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'app_name',
|
||||
type: 'string',
|
||||
label: 'APP.Name'
|
||||
label: 'App',
|
||||
doc: {
|
||||
constraints: {
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'app_id',
|
||||
name: 'region',
|
||||
type: 'string',
|
||||
label: 'APP.ID'
|
||||
label: 'City',
|
||||
doc: {
|
||||
constraints: {
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'app_category',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
label: 'APP.Category'
|
||||
label: 'Country',
|
||||
doc: {
|
||||
constraints: {
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'app_subcategory',
|
||||
name: 'asn',
|
||||
type: 'string',
|
||||
label: 'APP.Subcategory'
|
||||
},
|
||||
{
|
||||
name: 'app_risk',
|
||||
type: 'string',
|
||||
label: 'APP.Risk'
|
||||
},
|
||||
{
|
||||
name: 'app_description',
|
||||
type: 'string',
|
||||
label: 'APP.Description'
|
||||
},
|
||||
{
|
||||
name: 'app_longname',
|
||||
type: 'string',
|
||||
label: 'APP.Long name'
|
||||
},
|
||||
{
|
||||
name: 'app_technology',
|
||||
type: 'string',
|
||||
label: 'APP.Technology'
|
||||
label: 'ASN',
|
||||
doc: {
|
||||
constraints: {
|
||||
operator_functions: '=,in'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
export const operatorList = ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE']
|
||||
|
||||
@@ -741,34 +741,38 @@ export function truncateText (text, limitWidth, fontSize = 12, ellipsis = '...')
|
||||
}
|
||||
|
||||
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
|
||||
if (scrollY < 0) {
|
||||
dom.scrollTop = 0
|
||||
return
|
||||
if (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
|
||||
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
|
||||
}
|
||||
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)
|
||||
}
|
||||
oldTimestamp = newTimestamp
|
||||
window.requestAnimationFrame(step)
|
||||
} else {
|
||||
const wraps = document.querySelector('.entity-graph__detail')
|
||||
wraps.scrollTop = 0
|
||||
}
|
||||
window.requestAnimationFrame(step)
|
||||
}
|
||||
|
||||
export function getChainRatio (current, prev) {
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
<el-drawer
|
||||
v-model="rightBox.show"
|
||||
direction="rtl"
|
||||
custom-class="common-right-box"
|
||||
:size="700"
|
||||
:with-header="false"
|
||||
destroy-on-close>
|
||||
<chart-box
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
<el-drawer
|
||||
v-model="rightBox.show"
|
||||
direction="rtl"
|
||||
custom-class="common-right-box"
|
||||
:size="700"
|
||||
:with-header="false"
|
||||
destroy-on-close>
|
||||
<galaxy-proxy-box :object="object" @close="closeRightBox"></galaxy-proxy-box>
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
<el-drawer
|
||||
v-model="rightBox.show"
|
||||
direction="rtl"
|
||||
custom-class="common-right-box"
|
||||
:size="700"
|
||||
:with-header="false"
|
||||
destroy-on-close>
|
||||
<i18n-box
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
<el-drawer
|
||||
v-model="rightBox.show"
|
||||
direction="rtl"
|
||||
custom-class="common-right-box"
|
||||
:with-header="false"
|
||||
:size="700"
|
||||
destroy-on-close>
|
||||
<role-box :object="object" @close="closeRightBox"></role-box>
|
||||
</el-drawer>
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
<el-drawer
|
||||
v-model="rightBox.show"
|
||||
direction="rtl"
|
||||
custom-class="common-right-box"
|
||||
:size="700"
|
||||
:with-header="false"
|
||||
destroy-on-close>
|
||||
<user-box
|
||||
@@ -104,7 +106,7 @@ export default {
|
||||
}
|
||||
this.searchLabel = { ...this.searchLabel, ...this.pageObj }
|
||||
this.isNoData = false
|
||||
//this.tableData = []
|
||||
// this.tableData = []
|
||||
this.toggleLoading(true)
|
||||
delete this.searchLabel.total
|
||||
let listUrl = this.url
|
||||
|
||||
@@ -37,25 +37,15 @@ export default {
|
||||
location () {
|
||||
let location = ''
|
||||
if (this.chartInfo) {
|
||||
if (this.chartInfo.country) {
|
||||
location = this.chartInfo.country
|
||||
if (this.chartInfo.province) {
|
||||
location += ', '
|
||||
location += this.chartInfo.province
|
||||
if (this.chartInfo.city) {
|
||||
location += ', '
|
||||
location += this.chartInfo.city
|
||||
}
|
||||
}
|
||||
} else if (this.chartInfo.province) {
|
||||
location = this.chartInfo.province
|
||||
if (this.chartInfo.city) {
|
||||
location += ', '
|
||||
location += this.chartInfo.city
|
||||
}
|
||||
} else if (this.chartInfo.city) {
|
||||
if (this.chartInfo.city) {
|
||||
location = this.chartInfo.city
|
||||
}
|
||||
if (this.chartInfo.province) {
|
||||
location = location ? `${this.chartInfo.province}, ${location}` : this.chartInfo.province
|
||||
}
|
||||
if (this.chartInfo.country) {
|
||||
location = location ? `${this.chartInfo.country}, ${location}` : this.chartInfo.country
|
||||
}
|
||||
}
|
||||
return location
|
||||
},
|
||||
|
||||
@@ -75,7 +75,7 @@ export default {
|
||||
selector: '.entity-detail-info',
|
||||
correctionHeight: 161,
|
||||
chartType: typeMapping.entityDetail.basicInfo
|
||||
}*/
|
||||
} */
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { entityDetailRelatedEntitiesShowSize } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
chart: Object,
|
||||
@@ -8,13 +10,30 @@ export default {
|
||||
return {
|
||||
isNoData: false,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
errorMsg: '',
|
||||
entityDetailRelatedEntitiesShowSize: entityDetailRelatedEntitiesShowSize
|
||||
}
|
||||
},
|
||||
emits: ['toggleLoading'],
|
||||
methods: {
|
||||
toggleLoading (loading) {
|
||||
this.$emit('toggleLoading', loading)
|
||||
},
|
||||
showMore (showListInfo, allList) {
|
||||
const showNum = showListInfo.num
|
||||
if (showNum < allList.length) {
|
||||
showListInfo.num = showNum + entityDetailRelatedEntitiesShowSize
|
||||
if (showNum > allList.length) {
|
||||
showListInfo.num = allList.length
|
||||
}
|
||||
}
|
||||
},
|
||||
handleShowDataNum (showListInfo, allList) {
|
||||
if (allList.length <= entityDetailRelatedEntitiesShowSize) {
|
||||
showListInfo.num = allList.length
|
||||
} else {
|
||||
showListInfo.num = entityDetailRelatedEntitiesShowSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +288,18 @@ export default {
|
||||
}
|
||||
this.myChart = echarts.init(document.getElementById('dnsLineChart'))
|
||||
this.myChart.setOption(this.chartOption)
|
||||
|
||||
this.myChart.dispatchAction({
|
||||
type: 'takeGlobalCursor',
|
||||
key: 'brush',
|
||||
brushOption: {
|
||||
brushType: 'lineX',
|
||||
xAxisIndex: 'all',
|
||||
brushMode: 'single',
|
||||
throttleType: 'debounce'
|
||||
}
|
||||
})
|
||||
this.myChart.on('brushEnd', this.brushEcharts)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -470,6 +482,29 @@ export default {
|
||||
this.echartsInit(this.tabs, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* echarts框选
|
||||
* @param params
|
||||
*/
|
||||
brushEcharts (params) {
|
||||
this.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
// 避免点击空白区域报错
|
||||
if (params.areas && params.areas.length > 0) {
|
||||
const rangeObj = {
|
||||
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||
}
|
||||
|
||||
// 暂定框选最小范围为5分钟,后续可能会变动
|
||||
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||
}
|
||||
this.$store.commit('setRangeEchartsData', rangeObj)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<el-popover
|
||||
placement="bottom-end"
|
||||
:width="390"
|
||||
:width="450"
|
||||
trigger="click"
|
||||
popper-class="analysis-popper"
|
||||
@show="analysisPopSwitch(true)"
|
||||
@@ -254,6 +254,17 @@ export default {
|
||||
label: i18n.global.t('dns.dnsInsights'),
|
||||
path: '/panel/dnsServiceInsights'
|
||||
}
|
||||
const graphItem = {
|
||||
icon: 'cn-icon cn-icon-graph',
|
||||
label: i18n.global.t('entities.graph'),
|
||||
url: resolvePath({
|
||||
path: '/entityGraph',
|
||||
query: {
|
||||
entityType: props.entity.entityType,
|
||||
entityName: props.entity.entityName
|
||||
}
|
||||
})
|
||||
}
|
||||
switch (props.entity.entityType) {
|
||||
case 'ip': {
|
||||
const queryCondition = `common_client_ip='${props.entity.entityName}' OR common_server_ip='${props.entity.entityName}'`
|
||||
@@ -379,6 +390,7 @@ export default {
|
||||
break
|
||||
}
|
||||
}
|
||||
analysisItems.value.push(graphItem)
|
||||
// 底部各属性
|
||||
const detailCards = ref([])
|
||||
switch (props.entity.entityType) {
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
<template #label>
|
||||
<!--<div class="el-tabs__active-bar is-top" style="width: 80.9998px; transform: translateX(177px);"></div>-->
|
||||
<i :class="tab.icon"></i>{{tab.label}}
|
||||
<i v-if="tab.warnFlag" :class="tab.warnIcon" class="tab-pane-warn--icon"></i>
|
||||
<el-tag size="small" style="margin-left: 6px" :color="tab.name === activeTab ? 'rgb(223,237,248)' : 'rgb(237,237,237)'" round>
|
||||
<span :style="{color: tab.name === activeTab ? '#046ECA' : '#717171'}">{{ tab.tag }}</span>
|
||||
</el-tag>
|
||||
</template>
|
||||
<information-aggregation v-if="tab.name === entityDetailTabsName.informationAggregation && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity"></information-aggregation>
|
||||
<domain-name-resolution v-else-if="tab.name === entityDetailTabsName.relatedEntity && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter"></domain-name-resolution>
|
||||
<digital-certificate v-else-if="tab.name === entityDetailTabsName.digitalCertificate && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" />
|
||||
<security-event v-else-if="tab.name === entityDetailTabsName.securityEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkWarn="setWarn" />
|
||||
<performance-event v-else-if="tab.name === entityDetailTabsName.performanceEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkWarn="setWarn" />
|
||||
<open-port v-else-if="tab.name === entityDetailTabsName.openPort && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter"></open-port>
|
||||
<information-aggregation v-if="tab.name === entityDetailTabsName.informationAggregation && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></information-aggregation>
|
||||
<domain-name-resolution v-else-if="tab.name === entityDetailTabsName.relatedEntity && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter" @checkTag="setTag"></domain-name-resolution>
|
||||
<digital-certificate v-else-if="tab.name === entityDetailTabsName.digitalCertificate && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
|
||||
<security-event v-else-if="tab.name === entityDetailTabsName.securityEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
|
||||
<performance-event v-else-if="tab.name === entityDetailTabsName.performanceEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
|
||||
<open-port v-else-if="tab.name === entityDetailTabsName.openPort && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter" @checkTag="setTag"></open-port>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@@ -26,7 +28,7 @@
|
||||
<script>
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import i18n from '@/i18n'
|
||||
import { entityDetailTabsName } from '@/utils/constants'
|
||||
import { entityDetailTabsName, entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
||||
import { reactive, ref } from 'vue'
|
||||
import InformationAggregation from '@/views/charts2/charts/entityDetail/tabs/InformationAggregation'
|
||||
import DomainNameResolution from '@/views/charts2/charts/entityDetail/tabs/DomainNameResolution'
|
||||
@@ -36,7 +38,6 @@ import OpenPort from '@/views/charts2/charts/entityDetail/tabs/OpenPort'
|
||||
import DigitalCertificate from '@/views/charts2/charts/entityDetail/tabs/DigitalCertificate'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
@@ -80,14 +81,14 @@ export default {
|
||||
const entityType = props.entity.entityType
|
||||
|
||||
const tabs = reactive([
|
||||
{ name: entityDetailTabsName.relatedEntity, label: i18n.global.t('entities.relatedEntity'), icon: 'cn-icon cn-icon-domain-name-resolution' },
|
||||
{ name: entityDetailTabsName.openPort, label: i18n.global.t('entities.openPort'), icon: 'cn-icon cn-icon-open-port' },
|
||||
// { name: entityDetailTabsName.digitalCertificate, label: i18n.global.t('entities.digitalCertificate'), icon: 'cn-icon cn-icon-digital-certificate' },
|
||||
{ name: entityDetailTabsName.securityEvent, label: i18n.global.t('overall.securityEvent'), icon: 'cn-icon cn-icon-security-event', warnIcon: 'cn-icon cn-icon-warn', warnFlag: false },
|
||||
{ name: entityDetailTabsName.performanceEvent, label: i18n.global.t('overall.performanceEvent'), icon: 'cn-icon cn-icon-a-PerformanceEvent', warnIcon: 'cn-icon cn-icon-warn', warnFlag: false }
|
||||
{ name: entityDetailTabsName.relatedEntity, label: i18n.global.t('entities.relatedEntity'), icon: 'cn-icon cn-icon-domain-name-resolution', tag: 0 },
|
||||
{ name: entityDetailTabsName.openPort, label: i18n.global.t('entities.openPort'), icon: 'cn-icon cn-icon-open-port', tag: 0 },
|
||||
// { name: entityDetailTabsName.digitalCertificate, label: i18n.global.t('entities.digitalCertificate'), icon: 'cn-icon cn-icon-digital-certificate', tag: 0 },
|
||||
{ name: entityDetailTabsName.securityEvent, label: i18n.global.t('overall.securityEvent'), icon: 'cn-icon cn-icon-security-event', tag: 30 },
|
||||
{ name: entityDetailTabsName.performanceEvent, label: i18n.global.t('overall.performanceEvent'), icon: 'cn-icon cn-icon-a-PerformanceEvent', tag: 0 }
|
||||
])
|
||||
if (entityType !== 'app') {
|
||||
tabs.unshift({ name: entityDetailTabsName.informationAggregation, label: i18n.global.t('entities.informationAggregation'), icon: 'cn-icon cn-icon-information-aggregation' })
|
||||
tabs.unshift({ name: entityDetailTabsName.informationAggregation, label: i18n.global.t('entities.informationAggregation'), icon: 'cn-icon cn-icon-information-aggregation', tag: 0 })
|
||||
}
|
||||
const activeTab = ref(tabs[0].name)
|
||||
|
||||
@@ -107,32 +108,107 @@ export default {
|
||||
methods: {
|
||||
initData () {
|
||||
const params = {
|
||||
resource: this.entity.entityName,
|
||||
startTime: getSecond(this.oneDayTimeFilter.startTime),
|
||||
endTime: getSecond(this.oneDayTimeFilter.endTime)
|
||||
resource: this.entity.entityName
|
||||
// startTime: getSecond(this.oneDayTimeFilter.startTime),
|
||||
// endTime: getSecond(this.oneDayTimeFilter.endTime)
|
||||
}
|
||||
|
||||
const url = this.getUrlByEntityType(this.entity.entityType)
|
||||
const informationAggregation = axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1`, { params: params })
|
||||
const openPort = axios.get(url, { params: params })
|
||||
const security = axios.get(`${api.entity.security}/${this.entity.entityType}`, { params: params })
|
||||
const performance = axios.get(`${api.entity.performance}/${this.entityType}`, { params: params })
|
||||
|
||||
Promise.all([security, performance]).then(response => {
|
||||
if (response[0].data.code === 200 && response[1].data.code === 200) {
|
||||
const name1 = entityDetailTabsName.securityEvent
|
||||
const name2 = entityDetailTabsName.performanceEvent
|
||||
Promise.all([informationAggregation, openPort, security, performance]).then(response => {
|
||||
if (response[0].data.code === 200) {
|
||||
const list = []
|
||||
response[0].data.data.result.forEach(r => {
|
||||
Object.keys(r).forEach(k => {
|
||||
const aggregation = {
|
||||
createTime: r[k].createTime,
|
||||
updateTime: r[k].updateTime,
|
||||
status: r[k].isValid,
|
||||
intelligenceContent: []
|
||||
}
|
||||
if (k === 'userDefinedTag') {
|
||||
aggregation.intelligenceContent.push({ key: k, value: r[k].tagValue, type: 'normal' })
|
||||
} else {
|
||||
Object.keys(r[k]).forEach(k2 => {
|
||||
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
||||
if (find) {
|
||||
aggregation.intelligenceContent.push({ key: k2, value: this.tagValueHandler(k, k2, r[k][k2]), type: find.type })
|
||||
}
|
||||
})
|
||||
}
|
||||
if (aggregation.intelligenceContent.length > 0) {
|
||||
list.push(aggregation)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 为了避免tabs其中某项被注释或删除,使用name查找到该项进行更改,避免icon显示错误
|
||||
const obj1 = this.tabs.find(t => t.name === name1)
|
||||
const obj2 = this.tabs.find(t => t.name === name2)
|
||||
if (obj1) {
|
||||
obj1.warnFlag = response[0].data.data.result.length > 0
|
||||
this.initSetTag(entityDetailTabsName.informationAggregation, list.length)
|
||||
}
|
||||
if (response[1].data.code === 200) {
|
||||
this.initSetTag(entityDetailTabsName.openPort, response[1].data.data.result.length)
|
||||
}
|
||||
if (response[2].data.code === 200) {
|
||||
this.initSetTag(entityDetailTabsName.securityEvent, response[2].data.data.result.length)
|
||||
}
|
||||
if (response[3].data.code === 200) {
|
||||
this.initSetTag(entityDetailTabsName.performanceEvent, response[3].data.data.result.length)
|
||||
}
|
||||
})
|
||||
|
||||
// 域名解析
|
||||
if (this.entity.entityType === 'app') {
|
||||
const ipsOfApp = axios.get(api.entity.domainNameResolutionAboutIpsOfApp, { params: params })
|
||||
const domainsOfApp = axios.get(api.entity.domainNameResolutionAboutDomainsOfApp, { params: params })
|
||||
this.promiseData(ipsOfApp, domainsOfApp)
|
||||
}
|
||||
|
||||
if (this.entity.entityType === 'ip') {
|
||||
const appsOfIp = axios.get(api.entity.domainNameResolutionAboutAppsOfIp, { params: params })
|
||||
const domainsOfIp = axios.get(api.entity.domainNameResolutionAboutDomainsOfIp, { params: params })
|
||||
this.promiseData(appsOfIp, domainsOfIp)
|
||||
}
|
||||
|
||||
if (this.entity.entityType === 'domain') {
|
||||
const appsOfDomain = axios.get(api.entity.domainNameResolutionAboutAppsOfDomain, { params: params })
|
||||
const ipsOfDomain = axios.get(api.entity.domainNameResolutionAboutIpsOfDomain, { params: params })
|
||||
const fqdnsOfDomain = axios.get(api.entity.domainNameResolutionAboutFQDNsOfDomain, { params: params })
|
||||
this.promiseData(appsOfDomain, ipsOfDomain, fqdnsOfDomain)
|
||||
}
|
||||
},
|
||||
promiseData (data1, data2, data3) {
|
||||
Promise.all([data1, data2, data3]).then(res => {
|
||||
const res0 = res[0].data
|
||||
const res1 = res[1].data
|
||||
|
||||
switch (this.entity.entityType) {
|
||||
case 'ip': {
|
||||
const len1 = res0.code === 200 ? res0.data.result.length : 0
|
||||
const len2 = res1.code === 200 ? res1.data.result.length : 0
|
||||
this.initSetTag(entityDetailTabsName.relatedEntity, len1 + len2)
|
||||
break
|
||||
}
|
||||
if (obj2) {
|
||||
obj2.warnFlag = response[1].data.data.result.length > 0
|
||||
case 'domain': {
|
||||
const res2 = res[2].data
|
||||
const len1 = res0.code === 200 ? res0.data.result.length : 0
|
||||
const len2 = res1.code === 200 ? res1.data.result.length : 0
|
||||
const len3 = res2.code === 200 ? res2.data.result.length : 0
|
||||
this.initSetTag(entityDetailTabsName.relatedEntity, len1 + len2 + len3)
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
const len1 = res0.code === 200 ? res0.data.result.length : 0
|
||||
const len2 = res1.code === 200 ? res1.data.result.length : 0
|
||||
this.initSetTag(entityDetailTabsName.relatedEntity, len1 + len2)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleActiveBar (name, change) {
|
||||
handleActiveBar (name, num) {
|
||||
const tabDom = document.getElementById('tab-' + name)
|
||||
if (tabDom) {
|
||||
const { query } = this.$route
|
||||
@@ -143,26 +219,46 @@ export default {
|
||||
const clientWidth = tabDom.clientWidth
|
||||
const clientLeft = tabDom.clientLeft
|
||||
const activeBar = document.querySelector('.entity-detail-tabs .entity-detail-tabs__active-bar')
|
||||
const addWidth = change === 'add' ? 30 : 0
|
||||
const reduceWidth = change === 'reduce' ? -30 : 0
|
||||
activeBar.style.cssText += `width: ${clientWidth + 2 + addWidth + reduceWidth}px; left: ${offsetLeft + clientLeft - 1}px;`
|
||||
const newWidth = num ? num * 6 : 0
|
||||
activeBar.style.cssText += `width: ${clientWidth + 2 + newWidth}px; left: ${offsetLeft + clientLeft - 1}px;`
|
||||
}
|
||||
},
|
||||
setLoading (loading) {
|
||||
this.toggleLoading(loading)
|
||||
},
|
||||
setWarn (name, flag) {
|
||||
setTag (name, num) {
|
||||
const obj = this.tabs.find(t => t.name === name)
|
||||
if (obj) {
|
||||
const oldFlag = JSON.parse(JSON.stringify(obj.warnFlag))
|
||||
obj.warnFlag = flag
|
||||
if (oldFlag && !flag) {
|
||||
this.handleActiveBar(name, 'reduce') // 之前有warn,再次切换无数据
|
||||
}
|
||||
if (!oldFlag && flag) {
|
||||
this.handleActiveBar(name, 'add') // 之前无warn,再次切换有数据
|
||||
const oldNum = JSON.parse(JSON.stringify(obj.tag))
|
||||
obj.tag = num
|
||||
// 根据前后位数的变化来增减状态栏的长短,
|
||||
// 如初始是0(位数是1),点击tab变成10条(位数是2),所以状态栏宽度增加(2-1)*6px
|
||||
this.handleActiveBar(name, JSON.stringify(num).length - JSON.stringify(oldNum).length)
|
||||
}
|
||||
},
|
||||
initSetTag (name, num) {
|
||||
const obj = this.tabs.find(t => t.name === name)
|
||||
if (obj) {
|
||||
obj.tag = num
|
||||
}
|
||||
},
|
||||
getUrlByEntityType (type) {
|
||||
switch (type) {
|
||||
case 'ip': return api.entity.openPortOfIp
|
||||
case 'domain': return api.entity.openPortOfDomain
|
||||
case 'app': return api.entity.openPortOfApp
|
||||
}
|
||||
},
|
||||
tagValueHandler (k, k2, value) {
|
||||
if (k === 'psiphon3Ip') {
|
||||
if (k2 === 'type') {
|
||||
const find = psiphon3IpType.find(t => t.value === value)
|
||||
if (find) {
|
||||
return find.name
|
||||
}
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
@@ -170,3 +266,10 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag {
|
||||
font-size: 12px !important;
|
||||
border-radius: 20px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template xmlns="http://www.w3.org/1999/html">
|
||||
<div>
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
|
||||
@@ -8,11 +8,16 @@
|
||||
<span class="title-mark"></span>
|
||||
{{ $t('entities.tab.relatedApp') }} ({{ relatedAppList.length }})
|
||||
</div>
|
||||
<div class="type-content" v-if="!showError0">
|
||||
<div v-for="(entity, index) in relatedAppList" class="data-item" :key="index">
|
||||
{{ entity.appName ? entity.appName : entity }}
|
||||
<template v-if="!showError0">
|
||||
<div class="type-content" >
|
||||
<div v-for="(entity, index) in relatedAppList.slice(0,showRelatedAppListInfo.num)" class="data-item" :key="index">
|
||||
{{ entity.appName ? entity.appName : entity }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="more" v-if="relatedAppList.length > entityDetailRelatedEntitiesShowSize">
|
||||
<span class="button" :style="{'opacity': relatedAppList.length > showRelatedAppListInfo.num ? 1 : 0.6}" @click="showMore(showRelatedAppListInfo,relatedAppList)">{{ $t('overall.more') }} > </span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="type-error-content" v-else>
|
||||
<chart-error class="type-error-content__block" :content="errorMsg0"></chart-error>
|
||||
</div>
|
||||
@@ -23,11 +28,16 @@
|
||||
<span class="title-mark"></span>
|
||||
{{ $t('entities.tab.relatedIp') }} ({{ relatedIpList.length }})
|
||||
</div>
|
||||
<div class="type-content" v-if="!showError1">
|
||||
<div v-for="(entity, index) in relatedIpList" :key="index" class="data-item">
|
||||
{{ entity.ip ? entity.ip : entity }}
|
||||
<template v-if="!showError1">
|
||||
<div class="type-content" >
|
||||
<div v-for="(entity, index) in relatedIpList.slice(0,showRelatedIpListInfo.num)" :key="index" class="data-item">
|
||||
{{ entity.ip ? entity.ip : entity }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="more" v-if="relatedIpList.length > entityDetailRelatedEntitiesShowSize">
|
||||
<span class="button" :style="{'opacity': relatedIpList.length > showRelatedIpListInfo.num ? 1 : 0.6}" @click="showMore(showRelatedIpListInfo,relatedIpList)">{{ $t('overall.more') }} > </span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="type-error-content" v-else>
|
||||
<chart-error class="type-error-content__block" :content="errorMsg1"></chart-error>
|
||||
</div>
|
||||
@@ -38,11 +48,16 @@
|
||||
<span class="title-mark"></span>
|
||||
{{ $t('entities.tab.relatedDomain') }} ({{ relatedDomainList.length }})
|
||||
</div>
|
||||
<div class="type-content" v-if="!showError2">
|
||||
<div v-for="(entity, index) in relatedDomainList" class="data-item" :key="index">
|
||||
{{ entity.domain ? entity.domain : entity }}
|
||||
<template v-if="!showError2">
|
||||
<div class="type-content">
|
||||
<div v-for="(entity, index) in relatedDomainList.slice(0,showRelatedDomainListInfo.num)" class="data-item" :key="index">
|
||||
{{ entity.domain ? entity.domain : entity }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="more" v-if="relatedDomainList.length > entityDetailRelatedEntitiesShowSize">
|
||||
<span class="button" :style="{'opacity': relatedDomainList.length > showRelatedDomainListInfo.num ? 1 : 0.6}" @click="showMore(showRelatedDomainListInfo,relatedDomainList)">{{ $t('overall.more') }} > </span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="type-error-content" v-else>
|
||||
<chart-error class="type-error-content__block" :content="errorMsg2"></chart-error>
|
||||
</div>
|
||||
@@ -56,8 +71,8 @@
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import chartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import { entityDetailTabsName } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
name: 'DomainNameResolution',
|
||||
@@ -69,9 +84,18 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
relatedAppList: [],
|
||||
relatedIpList: [],
|
||||
relatedDomainList: [],
|
||||
relatedAppList: [], // 所有数据
|
||||
showRelatedAppListInfo: {
|
||||
num: 0
|
||||
}, // 界面展示的数量
|
||||
relatedIpList: [], // 所有数据
|
||||
showRelatedIpListInfo: {
|
||||
num: 0
|
||||
}, // 界面展示的数量
|
||||
relatedDomainList: [], // 所有数据
|
||||
showRelatedDomainListInfo: {
|
||||
num: 0
|
||||
}, // 界面展示的数量
|
||||
initFlag: false, // 初始化标识,请求接口之后再显示,避免标题初始化会闪一下
|
||||
showError0: false,
|
||||
errorMsg0: '',
|
||||
@@ -87,9 +111,9 @@ export default {
|
||||
methods: {
|
||||
initData () {
|
||||
const params = {
|
||||
resource: this.entity.entityName,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
resource: this.entity.entityName
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
if (this.entity.entityType === 'app') {
|
||||
const ipsOfApp = axios.get(api.entity.domainNameResolutionAboutIpsOfApp, { params: params })
|
||||
@@ -126,6 +150,7 @@ export default {
|
||||
if (this.entity.entityType === 'app' && !this.isNoData) {
|
||||
if (res0.code === 200) {
|
||||
this.relatedIpList = res0.data.result
|
||||
this.handleShowDataNum(this.showRelatedIpListInfo, this.relatedIpList)
|
||||
} else {
|
||||
this.showError1 = true
|
||||
this.errorMsg1 = this.errorMsgHandler(res0)
|
||||
@@ -133,26 +158,35 @@ export default {
|
||||
|
||||
if (res1.code === 200) {
|
||||
this.relatedDomainList = res1.data.result
|
||||
this.handleShowDataNum(this.showRelatedDomainListInfo, this.relatedDomainList)
|
||||
} else {
|
||||
this.showError2 = true
|
||||
this.errorMsg2 = this.errorMsgHandler(res1)
|
||||
}
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, res0.data.result.length + res1.data.result.length)
|
||||
} else {
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, 0)
|
||||
}
|
||||
|
||||
// ip相关,显示app,domain
|
||||
if (this.entity.entityType === 'ip' && !this.isNoData) {
|
||||
if (res0.code === 200) {
|
||||
this.relatedAppList = res0.data.result
|
||||
this.handleShowDataNum(this.showRelatedAppListInfo, this.relatedAppList)
|
||||
} else {
|
||||
this.showError0 = true
|
||||
this.errorMsg0 = this.errorMsgHandler(res0)
|
||||
}
|
||||
if (res1.code === 200) {
|
||||
this.relatedDomainList = res1.data.result
|
||||
this.handleShowDataNum(this.showRelatedDomainListInfo, this.relatedDomainList)
|
||||
} else {
|
||||
this.showError2 = true
|
||||
this.errorMsg2 = this.errorMsgHandler(res1)
|
||||
}
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, res0.data.result.length + res1.data.result.length)
|
||||
} else {
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, 0)
|
||||
}
|
||||
|
||||
// domain相关,显示app,ip,domain
|
||||
@@ -164,6 +198,7 @@ export default {
|
||||
|
||||
if (res0.code === 200) {
|
||||
this.relatedAppList = res0.data.result
|
||||
this.handleShowDataNum(this.showRelatedAppListInfo, this.relatedAppList)
|
||||
} else {
|
||||
this.showError0 = true
|
||||
this.errorMsg0 = this.errorMsgHandler(res0)
|
||||
@@ -171,6 +206,7 @@ export default {
|
||||
|
||||
if (res1.code === 200) {
|
||||
this.relatedIpList = res1.data.result
|
||||
this.handleShowDataNum(this.showRelatedIpListInfo, this.relatedIpList)
|
||||
} else {
|
||||
this.showError1 = true
|
||||
this.errorMsg1 = this.errorMsgHandler(res1)
|
||||
@@ -178,13 +214,16 @@ export default {
|
||||
|
||||
if (res2.code === 200) {
|
||||
this.relatedDomainList = res2.data.result
|
||||
this.handleShowDataNum(this.showRelatedDomainListInfo, this.relatedDomainList)
|
||||
} else {
|
||||
this.showError2 = true
|
||||
this.errorMsg2 = this.errorMsgHandler(res2)
|
||||
}
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, res0.data.result.length + res1.data.result.length + res2.data.result.length)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.log(e)
|
||||
this.$emit('checkTag', entityDetailTabsName.relatedEntity, 0)
|
||||
this.showError0 = true
|
||||
this.showError1 = true
|
||||
this.showError2 = true
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<!--初步方案:error提示替换table。后续若改为table内error提示,记得在此修改-->
|
||||
<chart-error v-if="showError" :content="errorMsg" class="entity-detail-event-error"></chart-error>
|
||||
<chart-no-data v-if="isNoData && !showError" test-id="no-data"></chart-no-data>
|
||||
|
||||
<div v-if="!isNoData && !showError && !loading" class="information-aggregation__table">
|
||||
<el-table
|
||||
style="width: 100%"
|
||||
@@ -40,32 +39,12 @@
|
||||
prop="intelligenceContent"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="intelligence-content">
|
||||
<!-- <div class="information-aggregation-tags">
|
||||
<template v-for="ic in scope.row.intelligenceContent" >
|
||||
<template v-if="ic.type === 0" >
|
||||
<div v-if="ic.threatLevel === -1" class="entity-tag entity-tag--small entity-tag--level-one-negative margin-r-6">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
<div v-else-if="ic.threatLevel === 0" class="entity-tag entity-tag--small entity-tag--level-one-normal margin-r-6">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
<div v-else-if="ic.threatLevel === 1" class="entity-tag entity-tag--small entity-tag--level-one-positive margin-r-6">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>-->
|
||||
<div class="information-aggregation-tags">
|
||||
<div v-for="ic in scope.row.intelligenceContent" :key="ic.key">
|
||||
<div>
|
||||
<div class="entity-tag entity-tag--small margin-r-6" :test-id="`entity-tag${scope.$index}`" :class="`entity-tag--level-two-${ic.type}`">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="ic in scope.row.intelligenceContent" :key="ic.key"
|
||||
class="entity-tag entity-tag--small margin-r-6" :test-id="`entity-tag${scope.$index}`" :class="`entity-tag--level-two-${ic.type}`">
|
||||
{{ic.value}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -92,7 +71,7 @@
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import { entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
||||
import { entityDetailTabsName, entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import chartNoData from '@/views/charts/charts/ChartNoData'
|
||||
|
||||
@@ -126,14 +105,15 @@ export default {
|
||||
},
|
||||
getData () {
|
||||
this.loading = true
|
||||
this.showError = false
|
||||
this.toggleLoading(true)
|
||||
this.informationAggregationList = []
|
||||
axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1`).then(response => {
|
||||
const res = response.data
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
// this.isNoData = res.data.result.length === 0
|
||||
this.showError = false
|
||||
if (!this.isNoData) {
|
||||
if (res.data.result.length > 0) {
|
||||
res.data.result.forEach(r => {
|
||||
Object.keys(r).forEach(k => {
|
||||
const aggregation = {
|
||||
@@ -157,18 +137,26 @@ export default {
|
||||
}
|
||||
})
|
||||
})
|
||||
this.$emit('checkTag', entityDetailTabsName.informationAggregation, this.informationAggregationList.length)
|
||||
} else {
|
||||
this.$emit('checkTag', entityDetailTabsName.informationAggregation, 0)
|
||||
}
|
||||
} else {
|
||||
this.showError = true
|
||||
this.isNoData = false
|
||||
this.errorMsg = this.errorMsgHandler(res)
|
||||
this.$emit('checkTag', entityDetailTabsName.informationAggregation, 0)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.showError = true
|
||||
this.isNoData = false
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
this.$emit('checkTag', entityDetailTabsName.informationAggregation, 0)
|
||||
}).finally(() => {
|
||||
if (this.informationAggregationList.length > 0) {
|
||||
this.isNoData = false
|
||||
} else {
|
||||
this.isNoData = true
|
||||
}
|
||||
this.loading = false
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
<span class="type-title-word">{{ $t('entities.tab.currentDevelopmentPortsAndServices') }}</span>({{ openPortList.length }})
|
||||
</div>
|
||||
<div class="type-content">
|
||||
<div v-for="(openPort, index) in openPortList" :key="index" class="data-item">
|
||||
<div v-for="(openPort, index) in openPortList.slice(0,showOpenPortListInfo.num)" :key="index" class="data-item">
|
||||
{{ openPort.port }}/{{ openPort.l7Protocol }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="more" v-if="openPortList.length > entityDetailRelatedEntitiesShowSize">
|
||||
<span class="button" :style="{'opacity': openPortList.length > showOpenPortListInfo.num ? 1 : 0.6}" @click="showMore(showOpenPortListInfo,openPortList)">{{ $t('overall.more') }} > </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,8 +25,8 @@
|
||||
import axios from 'axios'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import chartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import { entityDetailTabsName } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
name: 'OpenPort',
|
||||
@@ -33,6 +36,9 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
openPortList: [],
|
||||
showOpenPortListInfo: {
|
||||
num: 0
|
||||
},
|
||||
showError: false,
|
||||
errorMsg: '',
|
||||
initFlag: false // 初始化标识,请求接口之后再显示,避免标题初始化会闪一下
|
||||
@@ -49,9 +55,9 @@ export default {
|
||||
methods: {
|
||||
initData () {
|
||||
const params = {
|
||||
resource: this.entity.entityName,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
resource: this.entity.entityName
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
this.toggleLoading(true)
|
||||
@@ -60,9 +66,11 @@ export default {
|
||||
const res = response.data
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.$emit('checkTag', entityDetailTabsName.openPort, res.data.result.length)
|
||||
this.showError = false
|
||||
if (!this.isNoData) {
|
||||
this.openPortList = res.data.result
|
||||
this.handleShowDataNum(this.showOpenPortListInfo, this.openPortList)
|
||||
}
|
||||
} else {
|
||||
this.httpError(res)
|
||||
@@ -76,6 +84,7 @@ export default {
|
||||
})
|
||||
},
|
||||
httpError (e) {
|
||||
this.$emit('checkTag', entityDetailTabsName.openPort, 0)
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSecond, dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { eventSeverityColor, entityDetailTabsName } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import axios from 'axios'
|
||||
@@ -76,7 +76,7 @@ export default {
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const entityType = query.entityType
|
||||
const entityName = query.name || query.entityName
|
||||
const entityName = query.entityName
|
||||
|
||||
return {
|
||||
entityType,
|
||||
@@ -92,9 +92,9 @@ export default {
|
||||
dateFormatByAppearance,
|
||||
initData () {
|
||||
const params = {
|
||||
resource: this.entityName,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
resource: this.entityName
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
this.toggleLoading(true)
|
||||
@@ -103,7 +103,7 @@ export default {
|
||||
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.$emit('checkWarn', entityDetailTabsName.performanceEvent, !this.isNoData)
|
||||
this.$emit('checkTag', entityDetailTabsName.performanceEvent, res.data.result.length)
|
||||
this.showError = false
|
||||
if (!this.isNoData) {
|
||||
this.eventList = res.data.result
|
||||
@@ -122,6 +122,7 @@ export default {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSecond, dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { eventSeverityColor, entityDetailTabsName } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import axios from 'axios'
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const entityType = query.entityType
|
||||
const entityName = query.name
|
||||
const entityName = query.entityName
|
||||
|
||||
return {
|
||||
entityType,
|
||||
@@ -117,9 +117,9 @@ export default {
|
||||
dateFormatByAppearance,
|
||||
initData () {
|
||||
const params = {
|
||||
resource: this.entityName,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
resource: this.entityName
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
this.toggleLoading(true)
|
||||
@@ -128,7 +128,7 @@ export default {
|
||||
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.$emit('checkWarn', entityDetailTabsName.securityEvent, !this.isNoData)
|
||||
this.$emit('checkTag', entityDetailTabsName.securityEvent, res.data.result.length)
|
||||
this.showError = false
|
||||
if (!this.isNoData) {
|
||||
this.eventList = res.data.result
|
||||
@@ -144,6 +144,7 @@ export default {
|
||||
})
|
||||
},
|
||||
httpError (e) {
|
||||
this.$emit('checkTag', entityDetailTabsName.securityEvent, 0)
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
|
||||
@@ -231,6 +231,7 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.linkNoData = data.length === 0
|
||||
data.forEach((item) => {
|
||||
item.totalBitsRate = item.egressBitsRate + item.ingressBitsRate
|
||||
})
|
||||
@@ -246,7 +247,7 @@ export default {
|
||||
this.linkData = sorted
|
||||
}
|
||||
} else {
|
||||
this.linkNoData = false
|
||||
this.linkNoData = true
|
||||
this.showError1 = true
|
||||
this.errorMsg1 = this.errorMsgHandler(res[0])
|
||||
}
|
||||
@@ -267,7 +268,7 @@ export default {
|
||||
directionArr = Array.from(new Set(directionArr))
|
||||
|
||||
const newNextHopData = []
|
||||
|
||||
this.nextHopNoData = directionArr.length === 0
|
||||
directionArr.forEach((item1) => {
|
||||
const newObj = { egressBitsRate: 0, ingressBitsRate: 0, totalBitsRate: 0, linkDirection: item1 }
|
||||
nextHopData.forEach((item2) => {
|
||||
@@ -309,7 +310,7 @@ export default {
|
||||
}
|
||||
} else {
|
||||
this.showError2 = true
|
||||
this.nextHopNoData = false
|
||||
this.nextHopNoData = true
|
||||
this.errorMsg2 = this.errorMsgHandler(res[1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,10 +138,11 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.isLinkNoData = linkGridData.length === 0
|
||||
this.linkGridData = linkGridData
|
||||
}
|
||||
} else {
|
||||
this.isLinkNoData = false
|
||||
this.isLinkNoData = true
|
||||
this.isLinkShowError = true
|
||||
this.linkErrorMsg = this.errorMsgHandler(res[0])
|
||||
}
|
||||
@@ -227,10 +228,11 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.isNextNoData = nextGridData.length === 0
|
||||
this.nextGridData = nextGridData
|
||||
}
|
||||
} else {
|
||||
this.isNextNoData = false
|
||||
this.isNextNoData = true
|
||||
this.isNextShowError = true
|
||||
this.nextErrorMsg = this.errorMsgHandler(res[1])
|
||||
}
|
||||
|
||||
@@ -259,6 +259,18 @@ export default {
|
||||
}
|
||||
this.myChart = echarts.init(document.getElementById('linkTrafficLineChart'))
|
||||
this.myChart.setOption(this.chartOption)
|
||||
|
||||
this.myChart.dispatchAction({
|
||||
type: 'takeGlobalCursor',
|
||||
key: 'brush',
|
||||
brushOption: {
|
||||
brushType: 'lineX',
|
||||
xAxisIndex: 'all',
|
||||
brushMode: 'single',
|
||||
throttleType: 'debounce'
|
||||
}
|
||||
})
|
||||
this.myChart.on('brushEnd', this.brushEcharts)
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -401,6 +413,29 @@ export default {
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* echarts框选
|
||||
* @param params
|
||||
*/
|
||||
brushEcharts (params) {
|
||||
this.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
// 避免点击空白区域报错
|
||||
if (params.areas && params.areas.length > 0) {
|
||||
const rangeObj = {
|
||||
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||
}
|
||||
|
||||
// 暂定框选最小范围为5分钟,后续可能会变动
|
||||
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||
}
|
||||
this.$store.commit('setRangeEchartsData', rangeObj)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
import * as echarts from 'echarts'
|
||||
import { trafficLineChartOption } from '@/views/charts2/charts/options/echartOption'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { chartColor3, unitTypes } from '@/utils/constants.js'
|
||||
import { chartColor3, chartColor4, unitTypes } from '@/utils/constants.js'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||
import axios from 'axios'
|
||||
@@ -84,7 +84,8 @@ export default {
|
||||
npmQuantity: dataForNpmTrafficLine.npmQuantity,
|
||||
metricOptions: dataForNpmTrafficLine.metricOptions,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
errorMsg: '',
|
||||
sizes: [3, 4, 6, 8, 9, 10]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -238,6 +239,14 @@ export default {
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== this.$t('network.total') ? this.$t('network.total') : '',
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: chartColor4[t.positioning],
|
||||
borderWidth: 2,
|
||||
shadowColor: chartColor4[t.positioning],
|
||||
shadowBlur: this.sizes[t.positioning] + 2
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
@@ -283,6 +292,18 @@ export default {
|
||||
this.myChart = echarts.init(dom)
|
||||
this.myChart.setOption(this.chartOption, true)
|
||||
this.myChart.on('legendselectchanged', this.selectLegend)
|
||||
|
||||
this.myChart.dispatchAction({
|
||||
type: 'takeGlobalCursor',
|
||||
key: 'brush',
|
||||
brushOption: {
|
||||
brushType: 'lineX',
|
||||
xAxisIndex: 'all',
|
||||
brushMode: 'single',
|
||||
throttleType: 'debounce'
|
||||
}
|
||||
})
|
||||
this.myChart.on('brushEnd', this.brushEcharts)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -426,6 +447,29 @@ export default {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
},
|
||||
/**
|
||||
* echarts框选
|
||||
* @param params
|
||||
*/
|
||||
brushEcharts (params) {
|
||||
this.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
// 避免点击空白区域报错
|
||||
if (params.areas && params.areas.length > 0) {
|
||||
const rangeObj = {
|
||||
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||
}
|
||||
|
||||
// 暂定框选最小范围为5分钟,后续可能会变动
|
||||
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||
}
|
||||
this.$store.commit('setRangeEchartsData', rangeObj)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -49,8 +49,7 @@ export const pieChartOption1 = {
|
||||
}
|
||||
})
|
||||
name = name.length > 9 ? name.substr(0, 9) + '...' : name
|
||||
const arr = ['{a|' + ' ' + value + '}' + '{b|' + name + '}']
|
||||
return arr
|
||||
return ['{a|' + ' ' + value + '}' + '{b|' + name + '}']
|
||||
}
|
||||
},
|
||||
series: [
|
||||
@@ -108,8 +107,7 @@ export const pieChartOption2 = {
|
||||
}
|
||||
})
|
||||
name = name.length > 9 ? name.substr(0, 9) + '...' : name
|
||||
const arr = ['{a|' + ' ' + value + '}' + '{b|' + name + '}']
|
||||
return arr
|
||||
return ['{a|' + ' ' + value + '}' + '{b|' + name + '}']
|
||||
}
|
||||
},
|
||||
color: chartColor2,
|
||||
@@ -136,7 +134,7 @@ export const pieChartOption3 = {
|
||||
{
|
||||
name: 'Access From',
|
||||
type: 'pie',
|
||||
radius: ['45%', '50%'],
|
||||
radius: ['40%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
emphasis: {
|
||||
label: {
|
||||
@@ -229,6 +227,12 @@ export const linkTrafficLineChartOption = {
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
brush: {
|
||||
toolbox: ['lineX'],
|
||||
xAxisIndex: 'all',
|
||||
throttleType: 'debounce',
|
||||
transformable: false
|
||||
},
|
||||
grid: {
|
||||
top: '12%',
|
||||
left: '2%',
|
||||
@@ -393,6 +397,12 @@ export const trafficLineChartOption = {
|
||||
fontFamily: 'NotoSansSChineseRegular'
|
||||
}
|
||||
},
|
||||
brush: {
|
||||
toolbox: ['lineX'],
|
||||
xAxisIndex: 'all',
|
||||
throttleType: 'debounce',
|
||||
transformable: false
|
||||
},
|
||||
grid: {
|
||||
top: '21%',
|
||||
left: '2%',
|
||||
|
||||
@@ -180,7 +180,7 @@ export const pieForSeverity = {
|
||||
appendToBody: true
|
||||
},
|
||||
color: activeAttackColor,
|
||||
animation: false,
|
||||
animation: true,
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
type: 'plain',
|
||||
@@ -199,7 +199,7 @@ export const pieForSeverity = {
|
||||
{
|
||||
type: 'pie',
|
||||
selectedMode: 'single',
|
||||
radius: ['42%', '65%'],
|
||||
radius: ['43%', '65%'],
|
||||
center: ['30%', '50%'],
|
||||
data: [],
|
||||
label: {
|
||||
@@ -212,13 +212,6 @@ export const pieForSeverity = {
|
||||
formatter: function (param, index, callback) {
|
||||
return `${param.name}: ${param.value}`
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -244,7 +244,7 @@ export default {
|
||||
path: '/entityDetail',
|
||||
query: {
|
||||
entityType: type,
|
||||
name: name
|
||||
entityName: name
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
|
||||
@@ -275,7 +275,7 @@ export default {
|
||||
path: '/entityDetail',
|
||||
query: {
|
||||
entityType: type,
|
||||
name: name
|
||||
entityName: name
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
|
||||
@@ -236,7 +236,7 @@ export default {
|
||||
path: '/entityDetail',
|
||||
query: {
|
||||
entityType: type,
|
||||
name: name
|
||||
entityName: name
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
|
||||
@@ -379,7 +379,7 @@ export default {
|
||||
path: '/entityDetail',
|
||||
query: {
|
||||
entityType: type,
|
||||
name: name
|
||||
entityName: name
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
|
||||
@@ -22,21 +22,21 @@ export default {
|
||||
setup (props) {
|
||||
const { query } = useRoute()
|
||||
let panelType
|
||||
const entityData = { entityType: query.entityType, entityName: query.name }
|
||||
const entityData = { entityType: query.entityType, entityName: query.entityName }
|
||||
switch (query.entityType) {
|
||||
case 'ip': {
|
||||
panelType = panelTypeAndRouteMapping.ipEntityDetail
|
||||
entityData.ip = query.name
|
||||
entityData.ip = query.entityName
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
panelType = panelTypeAndRouteMapping.domainEntityDetail
|
||||
entityData.domain = query.name
|
||||
entityData.domain = query.entityName
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
panelType = panelTypeAndRouteMapping.appEntityDetail
|
||||
entityData.appName = query.name
|
||||
entityData.appName = query.entityName
|
||||
break
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -3,60 +3,60 @@
|
||||
class="entity-explorer"
|
||||
:class="{'entity-explorer--show-list': showList}">
|
||||
<!-- 顶部工具栏,在列表页显示 -->
|
||||
<!-- <div class="explorer-top-tools explorer-top-tools-new" v-show="showList">-->
|
||||
<!-- <div class="explorer-detection-top-tools">-->
|
||||
<!-- <div class="explorer-top-tools-title">{{$t('network.entity')}}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="explorer-top-tools">-->
|
||||
<!-- <DateTimeRange :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>-->
|
||||
<!-- <TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>-->
|
||||
<!-- <el-button-group size="mini">-->
|
||||
<!-- <el-button size="mini" @click="listMode = 'list'" :class="{'active': listMode === 'list'}"><i class="cn-icon cn-icon-list"></i></el-button>-->
|
||||
<!-- <el-button size="mini" @click="listMode = 'block'" :class="{'active': listMode === 'block'}"><i class="cn-icon cn-icon-blocks"></i></el-button>-->
|
||||
<!-- </el-button-group>-->
|
||||
<div class="explorer-top-tools" v-show="showList">
|
||||
<DateTimeRange :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>
|
||||
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
||||
<el-button-group size="mini">
|
||||
<el-button size="mini" @click="setListMode('list')" :class="{'active': listMode === 'list'}"><i class="cn-icon cn-icon-list"></i></el-button>
|
||||
<el-button size="mini" @click="setListMode('block')" :class="{'active': listMode === 'block'}"><i class="cn-icon cn-icon-blocks"></i></el-button>
|
||||
</el-button-group>
|
||||
<div class="explorer-top-tools explorer-top-tools-new" style="margin: 2px 0;" v-show="showList">
|
||||
<div class="explorer-detection-top-tools">
|
||||
<div class="explorer-top-tools-title" style="padding: 0;margin-left: -10px;">{{$t('network.entity')}}</div>
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 搜索组件 -->
|
||||
<explorer-search
|
||||
v-if="!showList"
|
||||
ref="search"
|
||||
:class="{'explorer-search--show-list': showList}"
|
||||
:show-list="showList"
|
||||
@search="search"
|
||||
></explorer-search>
|
||||
|
||||
<!--todo静态数据,之后记得修改-->
|
||||
<!-- <div class="explorer-result" v-if="showList">-->
|
||||
<!-- 8,866 results,IP 2666,Domain 3200,APP 3000-->
|
||||
<!-- </div>-->
|
||||
<!-- 内容区 -->
|
||||
<div class="explorer-container" v-if="showList" style="height: calc(100% - 20px); flex-direction: column">
|
||||
<div style="display: flex; height: auto;">
|
||||
<entity-filter
|
||||
:filter-data="filterData"
|
||||
:loading-left="loadingLeft"
|
||||
:q="q"
|
||||
:time-filter="timeFilter"
|
||||
@filter="filter"
|
||||
></entity-filter>
|
||||
<entity-list
|
||||
:list-data="listData"
|
||||
:list-mode="listMode"
|
||||
:pageObj="pageObj"
|
||||
:time-filter="timeFilter"
|
||||
@pageSize="pageSize"
|
||||
@pageNo="pageNo"
|
||||
:loading="listLoading"
|
||||
></entity-list>
|
||||
<div v-if="showList" style="display: flex;flex-direction: row;">
|
||||
<entity-filter
|
||||
:filter-data="newFilterData"
|
||||
:loading-left="loadingLeft"
|
||||
:q="q"
|
||||
:time-filter="timeFilter"
|
||||
@filter="filter"
|
||||
></entity-filter>
|
||||
<div class="explorer-container" style="height: calc(100% - 62px);flex-direction: column;width: 100%;">
|
||||
<explorer-search
|
||||
ref="search"
|
||||
:class="{'explorer-search--show-list': showList}"
|
||||
:show-list="showList"
|
||||
@search="search"
|
||||
></explorer-search>
|
||||
|
||||
<div style="display: flex;flex-direction: column;height: calc(100% - 42px);">
|
||||
<div class="explorer-result" v-if="showList" style="position: relative;">
|
||||
<loading :loading="loadingCount" style="width: 240px"></loading>
|
||||
<span>{{ summaryCount.total }} </span>results,IP
|
||||
<span>{{ summaryCount.ipCount }}</span>,Domain
|
||||
<span>{{ summaryCount.domainCount }}</span>,APP
|
||||
<span>{{ summaryCount.appCount }}</span>
|
||||
</div>
|
||||
|
||||
<entity-list
|
||||
style="width: 100%;"
|
||||
:list-data="listData"
|
||||
:list-mode="listMode"
|
||||
:pageObj="pageObj"
|
||||
:time-filter="timeFilter"
|
||||
@pageSize="pageSize"
|
||||
@pageNo="pageNo"
|
||||
:loading="listLoading"
|
||||
></entity-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="explorer-foot" v-else>
|
||||
|
||||
<div class="explorer-foot" v-if="!showList">
|
||||
<div>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<div class="entity-overview">
|
||||
@@ -65,16 +65,10 @@
|
||||
<loading :loading="loadingApp"></loading>
|
||||
<span class="overview-left-loading-span">{{ numberWithCommas(entityAppTotal) }}</span>
|
||||
</span>
|
||||
<span class="overview-left-span">APP</span>
|
||||
</div>
|
||||
<div class="overview-right">
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-increase"></i>
|
||||
<div class="right-label">New</div>
|
||||
<div class="right-label-loading">
|
||||
<loading :loading="loadingAppNew" size="small"></loading>
|
||||
<div class="right-value">{{ numberWithCommas(entityAppNew) }}</div>
|
||||
</div>
|
||||
APP
|
||||
</div>
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-active"></i>
|
||||
@@ -93,16 +87,10 @@
|
||||
<loading :loading="loadingDomain"></loading>
|
||||
<span class="overview-left-loading-span">{{ numberWithCommas(entityDomainTotal) }}</span>
|
||||
</span>
|
||||
<span class="overview-left-span">DOMAIN</span>
|
||||
</div>
|
||||
<div class="overview-right">
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-increase"></i>
|
||||
<div class="right-label">New</div>
|
||||
<div class="right-label-loading">
|
||||
<loading :loading="loadingDomainNew" size="small"></loading>
|
||||
<div class="right-value">{{ numberWithCommas(entityDomainNew) }}</div>
|
||||
</div>
|
||||
DOMAIN
|
||||
</div>
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-active"></i>
|
||||
@@ -121,16 +109,10 @@
|
||||
<loading :loading="loadingIp"></loading>
|
||||
<span class="overview-left-loading-span">{{ numberWithCommas(entityIpTotal) }}</span>
|
||||
</span>
|
||||
<span class="overview-left-span">IP</span>
|
||||
</div>
|
||||
<div class="overview-right">
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-increase"></i>
|
||||
<div class="right-label">New</div>
|
||||
<div class="right-label-loading">
|
||||
<loading :loading="loadingIpNew" size="small"></loading>
|
||||
<div class="right-value">{{ numberWithCommas(entityIpNew) }}</div>
|
||||
</div>
|
||||
IP
|
||||
</div>
|
||||
<div class="right-row">
|
||||
<i class="cn-icon cn-icon-active"></i>
|
||||
@@ -150,8 +132,6 @@
|
||||
|
||||
<script>
|
||||
import ExplorerSearch from '@/views/entityExplorer/search/ExplorerSearch'
|
||||
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
|
||||
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
|
||||
import EntityFilter from '@/views/entityExplorer/EntityFilter'
|
||||
import EntityList from '@/views/entityExplorer/entityList/EntityList'
|
||||
import { entityType, defaultPageSize, riskLevelMapping } from '@/utils/constants'
|
||||
@@ -172,8 +152,6 @@ export default {
|
||||
components: {
|
||||
Loading,
|
||||
ExplorerSearch,
|
||||
DateTimeRange,
|
||||
TimeRefresh,
|
||||
EntityFilter,
|
||||
EntityList
|
||||
},
|
||||
@@ -210,23 +188,15 @@ export default {
|
||||
{
|
||||
label: this.$t('overall.country'),
|
||||
column: 'countryDistinctCount',
|
||||
topColumn: 'ip_location_country', // top弹框查询字段
|
||||
topColumn: 'Country', // top弹框查询字段
|
||||
icon: 'cn-icon cn-icon-country',
|
||||
showTopTen: false,
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: this.$t('overall.province'),
|
||||
column: 'provinceDistinctCount',
|
||||
topColumn: 'ip_location_province', // top弹框查询字段
|
||||
icon: 'cn-icon cn-icon-position',
|
||||
showTopTen: false,
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: this.$t('overall.city'),
|
||||
column: 'cityDistinctCount',
|
||||
topColumn: 'ip_location_city', // top弹框查询字段
|
||||
topColumn: 'City', // top弹框查询字段
|
||||
icon: 'cn-icon cn-icon-city',
|
||||
showTopTen: false,
|
||||
value: 0
|
||||
@@ -234,7 +204,7 @@ export default {
|
||||
{
|
||||
label: this.$t('entities.asn'),
|
||||
column: 'asnDistinctCount',
|
||||
topColumn: 'ip_asn', // top弹框查询字段
|
||||
topColumn: 'ASN', // top弹框查询字段
|
||||
icon: 'cn-icon cn-icon-cloud',
|
||||
showTopTen: false,
|
||||
value: 0
|
||||
@@ -346,6 +316,26 @@ export default {
|
||||
]
|
||||
}
|
||||
],
|
||||
newFilterData: [
|
||||
{
|
||||
icon: 'cn-icon cn-icon-registration-country',
|
||||
title: 'Top Countries',
|
||||
totalCount: 0,
|
||||
data: []
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-city',
|
||||
title: 'Top Cities',
|
||||
totalCount: 0,
|
||||
data: []
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-as',
|
||||
title: 'Top ASNs',
|
||||
totalCount: 0,
|
||||
data: []
|
||||
}
|
||||
],
|
||||
listData: [],
|
||||
q: '',
|
||||
metaList: [],
|
||||
@@ -367,7 +357,14 @@ export default {
|
||||
// 实体详情列表页面 左侧筛选条件
|
||||
loadingLeft: false,
|
||||
initFlag: false, // 初始化标志,避免初始化时pageSize和pageNo会调用搜索
|
||||
timer: null // 初始化标志的延时器,需要销毁
|
||||
timer: null, // 初始化标志的延时器,需要销毁
|
||||
summaryCount: {
|
||||
total: 0,
|
||||
domainCount: 0,
|
||||
ipCount: 0,
|
||||
appCount: 0
|
||||
},
|
||||
loadingCount: false // 实体基数统计的loading
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -420,6 +417,12 @@ export default {
|
||||
return result
|
||||
},
|
||||
search (param) {
|
||||
// todo 下版本08版本删除 ---- start
|
||||
if (param && param.q.indexOf("QUERY('") > -1) {
|
||||
this.$message.error(this.$t('overall.versionNotSupportThisFormat'))
|
||||
return true
|
||||
}
|
||||
// 下版本08版本删除 ---- end
|
||||
let q
|
||||
let metaList
|
||||
if (param) {
|
||||
@@ -442,7 +445,8 @@ export default {
|
||||
q: q,
|
||||
mode: mode,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
range: this.timeFilter.dateRangeValue
|
||||
})
|
||||
|
||||
if (!this.showList) {
|
||||
@@ -454,7 +458,8 @@ export default {
|
||||
q: q,
|
||||
mode: mode,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
range: this.timeFilter.dateRangeValue
|
||||
}
|
||||
})
|
||||
this.showList = true
|
||||
@@ -487,29 +492,35 @@ export default {
|
||||
} else {
|
||||
this.limitFilterType = false
|
||||
}
|
||||
this.queryFilter({ entityType: entityType, q: this.q, ...this.timeFilter })
|
||||
if (entityType === 'ip') {
|
||||
this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
|
||||
}
|
||||
// this.queryFilter({ entityType: entityType, q: this.q, ...this.timeFilter })
|
||||
// if (entityType === 'ip') {
|
||||
// this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
|
||||
// }
|
||||
this.queryFilterNew({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
this.queryList({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
this.queryListTotal({ q: this.q, ...this.timeFilter })
|
||||
this.queryCount({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
// this.queryListTotal({ q: this.q, ...this.timeFilter })
|
||||
} else {
|
||||
this.limitFilterType = false
|
||||
this.queryFilter({ entityType: 'ip', q: this.q, ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'domain', q: this.q, ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'app', q: this.q, ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'ip', q: this.q, ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'domain', q: this.q, ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'app', q: this.q, ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'dns', q: this.q, ...this.timeFilter })
|
||||
this.queryFilterNew({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
this.queryList({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
this.queryListTotal({ q: this.q, ...this.timeFilter })
|
||||
this.queryCount({ q: this.q, ...this.pageObj, ...this.timeFilter })
|
||||
// this.queryListTotal({ q: this.q, ...this.timeFilter })
|
||||
}
|
||||
} else {
|
||||
this.limitFilterType = false
|
||||
this.queryFilter({ entityType: 'ip', ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'app', ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'domain', ...this.timeFilter })
|
||||
this.queryFilter({ entityType: 'dns', ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'ip', ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'app', ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'domain', ...this.timeFilter })
|
||||
// this.queryFilter({ entityType: 'dns', ...this.timeFilter })
|
||||
this.queryFilterNew({ ...this.pageObj, ...this.timeFilter })
|
||||
this.queryList({ ...this.pageObj, ...this.timeFilter })
|
||||
this.queryListTotal({ ...this.timeFilter })
|
||||
this.queryCount({ ...this.pageObj, ...this.timeFilter })
|
||||
// this.queryListTotal({ ...this.timeFilter })
|
||||
|
||||
// 延时一秒,避免初始化时pageSize为20,pageNo为1也会调用“搜索”的情况
|
||||
if (!this.initFlag) {
|
||||
@@ -634,27 +645,88 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 新版查询filter数据 */
|
||||
queryFilterNew (params) {
|
||||
const queryParams = {
|
||||
// startTime: getSecond(params.startTime),
|
||||
// endTime: getSecond(params.endTime),
|
||||
resource: params.q || ''
|
||||
}
|
||||
this.loadingLeft = true
|
||||
const aggCountry = get(api.entity.entityList.aggCountry, queryParams)
|
||||
const aggCity = get(api.entity.entityList.aggCity, queryParams)
|
||||
const aggAsn = get(api.entity.entityList.aggAsn, queryParams)
|
||||
|
||||
Promise.all([aggCountry, aggCity, aggAsn]).then(response => {
|
||||
response.forEach((item, index) => {
|
||||
if (item.code === 200 && item.data.list) {
|
||||
this.newFilterData[index].data = []
|
||||
item.data.list.forEach(item => {
|
||||
const obj = { label: item.value, flag: '011-china', topColumn: 'Country', value: item.uniqueEntities }
|
||||
if (index === 0) {
|
||||
obj.flag = item.uniqueEntities // 接口字段名称为'China',目前svg名称为'011-china',后续再指定方案调整
|
||||
}
|
||||
if (index === 1) {
|
||||
obj.topColumn = 'City'
|
||||
}
|
||||
if (index === 2) {
|
||||
obj.topColumn = 'ASN'
|
||||
}
|
||||
this.newFilterData[index].data.push(obj)
|
||||
})
|
||||
}
|
||||
})
|
||||
}).catch(e => {
|
||||
// e
|
||||
}).finally(() => {
|
||||
this.loadingLeft = false
|
||||
})
|
||||
},
|
||||
/** 实体列表查询 */
|
||||
queryList (params) {
|
||||
this.listLoading = true
|
||||
const queryParams = {
|
||||
...params,
|
||||
startTime: getSecond(params.startTime),
|
||||
endTime: getSecond(params.endTime)
|
||||
pageSize: params.pageSize,
|
||||
pageNo: params.pageNo,
|
||||
// startTime: getSecond(params.startTime),
|
||||
// endTime: getSecond(params.endTime),
|
||||
resource: params.q || ''
|
||||
}
|
||||
get(api.entityList, queryParams).then(response => {
|
||||
get(api.entity.entityList.list, queryParams).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.listData = []
|
||||
this.$nextTick(() => {
|
||||
this.listData = response.data.result
|
||||
this.listData = response.data.list
|
||||
this.pageObj.total = response.data.total
|
||||
})
|
||||
} else {
|
||||
console.error(response.message)
|
||||
this.$message.error(response.message)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
/** 实体基数统计 */
|
||||
queryCount (params) {
|
||||
this.loadingCount = true
|
||||
const queryParams = {
|
||||
// startTime: getSecond(params.startTime),
|
||||
// endTime: getSecond(params.endTime),
|
||||
resource: params.q || '' // 目前版本搜索不支持实体名称搜索,下版本改进
|
||||
}
|
||||
get(api.entity.entityList.summaryCount, queryParams).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.summaryCount = response.data
|
||||
} else {
|
||||
this.summaryCount = { total: 0, domainCount: 0, ipCount: 0, appCount: 0 }
|
||||
}
|
||||
}).catch(e => {
|
||||
console.log(e)
|
||||
this.summaryCount = { total: 0, domainCount: 0, ipCount: 0, appCount: 0 }
|
||||
}).finally(() => {
|
||||
this.loadingCount = false
|
||||
})
|
||||
},
|
||||
|
||||
queryListTotal (params) {
|
||||
const queryParams = {
|
||||
@@ -675,11 +747,6 @@ export default {
|
||||
},
|
||||
|
||||
getEntityIndexData () {
|
||||
const now = window.$dayJs.tz().valueOf()
|
||||
const timeFilter = {
|
||||
startTime: parseInt(now / 1000 - 3600),
|
||||
endTime: parseInt(now / 1000)
|
||||
}
|
||||
// Total
|
||||
this.loadingApp = true
|
||||
this.loadingDomain = true
|
||||
@@ -693,61 +760,37 @@ export default {
|
||||
this.loadingDomainActive = true
|
||||
this.loadingIpActive = true
|
||||
|
||||
get(api.entityTotal, { entityType: 'app' }).then(response => {
|
||||
get(api.entity.entityList.entityActive).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityAppTotal = response.data.result
|
||||
}
|
||||
this.loadingApp = false
|
||||
})
|
||||
get(api.entityTotal, { entityType: 'domain' }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityDomainTotal = response.data.result
|
||||
this.entityDomainTotal = response.data.domainCount
|
||||
this.entityIpTotal = response.data.ipCount
|
||||
this.entityAppTotal = response.data.appCount
|
||||
}
|
||||
this.loadingDomain = false
|
||||
})
|
||||
get(api.entityTotal, { entityType: 'ip' }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityIpTotal = response.data.result
|
||||
}
|
||||
this.loadingIp = false
|
||||
this.loadingApp = false
|
||||
})
|
||||
// New
|
||||
get(api.entityNew, { entityType: 'app', ...timeFilter }).then(response => {
|
||||
get(api.entity.entityList.entityNew).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityAppNew = response.data.result
|
||||
}
|
||||
this.loadingAppNew = false
|
||||
})
|
||||
get(api.entityNew, { entityType: 'domain', ...timeFilter }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityDomainNew = response.data.result
|
||||
this.entityDomainNew = response.data.domainCount
|
||||
this.entityIpNew = response.data.ipCount
|
||||
this.entityAppNew = response.data.appCount
|
||||
}
|
||||
this.loadingDomainNew = false
|
||||
})
|
||||
get(api.entityNew, { entityType: 'ip', ...timeFilter }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityIpNew = response.data.result
|
||||
}
|
||||
this.loadingIpNew = false
|
||||
this.loadingAppNew = false
|
||||
})
|
||||
// Active
|
||||
get(api.entityActive, { entityType: 'app', ...timeFilter }).then(response => {
|
||||
get(api.entity.entityList.entityActive).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityAppActive = response.data.result
|
||||
}
|
||||
this.loadingAppActive = false
|
||||
})
|
||||
get(api.entityActive, { entityType: 'domain', ...timeFilter }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityDomainActive = response.data.result
|
||||
this.entityDomainActive = response.data.domainCount
|
||||
this.entityIpActive = response.data.ipCount
|
||||
this.entityAppActive = response.data.appCount
|
||||
}
|
||||
this.loadingDomainActive = false
|
||||
})
|
||||
get(api.entityActive, { entityType: 'ip', ...timeFilter }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.entityIpActive = response.data.result
|
||||
}
|
||||
this.loadingIpActive = false
|
||||
this.loadingAppActive = false
|
||||
})
|
||||
},
|
||||
cleanFilterData (index) {
|
||||
@@ -779,10 +822,19 @@ export default {
|
||||
* @param q
|
||||
*/
|
||||
initSearch (q) {
|
||||
const str = q
|
||||
let str = q
|
||||
// 此处的mode不做text和tag区分,是因为text和tag构造搜索参数过程不一样,但结果的参数一致
|
||||
// 故采用text的参数形式进行搜索,tag形式在tagMode.vue的mounted里根据地址栏的参数q构造metaList
|
||||
if (str) {
|
||||
// 为避免地址栏任意输入导致全查询的q带QUERY,解析时不识别导致的语法错误
|
||||
// 如地址栏输入116.178.222.171,此时的q很长,刷新界面时需要把q里的116.178.222.171拿出来进行搜索
|
||||
if (str.indexOf('QUERY') > -1) {
|
||||
const strList = str.split(' ')
|
||||
if (strList.length > 0) {
|
||||
// 此时strList[1]为ip_addr:116.178.222.171,获取116.178.222.171
|
||||
str = strList[1].slice(8)
|
||||
}
|
||||
}
|
||||
const parser = new Parser(columnList)
|
||||
const errorList = parser.validateStr(str)
|
||||
if (_.isEmpty(errorList)) {
|
||||
@@ -828,7 +880,6 @@ export default {
|
||||
timeFilter.value.startTime = parseInt(startTimeParam)
|
||||
timeFilter.value.endTime = parseInt(endTimeParam)
|
||||
}
|
||||
timeFilter.value.dateRangeValue = 60
|
||||
return {
|
||||
timeFilter
|
||||
}
|
||||
|
||||
@@ -1,150 +1,94 @@
|
||||
<template >
|
||||
<div class="entity-filter-case">
|
||||
<div class="filter-case__header">{{$t('entities.filter')}}</div>
|
||||
<div
|
||||
class="entity-filter"
|
||||
v-for="(filters, index) in filterData"
|
||||
:key="index"
|
||||
>
|
||||
<div class="filter__header">{{filters.title}}</div>
|
||||
<div class="filter__body">
|
||||
<template>
|
||||
<div class="entity-filter-case" style="position: relative">
|
||||
<div class="filter-case__header">{{ $t('entities.filter1') }}</div>
|
||||
|
||||
<div class="filter__row" v-for="(item, i) in filters.data" :key="i">
|
||||
<el-popover popper-class="filter__row-popover" placement="right-start" :width="440" v-model:visible="item.showTopTen">
|
||||
<template #reference>
|
||||
<div class="filter__row-popover" @click="showTopDialog(i, item, filters)">
|
||||
<div class="row__label">
|
||||
<i :class="item.icon"></i>
|
||||
<span>{{item.label}}</span>
|
||||
</div>
|
||||
<div class="row__value">
|
||||
<loading :loading="loadingLeft" size="small"></loading>
|
||||
<span>{{item.value}}</span>
|
||||
<div v-if="filterDataLength>0">
|
||||
<div class="entity-filter" v-for="(item, index) in filterData" :key="index">
|
||||
<div v-if="item.data.length>0">
|
||||
<div class="filter__header">
|
||||
<i :class="item.icon"></i>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
|
||||
<div class="filter__body" style="position: relative">
|
||||
<loading :loading="loadingLeft" style="top: -5px;"></loading>
|
||||
|
||||
<div class="filter__body-item" v-for="(data, i) in item.data" :key="i" @click="filter(data.label, data)">
|
||||
<div class="filter__body-item-left">
|
||||
<!--当前无更好方案匹配国旗,后续解决-->
|
||||
<!--<div v-if="data.flag">-->
|
||||
<!-- <img :src="require(`../../../public/images/flag/${data.flag}.svg`)" class="filter-country-flag"/>-->
|
||||
<!--</div>-->
|
||||
<div class="filter__body-item-left-index">{{ i+1 }}</div>
|
||||
<div class="filter__body-item-left-label">
|
||||
<el-tooltip :content="data.label" placement="top" effect="light" :disabled="disabledLabel">
|
||||
<span @mouseenter="handleMouse(`filter${index}${i}`)" :id="`filter${index}${i}`">{{ data.label }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<entity-top
|
||||
ref="entityTopTenPop"
|
||||
:loading="loading"
|
||||
:popover-data="popoverData"
|
||||
:item-data="itemData"
|
||||
:total-count="totalCount"
|
||||
:top-column="item.topColumn"
|
||||
@filter="filter"
|
||||
></entity-top>
|
||||
</el-popover>
|
||||
|
||||
<div class="filter__body-item-right">{{ data.value }}</div>
|
||||
</div>
|
||||
<div class="filter-hr"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<chart-no-data v-else style="padding-top: 40px"></chart-no-data>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EntityTop from '@/views/entityExplorer/EntityTop'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
export default {
|
||||
name: 'EntityFilter',
|
||||
components: {
|
||||
Loading,
|
||||
EntityTop
|
||||
},
|
||||
components: { ChartNoData, Loading },
|
||||
props: {
|
||||
filterData: Array,
|
||||
q: String,
|
||||
timeFilter: Object,
|
||||
loadingLeft: Boolean
|
||||
filterData: {
|
||||
type: Object
|
||||
},
|
||||
loadingLeft: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterDataLength () {
|
||||
let length = 0
|
||||
this.filterData.forEach(item => {
|
||||
length += item.data.length
|
||||
})
|
||||
|
||||
return length
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
topList: 'list',
|
||||
topData: [],
|
||||
entityTopTenData: [],
|
||||
currentColumn: {},
|
||||
totalCount: 0,
|
||||
loading: false,
|
||||
popoverData: [],
|
||||
itemData: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
currentColumn (n, o) {
|
||||
if (n.column === 'dnsServerOrgCount') {
|
||||
this.totalCount = this.filterData[3].orgTotalCount
|
||||
} else if (n.column === 'dnsServerSoftwareCount') {
|
||||
this.totalCount = this.filterData[3].softwareTotalCount
|
||||
} else if (n.column === 'dnsServerOsCount') {
|
||||
this.totalCount = this.filterData[3].osTotalCount
|
||||
} else if (n.column === 'categoryDistinctCount' && n.type === 'app') {
|
||||
this.totalCount = this.filterData[1].totalCount
|
||||
} else {
|
||||
let count = 0
|
||||
this.filterData.forEach(f => {
|
||||
const filter = f.data.some(d => d.column === n.column)
|
||||
if (filter) {
|
||||
count = f.totalCount
|
||||
}
|
||||
})
|
||||
this.totalCount = count
|
||||
}
|
||||
disabledLabel: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTopDialog (i, item, filter) {
|
||||
if (this.currentColumn.column === item.column && item.showTopTen) {
|
||||
item.showTopTen = false
|
||||
return
|
||||
/**
|
||||
* 判断文字是否溢出,超出则鼠标移入tooltip显示,否则鼠标移入不显示
|
||||
* @param id
|
||||
*/
|
||||
handleMouse (id) {
|
||||
const dom = document.getElementById(id)
|
||||
if (dom) {
|
||||
const width = document.getElementById(id).offsetWidth
|
||||
this.disabledLabel = width < 180
|
||||
} else {
|
||||
this.disabledLabel = true
|
||||
}
|
||||
this.filterData.forEach(f => {
|
||||
f.data.forEach(ff => {
|
||||
ff.showTopTen = false
|
||||
})
|
||||
})
|
||||
item.showTopTen = true
|
||||
this.currentColumn = {
|
||||
column: item.column,
|
||||
type: filter.type
|
||||
}
|
||||
const queryParams = {
|
||||
q: this.q,
|
||||
entityType: filter.type,
|
||||
column: item.topColumn,
|
||||
top: 10,
|
||||
startTime: parseInt(this.timeFilter.startTime / 1000),
|
||||
endTime: parseInt(this.timeFilter.endTime / 1000)
|
||||
}
|
||||
this.loading = true
|
||||
this.popoverData = []
|
||||
this.itemData = {}
|
||||
get(api.filterTop, queryParams).then(response => {
|
||||
if (response.code === 200) {
|
||||
if (this.currentColumn.column === item.column) {
|
||||
if (filter.type === 'dns') {
|
||||
this.popoverData = response.data.result.filter(f => {
|
||||
return f.count > 0
|
||||
})
|
||||
} else {
|
||||
this.popoverData = response.data.result
|
||||
}
|
||||
this.itemData = item
|
||||
}
|
||||
} else {
|
||||
this.popoverData = []
|
||||
this.itemData = item
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
this.popoverData = []
|
||||
this.itemData = item
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
filter (name, topData) {
|
||||
this.showTopDialog('', topData)
|
||||
console.log('打印数据', name, topData)
|
||||
this.$emit('filter', name, topData)
|
||||
filter (name, data) {
|
||||
this.$emit('filter', name, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
119
src/views/entityExplorer/entityGraphDetail/AppList.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div>
|
||||
<loading :loading="entity.loading" size="small"></loading>
|
||||
<div class="graph-list-header">
|
||||
<div>
|
||||
<div class="graph-list-header-title">
|
||||
<i class="graph-list-header-icon cn-icon cn-icon-app-name"></i>
|
||||
<span>{{ $t('entities.tab.relatedApp') }}</span>
|
||||
</div>
|
||||
<div class="graph-list-header-number">
|
||||
{{ $t('entity.graph.associatedCount') }}: <span>{{entity.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
<div class="graph-list-expand-btn-block">
|
||||
<div class="graph-list-expand-btn" :class="{ 'graph-list-expand-btn--disabled': expandBtnDisable }" style="display: inline-flex;" @click="expandList">
|
||||
<i class="cn-icon cn-icon-expand-continue graph-expand-continue"></i>
|
||||
{{ $t('entity.graph.continueToExpand') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="digital-certificate">
|
||||
<div class="digital-certificate-header padding-b-12">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-list-content-header ">
|
||||
{{ $t('entity.graph.expandedEntityCount') }}:
|
||||
<span>{{ entity.listData ? entity.listData.length : 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-content">
|
||||
<div v-for="(item, index) in entity.listData" :key="index" @mouseenter="onMouseenter(item)">
|
||||
<div class="graph-list-item-ip" @click="expandDetail">{{ item.vertex }}</div>
|
||||
<div class="graph-list-item-block">
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">APP ID:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.appId', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.category')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.appCategory', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.subcategory')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.appSubcategory', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.riskLevel')}}:</div>
|
||||
<div class="graph-list-item-value">{{ appRisk($_.get(item.detail, 'category.appRisk', '-')) }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('config.dataSource.description')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.appDescription', '-') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="graph-list-dividing-line" v-if="index !== entity.listData.length - 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { riskLevelMapping } from '@/utils/constants'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import { scrollToTop } from '@/utils/tools'
|
||||
export default {
|
||||
name: 'AppList',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
computed: {
|
||||
appRisk () {
|
||||
return function (level) {
|
||||
const m = riskLevelMapping.find(mapping => {
|
||||
return mapping.value == level
|
||||
})
|
||||
return (m && m.name) || level
|
||||
}
|
||||
},
|
||||
expandBtnDisable () {
|
||||
return !((this.entity.listData ? this.entity.listData.length : 0) < this.entity.count && this.entity.count > 10 && (this.entity.listData && this.entity.listData.length < 50))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
expandDetail () {
|
||||
if (this.entity.entityType === 'app') {
|
||||
this.$emit('expandDetail', 'appDetail')
|
||||
} else if (this.entity.entityType === 'domain') {
|
||||
this.$emit('expandDetail', 'domainDetail')
|
||||
}
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
this.$emit('mouseenter', val)
|
||||
},
|
||||
expandList () {
|
||||
// 继续拓展ip列表,传递信息,调用接口
|
||||
this.$emit('expandList', this.entity.sourceName, this.entity.nodeId)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
scrollToTop()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
115
src/views/entityExplorer/entityGraphDetail/DomainList.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<loading :loading="entity.loading" size="small"></loading>
|
||||
<div class="graph-list-header">
|
||||
<div>
|
||||
<div class="graph-list-header-title">
|
||||
<i class="graph-list-header-icon cn-icon cn-icon-subdomain"></i>
|
||||
<span>{{ entity.isSubdomain ? $t('entities.subdomain') : (entity.sourceType === 'ip' ? $t('entity.graph.resolveDomain') : $t('entities.relatedDomain')) }}</span>
|
||||
</div>
|
||||
<div class="graph-list-header-number">
|
||||
{{ $t('entity.graph.associatedCount') }}: <span>{{entity.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
<div class="graph-list-expand-btn-block">
|
||||
<div class="graph-list-expand-btn" :class="{ 'graph-list-expand-btn--disabled': expandBtnDisable }" style="display: inline-flex;" @click="expandList">
|
||||
<i class="cn-icon cn-icon-expand-continue graph-expand-continue"></i>
|
||||
{{ $t('entity.graph.continueToExpand') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="digital-certificate">
|
||||
<div class="digital-certificate-header padding-b-12">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-list-content-header ">
|
||||
{{ $t('entity.graph.expandedEntityCount') }}:
|
||||
<span>{{ entity.listData ? entity.listData.length : 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-content">
|
||||
<div v-for="(item, index) in entity.listData" :key="index" @mouseenter="onMouseenter(item)">
|
||||
<div class="graph-list-item-ip" @click="expandDetail">{{ item.vertex }}</div>
|
||||
<div class="graph-list-item-block">
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.category')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.name', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.group')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'category.group', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.registration')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'whois.registrantCountry', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-list-item__app">
|
||||
<div class="graph-list-item-label__app">{{$t('entities.registry')}}:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'whois.registrantOrg', '-') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="graph-list-dividing-line" v-if="index !== entity.listData.length - 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { riskLevelMapping } from '@/utils/constants'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import { scrollToTop } from '@/utils/tools'
|
||||
export default {
|
||||
name: 'DomainList',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
computed: {
|
||||
appRisk () {
|
||||
return function (level) {
|
||||
const m = riskLevelMapping.find(mapping => {
|
||||
return mapping.value == level
|
||||
})
|
||||
return (m && m.name) || level
|
||||
}
|
||||
},
|
||||
expandBtnDisable () {
|
||||
return !((this.entity.listData ? this.entity.listData.length : 0) < this.entity.count && this.entity.count > 10 && (this.entity.listData && this.entity.listData.length < 50))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
expandDetail () {
|
||||
if (this.entity.entityType === 'app') {
|
||||
this.$emit('expandDetail', 'appDetail')
|
||||
} else if (this.entity.entityType === 'domain') {
|
||||
this.$emit('expandDetail', 'domainDetail')
|
||||
}
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
this.$emit('mouseenter', val)
|
||||
},
|
||||
expandList () {
|
||||
// 继续拓展ip列表,传递信息,调用接口
|
||||
this.$emit('expandList', this.entity.sourceName, this.entity.nodeId)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
scrollToTop()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
493
src/views/entityExplorer/entityGraphDetail/GraphDetail.vue
Normal file
@@ -0,0 +1,493 @@
|
||||
<template>
|
||||
<!--title-->
|
||||
<div class="graph-detail-basic-info">
|
||||
<div style="display: flex">
|
||||
<div class="graph-detail__icon"><i :class="iconClass"></i></div>
|
||||
|
||||
<div class="graph-detail-header">
|
||||
<div class="entity-graph-type">{{ entityType[entity.type || entity.entityType] }}</div>
|
||||
<div class="graph-basic-info">
|
||||
<div class="graph-basic-info-name__block">
|
||||
<div class="graph-basic-info-name" :title="$_.get(entity, 'detailData.vertex', '')" id="entityName">{{ $_.get(entity, 'detailData.vertex', '') }}</div>
|
||||
<div class="graph-basic-info-icon" @click="copyEntityName">
|
||||
<i class="cn-icon cn-icon-copy"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
|
||||
<!--basic info-->
|
||||
<div class="digital-certificate graph-basic-info__block">
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-basic-info__block-title">
|
||||
{{ $t('overall.basicInfo') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-basic-info__block-content">
|
||||
<template v-if="entity.type === 'ip'">
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.asNumber') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity.detailData, 'detail.asn.asn', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.asOrg') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity.detailData, 'detail.asn.organization', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.graph.isp') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity.detailData, 'detail.location.isp', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('overall.location') }}:</div>
|
||||
<div class="graph-content-item-value">{{ location(entity.detailData) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="entity.type === 'domain'">
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.category') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.name', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.group') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.group', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.creditLevel2') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.reputationLevel', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.graph.expirationDate') }}:</div>
|
||||
<div class="graph-content-item-value">{{ handleDate('detailData.detail.whois.expireDate') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.registrar') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.whois.registrarName', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.registry') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.whois.registrantOrg', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.registrationCountry') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.whois.registrantCountry', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.registrationDate') }}:</div>
|
||||
<div class="graph-content-item-value">{{ handleDate('detailData.detail.whois.createDate') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.registryEmail') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.whois.email', '-') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="entity.type === 'app'">
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.category') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.appCategory', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.subcategory') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.appSubcategory', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('entities.riskLevel') }}:</div>
|
||||
<div class="graph-content-item-value">{{ appRisk($_.get(entity, 'detailData.detail.category.appRisk', '-')) }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('overall.technology') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.appTechnology', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('overall.appFullName') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.appLongname', '-') }}</div>
|
||||
</div>
|
||||
<div class="graph-content-item" >
|
||||
<div class="graph-content-item-label">{{ $t('config.dataSource.description') }}:</div>
|
||||
<div class="graph-content-item-value">{{ $_.get(entity, 'detailData.detail.category.appDescription', '-') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--关系拓展-->
|
||||
<div class="digital-certificate graph-basic-info__block">
|
||||
<loading :loading="entity.loading" size="small"></loading>
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-basic-info__block-title">
|
||||
{{ $t('entity.graph.relationshipExpansion') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-basic-info__block-content" style="margin-top: -4px;">
|
||||
<div v-for="item in relationList" :key="item.name">
|
||||
<div class="graph-content-item graph-content-relationship-item" v-if="item.value === item.total">
|
||||
<div class="graph-relationship-item-label">
|
||||
<i class="margin-r-6" :class="item.icon"></i>
|
||||
<span>{{ item.label }}:</span>
|
||||
</div>
|
||||
<div class="graph-relationship-item-value">
|
||||
<span class="margin-r-6">{{ item.value }}/{{ item.total }}</span>
|
||||
<i class="cn-icon cn-icon-expand-relationship" :style="{color: iconColor(item.value, item.total)}"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="graph-content-item graph-content-relationship-item">
|
||||
<div class="graph-relationship-item-label">
|
||||
<i class="graph-relationship-item-label-icon margin-r-6" :class="item.icon"></i>
|
||||
<span>{{ item.label }}:</span>
|
||||
</div>
|
||||
<div class="graph-relationship-item-value">
|
||||
<span class="margin-r-6">{{ item.value }}/{{ item.total }}</span>
|
||||
<i class="cn-icon cn-icon-expand-relationship graph-expand-relationship__icon" :style="{color: iconColor(item.value, item.total)}" @click="expandRelation(item.name)"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--标签-->
|
||||
<div v-if="entity.tags && entity.tags.length > 1" class="digital-certificate graph-basic-info__block">
|
||||
<div class="digital-certificate-header padding-b-10">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-basic-info__block-title">
|
||||
{{ $t('entity.graph.tags') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="entity-detail graph-basic-info__block-content">
|
||||
<div class="graph-tag-list">
|
||||
<div v-for="ic in entity.tags" :key="ic.value">
|
||||
<div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`">
|
||||
<span>{{ic.value}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { copySelectionText, selectElementText } from '@/utils/tools'
|
||||
import { entityType, riskLevelMapping } from '@/utils/constants'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import Loading from '@/components/common/Loading'
|
||||
|
||||
export default {
|
||||
name: 'DomainDetail',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
mixins: [chartMixin],
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
entityType
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
appRisk () {
|
||||
return function (level) {
|
||||
const m = riskLevelMapping.find(mapping => {
|
||||
return mapping.value == level
|
||||
})
|
||||
return (m && m.name) || level
|
||||
}
|
||||
},
|
||||
iconClass () {
|
||||
let className
|
||||
switch (this.entity.type) {
|
||||
case ('ip'): {
|
||||
className = 'cn-icon cn-icon-ip2'
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
className = 'cn-icon cn-icon-domain2'
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
className = 'cn-icon cn-icon-app2'
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return className
|
||||
},
|
||||
handleDate () {
|
||||
return function (key) {
|
||||
const date = _.get(this.entity, key, '')
|
||||
return date ? dateFormatByAppearance(date) : '-'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
entity: {
|
||||
deep: true,
|
||||
handler (n) {
|
||||
this.handleDetailData(n)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.handleDetailData(this.entity)
|
||||
},
|
||||
setup (props) {
|
||||
const detailCards = ref([])
|
||||
const relationList = ref([])
|
||||
const tagList = ref([])
|
||||
|
||||
return {
|
||||
detailCards,
|
||||
relationList,
|
||||
tagList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 复制实体名称 */
|
||||
copyEntityName () {
|
||||
selectElementText(document.getElementById('entityName'))
|
||||
if (copySelectionText()) {
|
||||
this.$message.success(this.$t('tip.copySuccess'))
|
||||
} else {
|
||||
this.$message.error('Unknown error')
|
||||
}
|
||||
},
|
||||
/** 修改关系拓展图标颜色,全部拓展浅灰色,否则深灰色 */
|
||||
iconColor (length, total) {
|
||||
if (length < total) {
|
||||
if (length === 50) {
|
||||
return 'rgba(57, 57, 57, 0.5)'
|
||||
} else {
|
||||
return 'rgba(57, 57, 57, 1)'
|
||||
}
|
||||
} else {
|
||||
return 'rgba(57, 57, 57, 0.5)'
|
||||
}
|
||||
},
|
||||
// 关闭右侧详情栏
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
/** 构造地址,国-省市-市 */
|
||||
handleLocation (data) {
|
||||
const location = []
|
||||
if (data.country) {
|
||||
location.push(data.country)
|
||||
}
|
||||
if (data.province) {
|
||||
location.push(data.province)
|
||||
}
|
||||
if (data.city) {
|
||||
location.push(data.city)
|
||||
}
|
||||
return location.join(' - ')
|
||||
},
|
||||
/** 关系拓展 */
|
||||
expandRelation (name) {
|
||||
this.$emit('expandDetailList', name === 'subDomain' ? 'domain' : name, this.entity.name)
|
||||
},
|
||||
httpError (e) {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
},
|
||||
location (detailData) {
|
||||
let location = ''
|
||||
if (detailData) {
|
||||
const data = detailData.detail
|
||||
if (data) {
|
||||
if (data.city) {
|
||||
location = data.city
|
||||
}
|
||||
if (data.province) {
|
||||
location = location ? `${data.province}, ${location}` : data.province
|
||||
}
|
||||
if (data.country) {
|
||||
location = location ? `${data.country}, ${location}` : data.country
|
||||
}
|
||||
}
|
||||
}
|
||||
return location || '-'
|
||||
},
|
||||
handleDetailData (entity) {
|
||||
const n = entity
|
||||
const type = n.type || n.entityType
|
||||
switch (type) {
|
||||
case 'ip': {
|
||||
this.detailCards = [
|
||||
{ name: 'asn', label: this.$t('entities.asNumber'), value: _.get(n.detailData, 'detail.asn.asn', '-') },
|
||||
{
|
||||
name: 'asOrg',
|
||||
label: this.$t('entities.asOrg'),
|
||||
value: _.get(n.detailData, 'detail.asn.organization', '-')
|
||||
},
|
||||
{
|
||||
name: 'isp',
|
||||
label: this.$t('entities.graph.isp'),
|
||||
value: _.get(n.detailData, 'detail.location.isp', '-')
|
||||
},
|
||||
{ name: 'location', label: this.$t('overall.location'), value: this.location(n.detailData) }
|
||||
]
|
||||
this.relationList = [
|
||||
{
|
||||
icon: 'cn-icon cn-icon-subdomain',
|
||||
name: 'domain',
|
||||
label: this.$t('entity.graph.resolveDomain'),
|
||||
value: _.get(n.relatedEntityCount, 'domain.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'domain.total', '0') || 0
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-app-name',
|
||||
name: 'app',
|
||||
label: this.$t('entities.tab.relatedApp'),
|
||||
value: _.get(n.relatedEntityCount, 'app.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'app.total', '0') || 0
|
||||
}
|
||||
]
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
const expireDate = _.get(n.detailData, 'detail.whois.expireDate', '')
|
||||
const createDate = _.get(n.detailData, 'detail.whois.createDate', '')
|
||||
this.detailCards = [
|
||||
{
|
||||
name: 'categoryName',
|
||||
label: this.$t('entities.category'),
|
||||
value: _.get(n.detailData, 'detail.category.name', '-')
|
||||
},
|
||||
{
|
||||
name: 'categoryGroup',
|
||||
label: this.$t('entities.group'),
|
||||
value: _.get(n.detailData, 'detail.category.group', '-')
|
||||
},
|
||||
{
|
||||
name: 'reputationLevel',
|
||||
label: this.$t('entities.creditLevel2'),
|
||||
value: _.get(n.detailData, 'detail.category.reputationLevel', '-')
|
||||
},
|
||||
{
|
||||
name: 'expireDate',
|
||||
label: this.$t('entities.graph.expirationDate'),
|
||||
value: expireDate ? dateFormatByAppearance(expireDate) : '-'
|
||||
},
|
||||
{
|
||||
name: 'registrarName',
|
||||
label: this.$t('entities.registrar'),
|
||||
value: _.get(n.detailData, 'detail.whois.registrarName', '-')
|
||||
},
|
||||
{
|
||||
name: 'registrantOrg',
|
||||
label: this.$t('entities.registry'),
|
||||
value: _.get(n.detailData, 'detail.whois.registrantOrg', '-')
|
||||
},
|
||||
{
|
||||
name: 'registrantCountry',
|
||||
label: this.$t('entities.registrationCountry'),
|
||||
value: _.get(n.detailData, 'detail.whois.registrantCountry', '-')
|
||||
},
|
||||
{
|
||||
name: 'createDate',
|
||||
label: this.$t('entities.registrationDate'),
|
||||
value: createDate ? dateFormatByAppearance(createDate) : '-'
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
label: this.$t('entities.registryEmail'),
|
||||
value: _.get(n.detailData, 'detail.whois.email', '-')
|
||||
}
|
||||
]
|
||||
this.relationList = [
|
||||
{
|
||||
icon: 'cn-icon cn-icon-resolve-ip',
|
||||
name: 'ip',
|
||||
label: this.$t('entities.graph.resolveIp'),
|
||||
value: _.get(n.relatedEntityCount, 'ip.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'ip.total', '0') || 0
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-subdomain',
|
||||
name: 'subDomain',
|
||||
label: this.$t('entities.subdomain'),
|
||||
value: _.get(n.relatedEntityCount, 'subDomain.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'subDomain.total', '0') || 0
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-app-name',
|
||||
name: 'app',
|
||||
label: this.$t('entities.tab.relatedApp'),
|
||||
value: _.get(n.relatedEntityCount, 'app.current', 0) || 0,
|
||||
total: _.get(n.relatedEntityCount, 'app.total', 0) || 0
|
||||
}
|
||||
]
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
this.detailCards = [
|
||||
{
|
||||
name: 'appCategory',
|
||||
label: this.$t('entities.category'),
|
||||
value: _.get(n.detailData, 'detail.category.appCategory', '-')
|
||||
},
|
||||
{
|
||||
name: 'appSubcategory',
|
||||
label: this.$t('entities.subcategory'),
|
||||
value: _.get(n.detailData, 'detail.category.appSubcategory', '-')
|
||||
},
|
||||
{
|
||||
name: 'appRisk',
|
||||
label: this.$t('entities.riskLevel'),
|
||||
value: _.get(n.detailData, 'detail.category.appRisk', '-')
|
||||
},
|
||||
{
|
||||
name: 'appTechnology',
|
||||
label: this.$t('overall.technology'),
|
||||
value: _.get(n.detailData, 'detail.category.appTechnology', '-')
|
||||
},
|
||||
{
|
||||
name: 'appLongname',
|
||||
label: this.$t('overall.appFullName'),
|
||||
value: _.get(n.detailData, 'detail.category.appLongname', '-')
|
||||
},
|
||||
{
|
||||
name: 'appDescription',
|
||||
label: this.$t('config.dataSource.description'),
|
||||
value: _.get(n.detailData, 'detail.category.appDescription', '-')
|
||||
}
|
||||
]
|
||||
|
||||
this.relationList = [
|
||||
{
|
||||
icon: 'cn-icon cn-icon-resolve-ip',
|
||||
name: 'ip',
|
||||
label: this.$t('entities.tab.relatedIp'),
|
||||
value: _.get(n.relatedEntityCount, 'ip.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'ip.total', '0') || 0
|
||||
},
|
||||
{
|
||||
icon: 'cn-icon cn-icon-subdomain',
|
||||
name: 'domain',
|
||||
label: this.$t('entities.graph.relatedDomain'),
|
||||
value: _.get(n.relatedEntityCount, 'domain.current', '0') || 0,
|
||||
total: _.get(n.relatedEntityCount, 'domain.total', '0') || 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +1,101 @@
|
||||
<template>
|
||||
<div>
|
||||
<loading :loading="entity.loading" size="small"></loading>
|
||||
<div class="graph-list-header">
|
||||
<div>
|
||||
<div class="graph-list-header-title">
|
||||
<i class="cn-icon cn-icon-resolve-ip graph-list-header-icon"></i>
|
||||
<span>{{ entity.sourceType === 'domain' ? $t('entities.graph.resolveIp') : $t('entities.tab.relatedIp') }}</span>
|
||||
</div>
|
||||
<div class="graph-list-header-number">
|
||||
{{ $t('entity.graph.associatedCount') }}: <span>{{entity.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="cn-icon cn-icon-close graph-close" @click="closeBlock"></i>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-expand-btn-block">
|
||||
<div class="graph-list-expand-btn" :class="{ 'graph-list-expand-btn--disabled': expandBtnDisable }" style="display: inline-flex;" @click="expandList">
|
||||
<i class="cn-icon cn-icon-expand-continue graph-expand-continue"></i>
|
||||
{{ $t('entity.graph.continueToExpand') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="digital-certificate">
|
||||
<div class="digital-certificate-header padding-b-16">
|
||||
<div class="digital-certificate-header__icon graph-header__icon"></div>
|
||||
<div class="graph-list-content-header ">
|
||||
{{ $t('entity.graph.expandedEntityCount') }}:
|
||||
<span>{{ entity.listData ? entity.listData.length : 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-content">
|
||||
<div v-for="(item, index) in entity.listData" :key="index" @mouseenter="onMouseenter(item)">
|
||||
<div class="graph-list-item-ip"><span @click="expandDetail">{{ item.vertex }}</span></div>
|
||||
<div class="graph-list-item-block">
|
||||
<div class="graph-list-item padding-b-4">
|
||||
<div class="graph-list-item-label">{{ $t('overall.location') }}:</div>
|
||||
<div class="graph-list-item-value graph-list-item-value1" style="display: flex;align-items: center;">
|
||||
<!-- <img :src="require(`../../../../public/images/flag/${item.flag}.svg`)" class="graph-list-country-flag"/>-->
|
||||
<span>{{ $_.get(item.detail, 'location.city', '-') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-item">
|
||||
<div class="graph-list-item-label">ASN:</div>
|
||||
<div class="graph-list-item-value">{{ $_.get(item.detail, 'asn.asn', '-') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="graph-list-dividing-line" v-if="index !== entity.listData.length - 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Loading from '@/components/common/Loading'
|
||||
import { scrollToTop } from '@/utils/tools'
|
||||
export default {
|
||||
name: 'IpList'
|
||||
name: 'IpList',
|
||||
props: {
|
||||
entity: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
computed: {
|
||||
expandBtnDisable () {
|
||||
return !((this.entity.listData ? this.entity.listData.length : 0) < this.entity.count && this.entity.count > 10 && (this.entity.listData && this.entity.listData.length < 50))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBlock () {
|
||||
this.$emit('closeBlock')
|
||||
},
|
||||
expandDetail () {
|
||||
this.$emit('expandDetail', 'ipDetail')
|
||||
},
|
||||
onMouseenter (val) {
|
||||
// 鼠标移动过graph列表名称时,graph图的分支图形会变大一点
|
||||
this.$emit('mouseenter', val)
|
||||
},
|
||||
expandList () {
|
||||
// 继续拓展ip列表,传递信息,调用接口
|
||||
this.$emit('expandList', this.entity.sourceName, this.entity.nodeId)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
scrollToTop()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -9,77 +9,78 @@
|
||||
<div class="cn-entity__case">
|
||||
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
||||
<div class="cn-entity__row">
|
||||
<div class="cn-entity__header">
|
||||
{{ entityData.ipAddr || entityData.domainName || entityData.appName || 'Unknown' }}
|
||||
<!-- <div class="cn-entity__header" style="display: flex">-->
|
||||
<!-- <span class="cn-entity__header-title">{{ entityData.ipAddr || entityData.domainName || entityData.appName || 'Unknown' }}</span>-->
|
||||
<!-- <span class="entity-detail" style="display: flex">-->
|
||||
<!-- <span style="width: 62px;" class="entity-tag entity-tag--small entity-tag--level-two-positive margin-r-6">信息技术</span>-->
|
||||
<!-- <span style="width: 50px;" class="entity-tag entity-tag--small entity-tag--level-two-normal margin-r-6">互联网</span>-->
|
||||
<!-- </span>-->
|
||||
<!--标签-->
|
||||
<div class="cn-entity__header" style="display: flex;align-items: center">
|
||||
<span class="cn-entity__header-title">{{ entityData.entityValue || 'Unknown' }}</span>
|
||||
<span class="entity-detail" style="display: flex;margin-left: 6px;margin-top: 1px;">
|
||||
<span v-for="(item, index) in levelTwoTags" :key="index" class="entity-tag entity-tag--small margin-r-10" :class="`entity-tag--level-two-${item.type}`">
|
||||
{{ item.value }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="cn-entity__body">
|
||||
<div class="body__basic-info">
|
||||
<div class="basic-info">
|
||||
<template v-if="entityData.entityType === 'ip'">
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-country"></i>
|
||||
<span>{{ $t('overall.country') }} : </span>
|
||||
<span>{{ entityData.ipLocationCountry || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('overall.country') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.location ? entityData.location.country : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-position"></i>
|
||||
<span>{{ $t('overall.region') }} : </span>
|
||||
<span>{{ ipLocationRegion(entityData) }}</span>
|
||||
<span class="row-item-label">{{ $t('overall.region') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.location ? ipLocationRegion(entityData.location) : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-cloud"></i>
|
||||
<span>{{ $t('entities.asn') }} : </span>
|
||||
<span>{{ entityData.ipAsn || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('entities.asn') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.asn ? entityData.asn.asn : '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="entityData.entityType === 'domain'">
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-category"></i>
|
||||
<span>{{ $t('entities.domainDetail.categoryGroup') }} : </span>
|
||||
<span>{{ entityData.domainCategoryGroup || '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-sub-category"></i>
|
||||
<span>{{ $t('entities.category') }} : </span>
|
||||
<span>{{ entityData.domainCategory || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? entityData.category.name : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-credit"></i>
|
||||
<span>{{ $t('entities.reputationLevel') }} : </span>
|
||||
<span>{{ entityData.domainReputationScore || '-' }}</span>
|
||||
<i class="cn-icon cn-icon-category"></i>
|
||||
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? entityData.category.group : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-credit-rating"></i>
|
||||
<span class="row-item-label">{{ $t('entities.reputationLevel') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? entityData.category.reputationLevel : '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="entityData.entityType === 'app'">
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-id"></i>
|
||||
<span>{{ $t('entities.category') }} : </span>
|
||||
<span>{{ entityData.appCategory || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? entityData.category.appCategory : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-category"></i>
|
||||
<span>{{ $t('entities.subcategory') }} : </span>
|
||||
<span>{{ entityData.appSubcategory || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? entityData.category.appSubcategory : '-' }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-sub-category"></i>
|
||||
<span>{{ $t('entities.risk') }} : </span>
|
||||
<span>{{ appRisk(entityData.appRisk) || '-' }}</span>
|
||||
<span class="row-item-label">{{ $t('entities.risk') }} : </span>
|
||||
<span class="row-item-value">{{ entityData.category ? appRisk(entityData.category.appRisk) : '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 通用字段 -->
|
||||
<div class="basic-info__item">
|
||||
<div class="item__box">
|
||||
<i class="cn-icon cn-icon-rise"></i>
|
||||
<span>{{ $t('entities.sentThroughput') }} : </span>
|
||||
<span>
|
||||
<span class="row-item-label">{{ $t('entities.sentThroughput') }} : </span>
|
||||
<span class="row-item-value">
|
||||
{{
|
||||
entityData.bytesSentRate ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'
|
||||
unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') !=='- ' ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'
|
||||
}}
|
||||
</span>
|
||||
<!-- 曲线-->
|
||||
@@ -107,11 +108,9 @@
|
||||
<div class="basic-info__item">
|
||||
<div class="item__box">
|
||||
<i class="cn-icon cn-icon-fall"></i>
|
||||
<span>{{ $t('entities.receivedThroughput') }} : </span>
|
||||
<span>
|
||||
{{
|
||||
entityData.bytesReceivedRate ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-'
|
||||
}}
|
||||
<span class="row-item-label">{{ $t('entities.receivedThroughput') }} : </span>
|
||||
<span class="row-item-value">
|
||||
{{ unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-' }}
|
||||
</span>
|
||||
<div class="item-box-loading">
|
||||
<loading :loading="loading" size="small"></loading>
|
||||
@@ -133,34 +132,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--新版实体列表改版,去除这一段-->
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-entity-alert"></i>
|
||||
<span>{{ $t('entities.recentAlert') }} : </span>
|
||||
<span>{{ entityData.performanceCount }}</span>
|
||||
</div>
|
||||
<div class="basic-info__item">
|
||||
<i class="cn-icon cn-icon-safe"></i>
|
||||
<span>{{ $t('entities.recentSecurity') }} : </span>
|
||||
<span>{{ entityData.securityCount }}</span>
|
||||
</div>
|
||||
<!--新版实体列表改版,去除这一段-->
|
||||
</div>
|
||||
<div class="show-detail" @click="showDetail">
|
||||
{{ $t('overall.detail') }}>
|
||||
</div>
|
||||
<!-- 新版实体列表改版,后续记得解开-->
|
||||
<!-- <div class="show-detail">-->
|
||||
<!-- <div @click="showDetail"><i class="cn-icon cn-icon-detail"></i>{{ $t('overall.detail') }} ></div>-->
|
||||
<!-- <div><i class="cn-icon cn-icon-graph"></i>{{ $t('entities.graph') }} ></div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-show-detail">
|
||||
<div @click="showDetail"><i class="cn-icon cn-icon-detail"></i>{{ $t('overall.detail') }} ></div>
|
||||
<div @click="showGraph"><i class="cn-icon cn-icon-graph"></i>{{ $t('entities.graph') }} ></div>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div class="cn-entity__detail-overview" v-if="!isCollapse">
|
||||
<el-divider></el-divider>
|
||||
<detail-overview :entity="entityData" :time-filter="timeFilter"/>
|
||||
<detail-overview :entity="entityData" :time-filter="timeFilter" @reloadEntity="getEntity" />
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
@@ -172,6 +155,10 @@ import DetailOverview from '@/views/entityExplorer/entityList/detailOverview/Det
|
||||
import entityListMixin from './entityListMixin'
|
||||
import relatedServer from '@/mixins/relatedServer'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import { entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'Row',
|
||||
@@ -188,35 +175,109 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
isCollapse: true // 是否是折叠状态
|
||||
isCollapse: true, // 是否是折叠状态
|
||||
levelTwoTags: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ipLocationRegion () {
|
||||
return function (entityData) {
|
||||
const hasProvinceAndCity =
|
||||
entityData.ipLocationProvince &&
|
||||
entityData.ipLocationCity &&
|
||||
entityData.ipLocationProvince !== 'null' &&
|
||||
entityData.ipLocationCity !== 'null'
|
||||
entityData.province &&
|
||||
entityData.city &&
|
||||
entityData.province !== 'null' &&
|
||||
entityData.city !== 'null'
|
||||
const hasProvince =
|
||||
entityData.ipLocationProvince &&
|
||||
entityData.ipLocationProvince !== 'null'
|
||||
entityData.province &&
|
||||
entityData.province !== 'null'
|
||||
const hasCity =
|
||||
entityData.ipLocationCity && entityData.ipLocationCity !== 'null'
|
||||
entityData.city && entityData.city !== 'null'
|
||||
if (hasProvinceAndCity) {
|
||||
return `${entityData.ipLocationProvince}, ${entityData.ipLocationCity}`
|
||||
return `${entityData.province}, ${entityData.city}`
|
||||
} else if (hasProvince) {
|
||||
return entityData.ipLocationProvince
|
||||
return entityData.province
|
||||
} else if (hasCity) {
|
||||
return entityData.ipLocationCity
|
||||
return entityData.city
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initData()
|
||||
this.initTagsData()
|
||||
},
|
||||
methods: {
|
||||
initData () {
|
||||
let url = ''
|
||||
switch (this.entity.entityType) {
|
||||
case ('domain'): {
|
||||
url = api.entity.entityList.domainBasicInfo
|
||||
break
|
||||
}
|
||||
case ('ip'): {
|
||||
url = api.entity.entityList.ipBasicInfo
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
url = api.entity.entityList.appBasicInfo
|
||||
break
|
||||
}
|
||||
}
|
||||
axios.get(`${url}?resource=${this.entity.entityValue}`).then(response => {
|
||||
this.$nextTick(() => {
|
||||
this.entityData = { ...response.data.data, ...this.entity }
|
||||
})
|
||||
})
|
||||
},
|
||||
initTagsData () {
|
||||
let url = ''
|
||||
switch (this.entity.entityType) {
|
||||
case ('domain'): {
|
||||
url = api.entity.entityList.domainTags
|
||||
break
|
||||
}
|
||||
case ('ip'): {
|
||||
url = api.entity.entityList.ipTags
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
url = api.entity.entityList.appTags
|
||||
break
|
||||
}
|
||||
}
|
||||
axios.get(`${url}?resource=${this.entity.entityValue}`).then(responese => {
|
||||
const res = responese.data
|
||||
if (res.code === 200) {
|
||||
Object.keys(res.data).forEach(k => {
|
||||
if (k !== 'userDefinedTags' && res.data[k]) {
|
||||
Object.keys(res.data[k]).forEach(k2 => {
|
||||
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
||||
if (find) {
|
||||
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(k, k2, res.data[k][k2]), type: find.type })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
if (_.isArray(res.data.userDefinedTags)) {
|
||||
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, type: 'normal' })))
|
||||
}
|
||||
this.hideTagArea = _.isEmpty(this.levelTwoTags)
|
||||
}
|
||||
})
|
||||
},
|
||||
tagValueHandler (k, k2, value) {
|
||||
if (k === 'psiphon3Ip') {
|
||||
if (k2 === 'type') {
|
||||
const find = psiphon3IpType.find(t => t.value === value)
|
||||
if (find) {
|
||||
return find.name
|
||||
}
|
||||
}
|
||||
}
|
||||
return value
|
||||
},
|
||||
/* 切换折叠状态 */
|
||||
switchCollapse () {
|
||||
this.isCollapse = !this.isCollapse
|
||||
@@ -225,6 +286,9 @@ export default {
|
||||
/* 设为折叠状态 */
|
||||
collapse () {
|
||||
this.isCollapse = true
|
||||
},
|
||||
getEntity (data) {
|
||||
this.entityData = { ...data }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
<div class="overview__content">
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">APP ID</div>
|
||||
<div class="row__content">{{entity.appId|| '-'}}</div>
|
||||
<div class="row__content">{{entity.category.appId || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
|
||||
<div class="row__content">{{entity.appCategory|| '-'}}</div>
|
||||
<div class="row__content">{{entity.category.appCategory || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.subcategory')}}</div>
|
||||
<div class="row__content">{{entity.appSubcategory || '-'}}</div>
|
||||
<div class="row__content">{{entity.category.appSubcategory || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.riskLevel')}}</div>
|
||||
<div class="row__content">{{appRisk(entity.appRisk) || '-'}}</div>
|
||||
<div class="row__content">{{appRisk(parseInt(entity.category.appRisk)) || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
|
||||
<div class="row__content">{{entity.appDescription || '-'}}</div>
|
||||
<div class="row__content">{{entity.category.appDescription || '-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,116 +30,110 @@
|
||||
<loading :loading="loadingTraffic" size="small" inner-style="left: 8.75rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.peak')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.max, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.max, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.max, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.mean')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.avg, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.avg, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.avg, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.throughput')}}</div>
|
||||
<div class="row__contents">
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:
|
||||
{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.appName}`" ></div>
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`" ></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__content row__content-accept">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:
|
||||
{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.appName}`" ></div>
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`" ></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
|
||||
|
||||
<div style="position: relative;">
|
||||
<div class="entity-score" v-if="!loadingNetworkQuality">
|
||||
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
|
||||
Score:{{score}}
|
||||
</div>
|
||||
|
||||
<loading :loading="loadingNetworkQuality" size="small" style="left: 1rem;width: 50%;"></loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.relationship')}}</div>
|
||||
<div class="overview__content domain__content">
|
||||
<div class="overview__tags domain__tags" ref="relationship">
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataOne.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedDomains')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
<span class="tag__desc">{{item.domain}}</span>
|
||||
</div>
|
||||
<div class="overview__tags domain__tags" ref="relationship"></div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.tab.relatedDomain')}}</div>
|
||||
<div class="row__content overview__row-related">
|
||||
<div v-if="loadingRelationshipOne" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
|
||||
<span v-if="item.domain" :title="item.domain">{{item.domain}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
|
||||
|
||||
<div v-if="relationshipShowOne">
|
||||
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataTwo.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedServerIp')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
<span class="tag__desc">{{item.ip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row overview__row-related">
|
||||
<div class="row__label row__label--width130">{{$t('entities.tab.relatedIp')}}</div>
|
||||
|
||||
<div class="row__content">
|
||||
<div v-if="loadingRelationshipTwo" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
|
||||
<span v-if="item.ip" :title="item.ip">{{item.ip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
|
||||
|
||||
<div v-if="relationshipShowTwo">
|
||||
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
|
||||
<div class="overview__content overview__content-loading-net">
|
||||
<loading :loading="loadingNetworkQuality" size="small"></loading>
|
||||
<div class="overview__row overview__row--single-value">
|
||||
<chart-single-value
|
||||
v-for="(chartInfo, i) in singleValues.chartInfos"
|
||||
:chart-info="chartInfo"
|
||||
:chart-data="singleValues.chartDatas[i]"
|
||||
:key="i"
|
||||
class="cn-chart__single-value--detail-overview"
|
||||
></chart-single-value>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('entities.accessLink')}}</div>
|
||||
<div class="overview__content">
|
||||
<div class="overview__tags">
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingOut" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}},</span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingIn" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}},</span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.alert')}}</div>
|
||||
<div class="overview__content overview__content-loading">
|
||||
@@ -148,20 +142,17 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="performanceData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__content">{{entityData.performanceNum}}</div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width200">
|
||||
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
|
||||
<div>{{performance.eventType}}</div>
|
||||
</div>
|
||||
<div class="row__content-loading" style="position: relative;" >
|
||||
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
|
||||
<div class="row__charts" :id="`entityPerformanceChart${entity.appName}_${index}`"></div>
|
||||
<div class="row__content-loading" style="position: relative;">
|
||||
<div class="performance-event-remark">{{performance.eventType}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-if="performanceData && performanceData.length > 5">
|
||||
@@ -177,15 +168,26 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="securityData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__content">{{entityData.securityNum}}</div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width200">
|
||||
|
||||
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
|
||||
<div>{{security.securityType}}</div>
|
||||
</div>
|
||||
<div class="cn-detection__header">
|
||||
<i class="cn-icon cn-icon-attacker"></i>
|
||||
<span>{{ security.offenderIp }}</span>
|
||||
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
|
||||
<span class="line">-------</span>
|
||||
<span class="circle"></span>
|
||||
<i class="cn-icon cn-icon-attacked"></i>
|
||||
<span>{{ security.victimIp }}</span>
|
||||
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-if="securityData && securityData.length > 5">
|
||||
@@ -213,34 +215,38 @@ import { unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import Chart from '@/views/charts/Chart'
|
||||
import _ from 'lodash'
|
||||
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
|
||||
import { get } from '@/utils/http'
|
||||
import relatedServer from '@/mixins/relatedServer'
|
||||
import { getSecond, getMillisecond } from '@/utils/date-util'
|
||||
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
mixins: [entityDetailMixin, relatedServer],
|
||||
components: {
|
||||
Chart,
|
||||
Loading,
|
||||
ChartSingleValue
|
||||
Loading
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// entityData: {}
|
||||
entityType: 'app',
|
||||
trafficUrl: api.entityAppDetailTraffic,
|
||||
// trafficUrl: api.entityAppDetailTraffic,
|
||||
trafficUrl: api.entity.entityList.appThroughput,
|
||||
relationUrl: api.entityAppDetailRelation,
|
||||
networkQuantityUrl: api.entityAppDetailNetworkQuantity,
|
||||
// networkQuantityUrl: api.entityAppDetailNetworkQuantity,
|
||||
networkQuantityUrl: api.entity.entityList.appPerformance,
|
||||
linkInUrl: api.entityAppDetailLinkIn,
|
||||
linkOutUrl: api.entityAppDetailLinkOut,
|
||||
performanceUrl: api.entityAppDetailPerformance,
|
||||
securityUrl: api.entityAppDetailSecurity,
|
||||
trafficUrlMap: api.entityAppDetailTrafficMap,
|
||||
relatedServerDomainUrl: api.entityAppRelatedServerDomain,
|
||||
relatedServerIpUrl: api.entityAppRelatedServerIp,
|
||||
// performanceUrl: api.entityAppDetailPerformance,
|
||||
performanceUrl: api.entity.entityList.appEventPerformance,
|
||||
securityUrl: api.entity.entityList.appSecurity,
|
||||
// securityUrl: api.entityAppDetailSecurity,
|
||||
// trafficUrlMap: api.entityAppDetailTrafficMap,
|
||||
trafficUrlMap: api.entity.entityList.appTrafficMap,
|
||||
relatedServerDomainUrl: api.entity.entityList.appRelatedDomain,
|
||||
relatedServerIpUrl: api.entity.entityList.appRelatedIp,
|
||||
chartData: null,
|
||||
listMode: 'list',
|
||||
singleValues: {
|
||||
@@ -296,34 +302,33 @@ export default {
|
||||
i18n: 'entities.pktRetransPercent'
|
||||
}
|
||||
],
|
||||
chartDatas: [null, null, null, null, null],
|
||||
loadingTraffic: false,
|
||||
loadingRelationshipOne: false,
|
||||
loadingRelationshipTwo: false,
|
||||
loadingNetworkQuality: false,
|
||||
loadingOut: false,
|
||||
loadingIn: false,
|
||||
loadingAlert: false,
|
||||
loadingSecurityEvents: false,
|
||||
loadingMap: false
|
||||
}
|
||||
chartDatas: [null, null, null, null, null]
|
||||
},
|
||||
loadingTraffic: false,
|
||||
loadingRelationshipOne: false,
|
||||
loadingRelationshipTwo: false,
|
||||
loadingNetworkQuality: false,
|
||||
loadingOut: false,
|
||||
loadingIn: false,
|
||||
loadingAlert: false,
|
||||
loadingSecurityEvents: false,
|
||||
loadingMap: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMillisecond,
|
||||
dateFormatByAppearance,
|
||||
getQueryParams () {
|
||||
const queryParams = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
appName: this.entity.appName
|
||||
return {
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime),
|
||||
resource: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
getPerformanceQueryParams () {
|
||||
const queryParams = {
|
||||
appName: this.entity.appName
|
||||
return {
|
||||
appName: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
handleRelationData (result) {
|
||||
this.entityData.domainCount = result.domainCount
|
||||
@@ -353,10 +358,11 @@ export default {
|
||||
})
|
||||
},
|
||||
setup (props) {
|
||||
const entityData = ref({ ...props.entity })
|
||||
return {
|
||||
chart: {
|
||||
params: {
|
||||
url: '/interface/entity/detail/app/trafficMap?startTime={{startTime}}&endTime={{endTime}}&country={{country}}&appName={{appName}}',
|
||||
url: `${api.entity.entityList.appTrafficMap}?resource={{resource}}&country={{country}}`,
|
||||
unitType: 'number',
|
||||
valueColumn: 'sessions'
|
||||
},
|
||||
@@ -366,7 +372,8 @@ export default {
|
||||
entityCopy: {
|
||||
..._.cloneDeep(props.entity)
|
||||
},
|
||||
unitConvert
|
||||
unitConvert,
|
||||
entityData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="entity-detail-overview">
|
||||
<template v-if="entity.entityType === 'ip'">
|
||||
<ip-overview :entity="entity" :time-filter="timeFilter"></ip-overview>
|
||||
<ip-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></ip-overview>
|
||||
</template>
|
||||
<template v-else-if="entity.entityType === 'domain'">
|
||||
<domain-overview :entity="entity" :time-filter="timeFilter"></domain-overview>
|
||||
<domain-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></domain-overview>
|
||||
</template>
|
||||
<template v-else-if="entity.entityType === 'app'">
|
||||
<app-overview :entity="entity" :time-filter="timeFilter"></app-overview>
|
||||
<app-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></app-overview>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -28,6 +28,11 @@ export default {
|
||||
'domain-overview': Domain,
|
||||
'app-overview': App,
|
||||
'ip-overview': Ip
|
||||
},
|
||||
methods: {
|
||||
getEntity (data) {
|
||||
this.$emit('reloadEntity', data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,36 +4,32 @@
|
||||
<div class="overview__content">
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
|
||||
<div class="row__content">{{entityData.domainCategory || '-'}}</div>
|
||||
<div class="row__content">{{entityData.category ? entityData.category.categoryName : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.domainDetail.categoryGroup')}}</div>
|
||||
<div class="row__content">{{entityData.domainCategoryGroup || '-'}}</div>
|
||||
<div class="row__content">{{entityData.category ? entityData.category.categoryGroup : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.reputationLevel')}}</div>
|
||||
<div class="row__content">{{entityData.domainReputationScore || '-'}}</div>
|
||||
<div class="row__content">{{entityData.category ? entityData.category.reputationLevel : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.registration')}}</div>
|
||||
<div class="row__content">{{entityData.domainWhoisAddress || '-'}}</div>
|
||||
<div class="row__content">{{entityData.whois ? entityData.whois.registrantCountry : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.org')}}</div>
|
||||
<div class="row__content">{{entityData.domainWhoisOrg || '-'}}</div>
|
||||
<div class="row__content">{{entityData.whois ? entityData.whois.registrantOrg : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.icpCompanyName')}}</div>
|
||||
<div class="row__content">{{entityData.domainIcpCompanyName || '-'}}</div>
|
||||
<div class="row__content">{{entityData.icp ? entityData.icp.icpCompanyName : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.icpLicense')}}</div>
|
||||
<div class="row__content">{{entityData.domainIcpSiteLicense || '-'}}</div>
|
||||
<div class="row__content">{{entityData.icp ? entityData.icp.icpSiteLicense : '-'}}</div>
|
||||
</div>
|
||||
<!-- <div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
|
||||
<div class="row__content">{{entityData.domainDescription || '-'}}</div>
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
@@ -42,116 +38,107 @@
|
||||
<loading :loading="loadingTraffic" size="small" inner-style="left: 8.75rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.peak')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.max, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.max, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.max, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.mean')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.avg, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.avg, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.avg, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.throughput')}}</div>
|
||||
<div class="row__contents">
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:
|
||||
{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.domainName}`" >{</div>
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`" >{</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__content row__content-accept">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:
|
||||
{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.domainName}`" ></div>
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`" ></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
|
||||
<div style="position: relative;">
|
||||
<div class="entity-score" v-if="!loadingNetworkQuality">
|
||||
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
|
||||
Score:{{score}}
|
||||
</div>
|
||||
|
||||
<loading :loading="loadingNetworkQuality" size="small" style="left: 1rem;width: 50%;"></loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.relationship')}}</div>
|
||||
<div class="overview__content domain__content">
|
||||
<div class="overview__tags domain__tags" ref="relationship">
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataOne.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedApp')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
<span class="tag__desc">{{item.appName}}</span>
|
||||
</div>
|
||||
<div class="overview__tags domain__tags" ref="relationship"></div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.tab.relatedApp')}}</div>
|
||||
<div class="row__content overview__row-related">
|
||||
<div v-if="loadingRelationshipOne" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
|
||||
<span v-if="item.appName" :title="item.appName">{{item.appName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
|
||||
|
||||
<div v-if="relationshipShowOne">
|
||||
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataTwo.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedServerIp')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
<span class="tag__desc">{{item.ip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row overview__row-related">
|
||||
<div class="row__label row__label--width130">{{$t('entities.tab.relatedIp')}}</div>
|
||||
<div class="row__content">
|
||||
<div v-if="loadingRelationshipTwo" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
|
||||
<span v-if="item.ip" :title="item.ip">{{item.ip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
|
||||
|
||||
<div v-if="relationshipShowTwo">
|
||||
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
|
||||
<div class="overview__content overview__content-loading-net">
|
||||
<loading :loading="loadingNetworkQuality" size="small"></loading>
|
||||
<div class="overview__row overview__row--single-value">
|
||||
<chart-single-value
|
||||
v-for="(chartInfo, i) in singleValues.chartInfos"
|
||||
:chart-info="chartInfo"
|
||||
:chart-data="singleValues.chartDatas[i]"
|
||||
:key="i"
|
||||
class="cn-chart__single-value--detail-overview"
|
||||
></chart-single-value>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('entities.accessLink')}}</div>
|
||||
<div class="overview__content">
|
||||
<div class="overview__tags">
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingOut" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}},</span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingIn" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}},</span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.alert')}}</div>
|
||||
<div class="overview__content overview__content-loading">
|
||||
@@ -160,18 +147,16 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="performanceData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__content">{{entityData.performanceNum}}</div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width200">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
|
||||
<div>{{performance.eventType}}</div>
|
||||
</div>
|
||||
<div class="row__content-loading" style="position: relative;" >
|
||||
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
|
||||
<div class="row__charts" :id="`entityPerformanceChart${entity.domainName}_${index}`"></div>
|
||||
<div class="row__content-loading" style="position: relative;">
|
||||
<div class="performance-event-remark">{{performance.eventType}}</div>
|
||||
</div>
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
@@ -188,14 +173,24 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="securityData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__content">{{entityData.securityNum}}</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row overview__row--small-font" v-for="(security, i) in entityData.securityList" :key="i">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(getMillisecond(security.startTime)) || '-'}}</div>
|
||||
<div class="row__content row__content--width200">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(getMillisecond(security.startTime)) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
|
||||
<div>{{security.securityType}}</div>
|
||||
</div>
|
||||
<div class="cn-detection__header">
|
||||
<i class="cn-icon cn-icon-attacker"></i>
|
||||
<span>{{ security.offenderIp }}</span>
|
||||
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
|
||||
<span class="line">-------</span>
|
||||
<span class="circle"></span>
|
||||
<i class="cn-icon cn-icon-attacked"></i>
|
||||
<span>{{ security.victimIp }}</span>
|
||||
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
|
||||
</div>
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
@@ -218,7 +213,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
|
||||
import { api } from '@/utils/api'
|
||||
import entityDetailMixin from './entityDetailMixin'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
@@ -227,13 +221,13 @@ import Chart from '@/views/charts/Chart'
|
||||
import _ from 'lodash'
|
||||
import { get } from '@/utils/http'
|
||||
import relatedServer from '@/mixins/relatedServer'
|
||||
import { getSecond, getMillisecond } from '@/utils/date-util'
|
||||
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Domain',
|
||||
components: {
|
||||
ChartSingleValue,
|
||||
Loading,
|
||||
Chart
|
||||
},
|
||||
@@ -242,16 +236,21 @@ export default {
|
||||
return {
|
||||
// entityData: {},
|
||||
entityType: 'domain',
|
||||
trafficUrl: api.entityDomainDetailTraffic,
|
||||
// trafficUrl: api.entityDomainDetailTraffic,
|
||||
trafficUrl: api.entity.entityList.domainThroughput,
|
||||
relationUrl: api.entityDomainDetailRelation,
|
||||
networkQuantityUrl: api.entityDomainDetailNetworkQuantity,
|
||||
networkQuantityUrl: api.entity.entityList.domainPerformance,
|
||||
// networkQuantityUrl: api.entityDomainDetailNetworkQuantity,
|
||||
linkInUrl: api.entityDomainDetailLinkIn,
|
||||
linkOutUrl: api.entityDomainDetailLinkOut,
|
||||
performanceUrl: api.entityDomainDetailPerformance,
|
||||
securityUrl: api.entityDomainDetailSecurity,
|
||||
trafficUrlMap: api.entityDomainDetailTrafficMap,
|
||||
relatedServerIpUrl: api.entityDomainRelatedServerIp,
|
||||
relatedServerAppUrl: api.entityDomainRelatedServerApp,
|
||||
// performanceUrl: api.entityDomainDetailPerformance,
|
||||
performanceUrl: api.entity.entityList.domainEventPerformance,
|
||||
// securityUrl: api.entityDomainDetailSecurity,
|
||||
securityUrl: api.entity.entityList.domainSecurity,
|
||||
// trafficUrlMap: api.entityDomainDetailTrafficMap,
|
||||
trafficUrlMap: api.entity.entityList.domainTrafficMap,
|
||||
relatedServerIpUrl: api.entity.entityList.domainRelatedIp,
|
||||
relatedServerAppUrl: api.entity.entityList.domainRelatedApp,
|
||||
basicProperties: api.entityDomainDetailBasic,
|
||||
chartData: null,
|
||||
listMode: 'list',
|
||||
@@ -308,34 +307,33 @@ export default {
|
||||
i18n: 'entities.pktRetransPercent'
|
||||
}
|
||||
],
|
||||
chartDatas: [null, null, null, null, null],
|
||||
loadingTraffic: false,
|
||||
loadingRelationshipOne: false,
|
||||
loadingRelationshipTwo: false,
|
||||
loadingNetworkQuality: false,
|
||||
loadingOut: false,
|
||||
loadingIn: false,
|
||||
loadingAlert: false,
|
||||
loadingSecurityEvents: false,
|
||||
loadingMap: false
|
||||
}
|
||||
chartDatas: [null, null, null, null, null]
|
||||
},
|
||||
loadingTraffic: false,
|
||||
loadingRelationshipOne: false,
|
||||
loadingRelationshipTwo: false,
|
||||
loadingNetworkQuality: false,
|
||||
loadingOut: false,
|
||||
loadingIn: false,
|
||||
loadingAlert: false,
|
||||
loadingSecurityEvents: false,
|
||||
loadingMap: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMillisecond,
|
||||
dateFormatByAppearance,
|
||||
getQueryParams () {
|
||||
const queryParams = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
domain: this.entity.domainName
|
||||
return {
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime),
|
||||
resource: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
getPerformanceQueryParams () {
|
||||
const queryParams = {
|
||||
domain: this.entity.domainName
|
||||
return {
|
||||
domain: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
handleRelationData (result) {
|
||||
this.entityData.appCount = result.appCount
|
||||
@@ -383,14 +381,15 @@ export default {
|
||||
})
|
||||
},
|
||||
setup (props) {
|
||||
const entityData = ref({ ...props.entity })
|
||||
const entityCopy = {
|
||||
..._.cloneDeep(props.entity),
|
||||
domain: props.entity.domainName
|
||||
domain: props.entity.entityValue
|
||||
}
|
||||
return {
|
||||
chart: {
|
||||
params: {
|
||||
url: '/interface/entity/detail/domain/trafficMap?startTime={{startTime}}&endTime={{endTime}}&country={{country}}&domain={{domain}}',
|
||||
url: `${api.entity.entityList.domainTrafficMap}?resource={{resource}}&country={{country}}`,
|
||||
unitType: 'number',
|
||||
valueColumn: 'sessions'
|
||||
},
|
||||
@@ -398,7 +397,8 @@ export default {
|
||||
},
|
||||
entityCopy,
|
||||
unitTypes,
|
||||
unitConvert
|
||||
unitConvert,
|
||||
entityData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
<div class="overview__content">
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.location')}}</div>
|
||||
<div class="row__content">{{ipLocationRegion(entity)}}</div>
|
||||
<div class="row__content">{{ipLocationRegion(entity.location)}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">ASN</div>
|
||||
<div class="row__content">{{entity.ipAsn || '-'}}</div>
|
||||
<div class="row__content">{{entity.asn ? entity.asn.asn : '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.openPort')}}</div>
|
||||
<div class="row__content">{{ openPort }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,7 +48,7 @@
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<loading :loading="!loadingDns && loading" size="small"></loading>
|
||||
<div class="row__charts" :id="`entityDnsServerInfo${entity.ipAddr}`"></div>
|
||||
<div class="row__charts" :id="`entityDnsServerInfo${entity.entityValue}`"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,116 +61,107 @@
|
||||
<loading :loading="loadingTraffic" size="small" inner-style="left: 8.75rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.peak')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.max, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.max, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.max, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.mean')}}</div>
|
||||
<div class="row__content">{{unitConvert(entityData.avg, unitTypes.byte).join(' ')}}/s</div>
|
||||
<div class="row__content">
|
||||
{{unitConvert(entityData.avg, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.avg, unitTypes.byte).join(' ') + '/s' : '-'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.throughput')}}</div>
|
||||
<div class="row__contents">
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__charts-msg">{{$t('overall.sent')}}:
|
||||
{{unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesSentRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.ipAddr}`"></div>
|
||||
<div class="row__charts" :id="`entityDetailSend${entity.entityValue}`"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row__content">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ')}}ps</div>
|
||||
<div class="row__content row__content-accept">
|
||||
<div class="row__charts-msg">{{$t('overall.received')}}:
|
||||
{{unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') !== '- ' ? unitConvert(entityData.bytesReceivedRate, unitTypes.byte).join(' ') + 'ps' : '-'}}
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="row__content-loading">
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.ipAddr}`"></div>
|
||||
<div class="row__charts" :id="`entityDetailReceived${entity.entityValue}`"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.networkQualityRating')}}</div>
|
||||
<div style="position: relative;">
|
||||
<div class="entity-score" v-if="!loadingNetworkQuality">
|
||||
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
|
||||
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
|
||||
Score:{{score}}
|
||||
</div>
|
||||
|
||||
<loading :loading="loadingNetworkQuality" size="small" style="left: 1rem;width: 50%;"></loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.relationship')}}</div>
|
||||
<div class="overview__content domain__content">
|
||||
<div class="overview__tags domain__tags" ref="relationship">
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipOne" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataOne.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedDomains')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
<span class="tag__desc">{{item.domain}}</span>
|
||||
</div>
|
||||
<div class="overview__tags domain__tags" ref="relationship"></div>
|
||||
<div class="overview__row overview__row-related">
|
||||
<div class="row__label row__label--width130">{{$t('entities.tab.relatedApp')}}</div>
|
||||
<div class="row__content">
|
||||
<div v-if="loadingRelationshipOne" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataOne, 1)" v-if="relationshipShowOne">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreOne" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataOne" :key="item">
|
||||
<span v-if="item.domain" :title="item.domain">{{item.domain}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
|
||||
|
||||
<div v-if="relationshipShowOne">
|
||||
<el-popover placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div class="popover-content" v-for="(item, index) in relationshipDataOne" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview__domain-tabs overview__domain-tabs-loading">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" inner-style="left: 1rem;" style="width: 50%;"></loading>
|
||||
<div class="overview__domain-tab">
|
||||
<div class="overview__tag domain__tag">
|
||||
<span class="tag__value">{{relationshipDataTwo.length}}</span>
|
||||
<span class="tag__desc">{{$t('entities.relatedApp')}}</span>
|
||||
</div>
|
||||
<div class="overview__tag domain__tag-list" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
<span class="tag__desc">{{item.appName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row overview__row-related">
|
||||
<div class="row__label row__label--width130">{{$t('entities.relatedDomain')}}</div>
|
||||
<div class="row__content">
|
||||
<div v-if="loadingRelationshipTwo" style="position: relative;width: 450px;">
|
||||
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
|
||||
</div>
|
||||
<div class="overview__domain-btn">
|
||||
<div class="overview__domain-more" @click="more(relationshipDataTwo, 2)" v-if="relationshipShowTwo">...</div>
|
||||
<div class="overview__domain-more-tabs show-more-list" v-if="relationshipShowMoreTwo" v-ele-click-outside="mouseout">
|
||||
<div class="domain-more-tab" v-for="item in relationshipMoreDataTwo" :key="item">
|
||||
<span v-if="item.appName" :title="item.appName">{{item.appName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
|
||||
{{item.value}}
|
||||
</div>
|
||||
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
|
||||
|
||||
<div v-if="relationshipShowTwo">
|
||||
<el-popover class="entity-expand-detail" placement="right-end" trigger="click" show-arrow="false" offset="20">
|
||||
<template #reference>
|
||||
<div class="data-item show-more-related">...</div>
|
||||
</template>
|
||||
<div v-for="(item, index) in relationshipDataTwo" :key="index">{{item.value}}</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.networkQuality')}}</div>
|
||||
<div class="overview__content overview__content-loading-net">
|
||||
<loading :loading="loadingNetworkQuality" size="small"></loading>
|
||||
<div class="overview__row overview__row--single-value">
|
||||
<chart-single-value
|
||||
v-for="(chartInfo, i) in singleValues.chartInfos"
|
||||
:chart-info="chartInfo"
|
||||
:chart-data="singleValues.chartDatas[i]"
|
||||
:key="i"
|
||||
class="cn-chart__single-value--detail-overview"
|
||||
></chart-single-value>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('entities.accessLink')}}</div>
|
||||
<div class="overview__content">
|
||||
<div class="overview__tags">
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingOut" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.outLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutId ? entityData.linkOutId : '-'}}, </span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkOutPercent ? unitConvert(entityData.linkOutPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
<div class="overview__tag overview__tag-loading">
|
||||
<loading :loading="loadingIn" size="small"></loading>
|
||||
<span class="tag__desc">{{$t('entities.inLinkTrafficPercentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInId ? entityData.linkInId : '-'}}, </span>
|
||||
<span class="tag__desc">{{$t('entities.percentage')}}</span>
|
||||
<span class="tag__value">{{entityData.linkInPercent ? unitConvert(entityData.linkInPercent, unitTypes.percent).join(' ') : '-'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-item">
|
||||
<div class="overview__title">{{$t('overall.alert')}}</div>
|
||||
<div class="overview__content overview__content-loading">
|
||||
@@ -175,18 +170,16 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="performanceData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentAlert')}}</div>
|
||||
<div class="row__content">{{entityData.performanceNum}}</div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
|
||||
<div>{{performance.eventType}}</div>
|
||||
</div>
|
||||
<div class="row__content-loading" style="position: relative; padding-left: 10px;">
|
||||
<loading :loading="!loadingAlert && loadingPerformance[index]?loadingPerformance[index]:false" :id="`loading${entity.ipAddr}_${index}`" size="small"></loading>
|
||||
<div class="row__charts" :id="`entityPerformanceChart${entity.ipAddr}_${index}`"></div>
|
||||
<div class="row__content-loading" style="position: relative;">
|
||||
<div class="performance-event-remark">{{performance.eventType}}</div>
|
||||
</div>
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
@@ -203,15 +196,26 @@
|
||||
<span class="no-recent-alerts"><i class="el-icon-success"></i>{{$t('relationShip.noRecentAlerts')}}</span>
|
||||
</div>
|
||||
<div class="overview__row" v-if="securityData.length > 0">
|
||||
<div class="row__label">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__label row__label--width130">{{$t('entities.recentSecurity')}}</div>
|
||||
<div class="row__content">{{entityData.securityNum}}</div>
|
||||
</div>
|
||||
|
||||
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
|
||||
<div class="row__label row__label--width160">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width200">
|
||||
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
|
||||
<div class="row__content row__content--width90">
|
||||
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
|
||||
<div>{{security.securityType}}</div>
|
||||
</div>
|
||||
<div class="cn-detection__header" >
|
||||
<i class="cn-icon cn-icon-attacker"></i>
|
||||
<span>{{ security.offenderIp }}</span>
|
||||
<div class="domain" v-if="security.offenderIp===security.serverIp">{{ security.domain }}</div>
|
||||
<span class="line">-------</span>
|
||||
<span class="circle"></span>
|
||||
<i class="cn-icon cn-icon-attacked"></i>
|
||||
<span>{{ security.victimIp }}</span>
|
||||
<div class="domain" v-if="security.victimIp===security.serverIp">{{ security.domain }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row__desc"></div>
|
||||
</div>
|
||||
<div class="overview__row overview__row--small-font" v-if="securityData && securityData.length > 5">
|
||||
@@ -234,7 +238,6 @@
|
||||
|
||||
<script>
|
||||
import entityDetailMixin from './entityDetailMixin'
|
||||
import ChartSingleValue from '@/views/charts/charts/ChartSingleValue'
|
||||
import { api } from '@/utils/api'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
@@ -242,30 +245,35 @@ import Chart from '@/views/charts/Chart'
|
||||
import _ from 'lodash'
|
||||
import { get } from '@/utils/http'
|
||||
import relatedServer from '@/mixins/relatedServer'
|
||||
import { getSecond, getMillisecond } from '@/utils/date-util'
|
||||
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Ip',
|
||||
mixins: [entityDetailMixin, relatedServer],
|
||||
components: {
|
||||
Loading,
|
||||
Chart,
|
||||
ChartSingleValue
|
||||
Chart
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
entityType: 'ip',
|
||||
trafficUrl: api.entityIpDetailTraffic,
|
||||
trafficUrlMap: api.entityIpDetailTrafficMap,
|
||||
// trafficUrl: api.entityIpDetailTraffic,
|
||||
trafficUrl: api.entity.entityList.ipThroughput,
|
||||
// trafficUrlMap: api.entityIpDetailTrafficMap,
|
||||
trafficUrlMap: api.entity.entityList.ipTrafficMap,
|
||||
relationUrl: api.entityIpDetailRelation,
|
||||
networkQuantityUrl: api.entityIpDetailNetworkQuantity,
|
||||
// networkQuantityUrl: api.entityIpDetailNetworkQuantity,
|
||||
networkQuantityUrl: api.entity.entityList.ipPerformance,
|
||||
linkInUrl: api.entityIpDetailLinkIn,
|
||||
linkOutUrl: api.entityIpDetailLinkOut,
|
||||
performanceUrl: api.entityIpDetailPerformance,
|
||||
securityUrl: api.entityIpDetailSecurity,
|
||||
relatedServerDomainUrl: api.entityIpRelatedServerDomain,
|
||||
relatedServerAppUrl: api.entityIpRelatedServerApp,
|
||||
performanceUrl: api.entity.entityList.ipEventPerformance,
|
||||
// performanceUrl: api.entityIpDetailPerformance,
|
||||
// securityUrl: api.entityIpDetailSecurity,
|
||||
securityUrl: api.entity.entityList.ipSecurity,
|
||||
relatedServerDomainUrl: api.entity.entityList.ipRelatedDomain,
|
||||
relatedServerAppUrl: api.entity.entityList.ipRelatedApp,
|
||||
entityDetectionsIpUrl: api.entityDetectionsIp,
|
||||
entityDetectionsIpQueryRateUrl: api.entityDetectionsIpQueryRate,
|
||||
listMode: 'list',
|
||||
@@ -336,21 +344,22 @@ export default {
|
||||
loadingIn: false,
|
||||
loadingAlert: false,
|
||||
loadingSecurityEvents: false,
|
||||
loadingMap: false
|
||||
loadingMap: false,
|
||||
openPort: '-'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ipLocationRegion () {
|
||||
return function (entityData) {
|
||||
let result = ''
|
||||
if (entityData.ipLocationCountry) {
|
||||
result += `${entityData.ipLocationCountry},`
|
||||
if (entityData.country) {
|
||||
result += `${entityData.country},`
|
||||
}
|
||||
if (entityData.ipLocationProvince) {
|
||||
result += `${entityData.ipLocationProvince},`
|
||||
if (entityData.province) {
|
||||
result += `${entityData.province},`
|
||||
}
|
||||
if (entityData.ipLocationCity) {
|
||||
result += `${entityData.ipLocationCity},`
|
||||
if (entityData.city) {
|
||||
result += `${entityData.city},`
|
||||
}
|
||||
result = result.substr(0, result.length - 1)
|
||||
if (!result) {
|
||||
@@ -381,19 +390,18 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getMillisecond,
|
||||
dateFormatByAppearance,
|
||||
getQueryParams () {
|
||||
const queryParams = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
ip: this.entity.ipAddr
|
||||
return {
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime),
|
||||
resource: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
getPerformanceQueryParams () {
|
||||
const queryParams = {
|
||||
serverIp: this.entity.ipAddr
|
||||
return {
|
||||
serverIp: this.entity.entityValue
|
||||
}
|
||||
return queryParams
|
||||
},
|
||||
handleRelationData (result) {
|
||||
this.entityData.appCount = result.appCount
|
||||
@@ -411,11 +419,29 @@ export default {
|
||||
queryRelated () {
|
||||
this.getRelatedServerDataOne(this.relatedServerDomainUrl)
|
||||
this.getRelatedServerDataTwo(this.relatedServerAppUrl)
|
||||
},
|
||||
getOpenPort () {
|
||||
const params = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
resource: this.entity.entityValue
|
||||
}
|
||||
|
||||
axios.get(api.entity.entityList.ipRelatedPort, { params: params }).then(res => {
|
||||
if (res.data.code === 200 && res.data.data.result.length) {
|
||||
this.openPort = ''
|
||||
res.data.data.result.forEach(item => {
|
||||
this.openPort += item.port + '/' + item.l7Protocol + ','
|
||||
})
|
||||
this.openPort = this.openPort.slice(0, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.queryParams = this.getQueryParams()
|
||||
this.chartGetMap()
|
||||
this.getOpenPort()
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.queryRelated()
|
||||
@@ -425,16 +451,16 @@ export default {
|
||||
setup (props) {
|
||||
const entityCopy = {
|
||||
..._.cloneDeep(props.entity),
|
||||
ip: props.entity.ipAddr
|
||||
ip: props.entity.entityValue
|
||||
}
|
||||
return {
|
||||
chart: {
|
||||
params: {
|
||||
url: '/interface/entity/detail/ip/trafficMap?startTime={{startTime}}&endTime={{endTime}}&country={{country}}&ip={{ip}}',
|
||||
url: `${api.entity.entityList.ipTrafficMap}?resource={{resource}}&country={{country}}`,
|
||||
unitType: 'number',
|
||||
valueColumn: 'sessions'
|
||||
},
|
||||
id: props.entity.ipAddr,
|
||||
id: props.entity.entityValue,
|
||||
type: 2
|
||||
},
|
||||
entityCopy,
|
||||
@@ -444,3 +470,110 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
//.type-content {
|
||||
// margin-bottom:15px;
|
||||
// display:flex;
|
||||
// flex-flow: row wrap;
|
||||
// width:100%;
|
||||
.data-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgba(119,131,145,0.06);
|
||||
border: 1px solid rgba(119,131,145,0.36);
|
||||
border-radius: 2px;
|
||||
height:28px;
|
||||
padding:8px 15px;
|
||||
margin-right:10px;
|
||||
//margin-bottom:15px;
|
||||
font-size: 12px;
|
||||
color: #353636;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.show-more-related {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
padding-bottom: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
//}
|
||||
.entity-score {
|
||||
.circle-icon {
|
||||
border-radius: 3px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.data-score-red {
|
||||
background: #E26154;
|
||||
}
|
||||
.data-score-yellow {
|
||||
background: #E5A219;
|
||||
}
|
||||
.data-score-green {
|
||||
background: #749F4D;
|
||||
}
|
||||
height:24px;
|
||||
font-size: 14px;
|
||||
color: #046ECA;
|
||||
font-weight: 500;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.cn-detection__header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
padding-bottom: 3px;
|
||||
color: #333333;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
|
||||
i {
|
||||
color: #7b8fa2;
|
||||
margin-right: 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.line {
|
||||
color: #da5656;
|
||||
margin-left: 12px;
|
||||
font-size: xx-small;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.circle {
|
||||
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;
|
||||
font-style: italic;
|
||||
padding: 0 2px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.el-popper {
|
||||
min-width: 90px !important;
|
||||
width: auto !important;
|
||||
max-width: 300px !important;
|
||||
max-height: 180px !important;
|
||||
overflow: scroll !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { riskLevelMapping, unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { shallowRef, markRaw } from 'vue'
|
||||
import { metricOption } from '@/views/detections/options/detectionOptions'
|
||||
import { sortBy, reverseSortBy } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, computeScore } from '@/utils/tools'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
@@ -45,29 +45,13 @@ export default {
|
||||
metricChart: null,
|
||||
performanceChartList: [],
|
||||
loadingPerformance: [],
|
||||
|
||||
score: '-', // 网络质量评分
|
||||
performanceMetricEndTimeInterval: 3600 // 服务质量事件指标的结束时间与开始时间的秒间隔
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
entityName () {
|
||||
let name
|
||||
switch (this.entity.entityType) {
|
||||
case ('ip'): {
|
||||
name = this.entity.ipAddr
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
name = this.entity.domainName
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
name = this.entity.appName
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return name
|
||||
return this.entity.entityValue
|
||||
},
|
||||
appRisk () {
|
||||
return function (level) {
|
||||
@@ -172,6 +156,7 @@ export default {
|
||||
this.sentChart.setOption(this.chartOptionSent)
|
||||
this.receivedChart.setOption(this.chartOptionReceived)
|
||||
this.loadingTraffic = false
|
||||
this.$emit('reloadEntity', this.entityData)
|
||||
} else {
|
||||
this.loadingTraffic = false
|
||||
}
|
||||
@@ -234,7 +219,7 @@ export default {
|
||||
this.performanceChartList.push(metricChart)
|
||||
this.echartsArray.push(shallowRef(metricChart))
|
||||
} else {
|
||||
const chartDom = document.getElementById(`entityPerformanceChart${this.entityName}${index}`)
|
||||
const chartDom = document.getElementById(`entityPerformanceChart${this.entityName}_${index}`)
|
||||
chartDom.innerHTML = '<span style="padding-left:5px;">-</span>'
|
||||
}
|
||||
})
|
||||
@@ -272,6 +257,14 @@ export default {
|
||||
if (this.networkQuantityUrl) {
|
||||
get(this.networkQuantityUrl, this.getQueryParams()).then(response => {
|
||||
if (response.code === 200) {
|
||||
const data = {
|
||||
establishLatencyMs: response.data.result.establishLatencyValue || null,
|
||||
httpResponseLatency: response.data.result.httpResponseLatencyValue || null,
|
||||
sslConLatency: response.data.result.sslConLatencyValue || null,
|
||||
tcpLostlenPercent: response.data.result.sequenceGapLossPercentValue || null,
|
||||
pktRetransPercent: response.data.result.pktRetransPercentValue || null
|
||||
}
|
||||
this.score = computeScore(data)
|
||||
this.entityData.establishLatencyValue = response.data.result.establishLatencyValue
|
||||
this.entityData.establishLatencyP50 = response.data.result.establishLatencyP50
|
||||
this.entityData.establishLatencyP90 = response.data.result.establishLatencyP90
|
||||
@@ -389,11 +382,6 @@ export default {
|
||||
this.entityData.performanceNum = response.data.result.length
|
||||
this.performanceData = response.data.result
|
||||
this.entityData.performanceList = this.getTargetPageData(1, this.showMore.performancePageSize, this.performanceData)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.queryEntityDetailPerformanceChart(this.entityData.performanceList, 0)
|
||||
}, 200)
|
||||
})
|
||||
}
|
||||
this.loadingAlert = false
|
||||
})
|
||||
@@ -412,16 +400,16 @@ export default {
|
||||
},
|
||||
|
||||
performanceShowMore (num) {
|
||||
const startIndex = this.showMore.performancePageSize
|
||||
// const startIndex = this.showMore.performancePageSize
|
||||
this.showMore.performancePageSize += num
|
||||
this.entityData.performanceList = this.getTargetPageData(this.showMore.pageNo, this.showMore.performancePageSize, this.performanceData)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (this.entityData.performanceList && this.entityData.performanceList.length > 0) {
|
||||
this.queryEntityDetailPerformanceChart(this.entityData.performanceList.slice(startIndex, this.entityData.performanceList.length), startIndex)
|
||||
}
|
||||
}, 200)
|
||||
})
|
||||
// this.$nextTick(() => {
|
||||
// setTimeout(() => lltext
|
||||
// if (this.entityData.performanceList && this.entityData.performanceList.length > 0) {
|
||||
// this.queryEntityDetailPerformanceChart(this.entityData.performanceList.slice(startIndex, this.entityData.performanceList.length), startIndex)
|
||||
// }
|
||||
// }, 200)
|
||||
// })
|
||||
},
|
||||
|
||||
securityShowMore (num) {
|
||||
@@ -520,6 +508,7 @@ export default {
|
||||
this.chartOption = _.cloneDeep(entityListLineOption)
|
||||
setTimeout(() => { this.queryEntityDetail() })
|
||||
const _this = this
|
||||
this.entityData = { ...this.entityData, ...this.entity }
|
||||
this.emitter.on('switch-collapse', function () {
|
||||
setTimeout(() => { _this.queryEntityDetail() }, 200)
|
||||
})
|
||||
|
||||
@@ -45,43 +45,10 @@ export default {
|
||||
return className
|
||||
},
|
||||
entityType () {
|
||||
let type
|
||||
switch (this.entityData.entityType) {
|
||||
case 'ip': {
|
||||
type = this.entityData.ipAddr
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
type = this.entityData.domainName
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
type = this.entityData.appName
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return type
|
||||
return this.entity.entityValue
|
||||
},
|
||||
entityName () {
|
||||
let name
|
||||
switch (this.entityData.entityType) {
|
||||
case ('ip'): {
|
||||
name = this.entity.ipAddr
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
name = this.entity.domainName
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
name = this.entity.appName
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return name
|
||||
return this.entity.entityValue
|
||||
},
|
||||
appRisk () {
|
||||
return function (level) {
|
||||
@@ -94,32 +61,11 @@ export default {
|
||||
queryParams () {
|
||||
let params
|
||||
const now = window.$dayJs.tz().valueOf()
|
||||
switch (this.entityData.entityType) {
|
||||
case ('ip'): {
|
||||
params = {
|
||||
startTime: this.timeFilter.startTime ? parseInt(this.timeFilter.startTime / 1000) : Math.floor(now / 1000 - 3600),
|
||||
endTime: this.timeFilter.endTime ? parseInt(this.timeFilter.endTime / 1000) : Math.floor(now / 1000),
|
||||
ip: this.entityData.ipAddr
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
params = {
|
||||
startTime: this.timeFilter.startTime ? parseInt(this.timeFilter.startTime / 1000) : Math.floor(now / 1000 - 3600),
|
||||
endTime: this.timeFilter.endTime ? parseInt(this.timeFilter.endTime / 1000) : Math.floor(now / 1000),
|
||||
domain: this.entityData.domainName
|
||||
}
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
params = {
|
||||
startTime: this.timeFilter.startTime ? parseInt(this.timeFilter.startTime / 1000) : Math.floor(now / 1000 - 3600),
|
||||
endTime: this.timeFilter.endTime ? parseInt(this.timeFilter.endTime / 1000) : Math.floor(now / 1000),
|
||||
appName: this.entityData.appName
|
||||
}
|
||||
break
|
||||
}
|
||||
default: break
|
||||
// eslint-disable-next-line prefer-const
|
||||
params = {
|
||||
startTime: this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : Math.floor(now / 1000 - 3600),
|
||||
endTime: this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : Math.floor(now / 1000),
|
||||
resource: this.entityData.entityValue
|
||||
}
|
||||
return params
|
||||
}
|
||||
@@ -130,7 +76,17 @@ export default {
|
||||
path: '/entityDetail',
|
||||
query: {
|
||||
entityType: this.entityData.entityType,
|
||||
name: this.entityData.ipAddr || this.entityData.domainName || this.entityData.appName
|
||||
entityName: this.entityData.entityValue
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
},
|
||||
showGraph () {
|
||||
const { href } = this.$router.resolve({
|
||||
path: '/entityGraph',
|
||||
query: {
|
||||
entityType: this.entityData.entityType,
|
||||
entityName: this.entityData.entityValue
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
@@ -197,11 +153,9 @@ export default {
|
||||
},
|
||||
getQueryParams () {
|
||||
return {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
appName: this.entityType,
|
||||
domain: this.entityType,
|
||||
ip: this.entityType
|
||||
// startTime: getSecond(this.timeFilter.startTime),
|
||||
// endTime: getSecond(this.timeFilter.endTime),
|
||||
resource: this.entityType
|
||||
}
|
||||
},
|
||||
queryEntityDetailTraffic () {
|
||||
@@ -285,30 +239,36 @@ export default {
|
||||
},
|
||||
resize () {
|
||||
this.echartsArray.forEach(item => { item.value.resize() })
|
||||
},
|
||||
initUrl () {
|
||||
if (this.entity.entityType) {
|
||||
switch (this.entity.entityType) {
|
||||
case 'ip': {
|
||||
// this.trafficUrl = api.entityIpDetailTraffic
|
||||
this.trafficUrl = api.entity.entityList.ipThroughput
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
// this.trafficUrl = api.entityDomainDetailTraffic
|
||||
this.trafficUrl = api.entity.entityList.domainThroughput
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
// this.trafficUrl = api.entityAppDetailTraffic
|
||||
this.trafficUrl = api.entity.entityList.appThroughput
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
entityData: {
|
||||
deep: true,
|
||||
handler (n) {
|
||||
if (n.entityType) {
|
||||
switch (n.entityType) {
|
||||
case 'ip': {
|
||||
this.trafficUrl = api.entityIpDetailTraffic
|
||||
break
|
||||
}
|
||||
case 'domain': {
|
||||
this.trafficUrl = api.entityDomainDetailTraffic
|
||||
break
|
||||
}
|
||||
case 'app': {
|
||||
this.trafficUrl = api.entityAppDetailTraffic
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
this.initUrl()
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -316,7 +276,9 @@ export default {
|
||||
this.debounceFunc = this.$_.debounce(this.resize, 200)
|
||||
window.addEventListener('resize', this.debounceFunc)
|
||||
this.chartOption = _.cloneDeep(entityListLineOption)
|
||||
this.entityData = _.cloneDeep(this.entity)
|
||||
// this.entityData = _.cloneDeep(this.entity)
|
||||
this.entityData = { ...this.entityData, ...this.entity }
|
||||
this.initUrl()
|
||||
setTimeout(() => {
|
||||
this.querySecurity()
|
||||
this.queryEntityDetailTraffic()
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
<div class="explorer-search">
|
||||
<div class="explorer-search__title" v-show="!showList">{{$t('search.title')}}</div>
|
||||
<div class="explorer-search__input-case" :class="{'explorer-search__input-case--question-mark-in-line': showList}">
|
||||
<div class="explorer-search__input">
|
||||
<!--新版实体列表改版,后续记得解开-->
|
||||
<!--<div class="explorer-search__input" style="border: 1px #DEDEDE solid;height: 42px;">-->
|
||||
<div class="explorer-search__input" style="border: 1px #DEDEDE solid;height: 42px;">
|
||||
<advanced-search
|
||||
ref="search"
|
||||
:column-list="columnList"
|
||||
@@ -25,8 +23,8 @@
|
||||
<span>{{$t('search.searchHistory')}}</span>
|
||||
</div>
|
||||
<div class="foot__item">
|
||||
<span @click="search">{{$t('overall.explore')}}</span>
|
||||
<!-- <el-divider direction="vertical"></el-divider>
|
||||
<!-- <span @click="search">{{$t('overall.explore')}}</span>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span>{{$t('overall.help')}}</span>-->
|
||||
</div>
|
||||
<transition name="el-zoom-in-top">
|
||||
@@ -69,7 +67,8 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
columnList: columnList,
|
||||
operatorList: ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE'],
|
||||
// operatorList: ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE'],
|
||||
operatorList: ['=', 'IN'],
|
||||
connectionList: [
|
||||
{
|
||||
value: 'AND',
|
||||
|
||||